一、Vue2核心
基本模板
<div id='root'>
name }} {{ cla.name }}
</div>
//创建容器
new Vue({
el
- 容器和实例是一一对应的关系,不能有一对多或多对一
- 同名变量,后者会覆盖前者
- 对于同名变量,可以创建一个子对象,然后调用时类似java的类一样去调用
1.1、语法
插值语法
<div id='root'> {{ name </div>
- 插值语法用于解析标签体内容
}}
内部写的必须是js表达式,且可以读取data中所有属性(表达式是有值的语句)
指令语法
<a v-blind
- 对于标签里面的属性,使用
v-blnd:
进行绑定,同时v-blind
可以简写为:
- 对于标签里面的属性,使用
1.2、数据
数据绑定
v-blind
是单向绑定,因此在页面中更改值时,data中的值不会变v-model
是双向绑定,页面中更改值时,data中的值也会变,但只能用于表单元素(input , select)。同时可以简写v-model:value = '123'
为v-model = '123'
data与el的2种写法
e1有2种写法
new Vue
时候配置el属性- 先创建Vue实例
const vm = new Vue()
,随后再通过vm.$mount('#root')
指定el的值
data有2种写法
- 对象式
函数式
new Vue({ el: '#root', data() { return { name : 'NAME' } }, );
数据代理
回顾Object.defineproperty
Object.defineproperty(对象 , 属性 , 参数)
Object.defineproperty(person , 'age' , { value: 18, enumerable: true, //控制属性是否可以枚举,默认值是false writable: true, //控制属性是否可以被修改,默认值是false configurable: true, //控制属性是否可以被删除,默认值是false //当有人读取person的age属性时,get自动执行,且返回age的值 get(){ retrun '11' } //当有人修改person的age属性时,set自动执行,且收到修改的值 set(value){ console.log(value) } }) //为person添加 'age:18' 这一属性
数据代理就是通过一个 对象代理 对另一个对象进行属性操作
Vue中的数据代理是通过vm对象来代理data对象中属性的操作。内置
Object.defineproperty()
方法把源代码data所有元素都添加到vm的_data
上,同时为每一个对象都用getter和setter方法去内部操作属性。
1.3、事件处理
基本使用
//事件绑定 <button v-on:click = 'show1()' >点击执行函数</button> <button @click = 'show2(12 , $event)' >点击执行函数</button> //事件回调 const vm = new Vue({ el: '#root', data: { name: 'zhang' }, methods: { show1() { alert(12); }, show2(number , e){ console.log(number , e); } }, });
- 事件的绑定使用
v-on:
或@
- methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
$event
是事件对象
- 事件的绑定使用
事件修饰符
<!-- 阻止事件冒泡--> <a @click.stop="showInfo()"></a> <!-- 阻止默认事件 --> <a @click.prevent="showInfo()"></a> <!-- 修饰语可以使用链式书写 --> <a @click.stop.prevent="showInfo()"></a> <!-- 事件只执行一次 --> <button @click.once=""></button> <!-- 使用事件捕获模式 --> <button @click.captrue=""></button> <!-- 仅当 event.target 是元素本身时才会触发事件处理器 --> <!-- 例如:事件处理器不来自子元素 --> <div @click.self="showInfo()">...</div> <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕 --> <!-- 这里则先进行事件回调,再触发button函数--> <button @click.passive="show()"></button>
键盘事件
<!-- 键盘按下enter时触发函数 --> <inpuut @keyup.enter="show()">
Vue 为一些常用的按键提供了别名:
Vue.config.keyCodes.自定义键名 = 键码
可以使用该方法自定义按键名
1.4、计算属性(compute)
计算属性的数据来源于data内,不能获取外部的值
底层原理还是Object.defineproperty
方法
const vm = new Vue({
el: '#root',
data: {
name: 'zhang'
},
compute: {
//当有人调用fullname时,执行get并其返回的值为fullname的值
fullname:{
get(){
return name
}
}
},
});
get被调用的时机:
- 初次被调用,此后值保存在缓存内,对此后所有的fullname应用
- 当值被修改时,此时get再次被调用,缓存刷新
若要修改计算属性的值,那么需要写一个set()
方法
计算属性简写(对于只读不改的情况才使用)
compute: {
fullname(){
return name
}
}
调用时不用加括号 <span>{{ fullname </span>
(计算属性仍然是属性)
1.5、监视属性(watch)
const vm = new Vue({
el: '#root',
data: {
name: 'zhang'
},
watch:{
name:{
immediate:true, //刷新时调用一下handler
//当name发生改变时,调用handler
handler(){
console.log('修改了')
}
}
}
});
handler()
里面有两个参数 ,handler(newvalue , oldervalue)
此外监视属性还有另一种写法
const vm = new Vue({
el: '#root',
data: {
name: 'zhang'
}
});
//以外部挂载的方式
vm.$watch('name' , {
immediate:true, //刷新时调用一下handler
//当name发生改变时,调用handler
handler(){
console.log('修改了')
}
})
- 两种写法都只能监视
data
和compute
里面的属性 但仅有
handler()
时 可以简写为watch:{ name(){ console.log('修改了') } } //-----------------------------------------// vm.$watch('name' , function() { console.log('修改了') })
vue对象自身是可以监视多层级属性的 , 但vue的watch默认不监视多层级的变化 , 因此需要配置deep
const vm = new Vue({
el: '#root',
data: {
num: {
a:1,
b:2
}
}
});
//以外部挂载的方式
vm.$watch('num' , {
deep:true, //监视多级属性内所有属性的变化
//当name发生改变时,调用handler
handler(){
console.log('修改了')
}
})
如果要在watch里面使用不被Vue管理的函数 , 需要写成箭头函数的形式,这样this才是指向Vue对象
1.6、class和style绑定
class绑定
class绑定有三种写法: 字符串 、数组 、 对象
<div class='basic' :class='change' ></div>
data: { changeArr = ['1' , '2' , '3'] changeObject: { a:false, b:true } },
- 字符串写法,适用于:样式的类名不确定,需要动态指定
- 数组写法,适用于:要绑定的样式个数不确定.名字也不确定
- 对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用
style绑定
<div class='basic' :style='change' ></div>
- 写法有字符串 、 数组 、 对象三种(小驼峰写法)
- 数组写法实际上是一个嵌套,在数组里面放置style对象(了解)
1.7、条件渲染与列表渲染
条件渲染
使用
v-show
来隐藏元素,当值为false时隐藏<div v-show:'false'>div</div>
此时该节点在dom中还存在( 在dom中是
display:none
)使用
v-if
来彻底隐藏元素,当值为false时隐藏<div v-if:'false'>div</div>
此时该节点在dom中不存在
- 此外还有
v-else
、v-else-if
,与其他语言作用一样。同时连续的条件指令视为一个配对组。v-if
要最开始使用 切不允许被打断 在
v-if
中使用temple来进行包装会更好,实现对子元素的批量处理。同时在dom中不存在 “包装壳”<temple v-if:'true'> <h2>001</h2> <h2>002</h2> <h2>003</h2> </temple>
- 此外还有
- 高频率切换使用
v-show
更好
列表渲染
v-for
起遍历作用<div v-for:'p in persons' :key='p.id'> p.name }} --- {{ p.age }} </div>
data
key
的值最好不用index来表示 ,如果index改变,会导致页面重新渲染
1.8、表单数据的收集
<input type="text"/> //则v-model收集的是value值,需要配置一个v-model
<input type="radio"/> //则v-model收集的是value值,且要给标签配置value值
<input type="checkbox"/>
//1.没有配置input的value属性,那么收集的就是checked(勾选or未勾选,是布尔值)
//2.配置input的value属性:
//(1)v-model的初始值是非数组,那么收集的就是checked(勾选or未勾选,是布尔值)
//(2)v-mode1的初始值是数组,那么收集的的就是va1ue组成的数组
v-model的三个修饰符:
lazy
失去焦点再收集数据number
输入字符串转为有效的数字trim
输入首尾空格过滤
1.9、内置指令
v-text
与v-html
v-text
在所在节点内插入文本(会替换原有内容),相当于innerTextv-html
与v-text
作用相同 ,但其支持解析Html结构(该方法具有一定的网络安全性问题)
v-cloak
- 本质是一个特殊属性,vue实例创建完毕并接管容器并删去
v-cloak
属性 使用css配合
v-c1oak
可以解决网速慢时页面展示出({xxx的问题<style> /*---- 再其为未显示之前设置为隐藏 -----*/ [v-cloak] { display: none } </style> <div v-cloak> name }}</div>
- 本质是一个特殊属性,vue实例创建完毕并接管容器并删去
v-once
v-once
所在节点在初动态渲染后就视为静态内容,只渲染一次
v-pre
- 跳过该节点的解析过程,可以用于加快解析渲染,提高效率
1.10、自定义指令
函数式
directives
指令式
new Vue({ ... directives:{ fun:{ // 绑定时触发 bind(element ,binding){ }, // 插入时触发 inserted(element ,binding){ }, // 数据更新时触发 update(element ,binding){ } } } })
总结
- 自定义指令本质是对原生js的包装,element是绑定的元素 , binding是对绑定的
- 例如要定义
fun
指令 , 使用时需要使用v-fun
(<div v-fun></div>
) - 自定义指令不需要设置返回值
1.11、生命周期
生命函数是Vue在关键时刻帮我们调用的一些特殊名称的函数
生命周期钩子分为 创建、挂载、更新、销毁四种
常用的生命周期钩子:
mounted
发送ajax请求、启动定时器、绑定自定义事件、订阅消息等beforeDestroy
清除定时器、解绑自定义事件、取消订阆消息等【收尾工作】
二、Vue组件化
2.1、非单文件组件
创建使用
//使用组件
<div id="root">
<my></my>
</div>
<script>
// 创建组件
const my = Vue.extend({
template:`
<div>
<h2>姓名:{{ name </h2>
<h2>年龄: age }}</h2>
</div>
`,
data() {
return {
name
组件的使用需要经历 创建 、 注册 、 使用 三步
Vue.extend(options)
创建组件,其中配置项与new Vue
几乎一样,使用temple进行组件结构的配置
也可以简写成consr ve = options
区别:
- data必须写成函数,避免组件被复用时,数据存在引用关系
- 没有el配置项
对于组件的注册:
- 局部注册:在
new Vue
的时候传入components选项 - 全局注册:靠
Vue.component('组件名',组件)
使用组件时 ,可以用双标签(<my></my>
) 也可以使用单闭合标签(<my/>
)。但单闭合标签最好只在脚手架内使用
关于VueComponent
- school组件本质是一个名为
VueComponent
的构造函数,且不是程序员定义的,是Vue.extend生成的 - 我们只需要写
<school/>
或<school></school>
,Vue解析时会帮我们创建school组件的实例对象,即Vue执行new VueComponent(options)
且调用Vue.extend返回的都是一个全新的VueComponent
关于this指向
- 组件配置中,this是【VueComponent实例对象】
new Vue
配置中,this均是【Vue实例对象】
2.2、vue脚手架相关属性
ref属性
<!-- ref配置 --> <school ref='demo'></school> <div ref='div'></div>
ref属性的作用:
- 被用来给元素域子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实dom元素,应用在组件标签上是组件实例对象(vc)
- ref的获取:
this.$refs.xxx
props配置
proos有三种写法
<School name:'zhang' :age='18' sex='man'></School>
new Vue() { ... props:['name' , 'age' , 'sex'] // 简单写法 // 对象写法 props:{ name:String, age:Number, sex:String } // 完整写法 props:{ name:{ type: String, //数据类型 required: true //该数据是必要的 }, age:{ type: String, default:18 //数据没值时默认 }, sex:{ type: String, //数据类型 required: true //该数据是必要的 } } }
- 年龄是一个Number类型的值,如果需要对值进行变化,需要进行
v-bind
绑定 - props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告
- 若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中
的数据
- 年龄是一个Number类型的值,如果需要对值进行变化,需要进行
mixin
定义混入
在mixin.js里面写入并暴露
const mixin ={ data(){...}, methods:{...} } export default mixin
使用混入
创建一个mixin.js文件 , 使用import导入。
- 全局混入
Vue.mixin(xxx)
- 局部混入
mixins:['xxx']
- 全局混入
2.3、scope属性
在style属性内使用scope,将样式设置为局部样式,避免与其他组件冲突
<style scope>
...
<style>
2.4、TodoList案例总结
组件化编码流程:
- 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
实现动态组件:考虑好数的存放位置,数据是一个组件在用,还是一些组件在用:
- 一个组件在用:放在组件自身即可
- 一些组件在用:放在他们共同的父组件上(状态提升)
- 实现交互:从绑定事件开始
propsi适用于:
- 父组件=>子组件通信
- 子组件==>父组件通信(要求父先给子一个函数】
- 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props
是不可以修改的! - props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,在不推
荐这样做
2.5、自定义触发事件
子组件想给父组件传数据,那么就要在父组件中给子组件绑定自定义事件
绑定方法
- 第一种方法:在父组件中使用
v-on
绑定
- 第一种方法:在父组件中使用
<!--- 父组件School --->
<!--- 事件绑定在组件上 --->
<Student @tapstu='getSchoolName'/>
methods:{
getSchoolName(){console.log('被调用了')}
}
<!--- 子组件Student --->
<button @click='getName'></button>
methods:{
getName(){
this.$emit('tapstu')
}
}
- 第二种方法:在父组件中挂载
this.$refs.demo.$on('事件',方法)
<!--- 父组件 --->
<Student ref='student'></Student>
methods:{
getStudentName(){console.log('被调用了')}
},
mounted(){
this.$refs.student.$on('tapstu',this.getStudentName)
}
<!--- 子组件Student --->
<button @click='getName'></button>
methods:{
getName(){
this.$emit('tapstu')
}
}
解绑自定义事件
this.$off('事件名')
- 对于多个解绑,使用数组
this.$off(['事件1','事件2'])
- 对于多个解绑,使用数组
- 组件可以绑定原生DOM事件,需要使用native修饰符
@click.native="show"
- 上面绑定自定义事件,即使绑定的是原生事件也会被认为是自定义的,需要加native,加了后就将此事件给组件的根元素
- 注意:以
this.$refs.xxx.$on('事件名',回调函数)
绑定自定义事件时,回调函数要么配置在methods中,要么用箭头函数,否则 this 指向会出问题。(对于自定义事件。谁触发,谁就是this指向;但是如果this.函数,该普通函数配置在当前vc的methods内,则会改变其指向本身)
2.6、全局事件总线
在兄弟组件或者多层级组件进行信息传递时,使用独立于组件之外的全局事件总线进行串联
创建全局事件总线
new Vue({ ... beforeCreate(){ Vue.prototype.$bus = this; // $bus就是全局事件总线 }, })
发送方创建methods
sendAge(){ this.$bus.$emit('sendAge',this.age) }
接收方挂载和销毁
mounted() { this.$bus.$on("sendAge", (age) => { console.log(age); }); }, beforeDestroy() { this.$bus.$off("sendAge"); }
2.7、$nextTick
- 用法:
this.$nextTick(回调函数)
- 作用:在下一次DOM更新结束后执行其指定的回调
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
2.8、动画与效果
- 作用:在更新dom元素时会给元素添加合适的类名
写法:
元素进入:
v-enter
进入的起点v-enter-active
进入的过程v-enter-to
进入的终点
元素离开:
v-leave
离开的起点v-leave-active
离开的过程v-leave-to
离开的终点
使用时用
transition
包裹要过度的元素,并为其配置name属性<transition name='hello' appear> <h1 v-show:'isShiow'></h1> </transition>
<style> .hello-enter,.hello-leave-to{ ... }, .hello-leave,.hello-enter-to{ ... }, .hello-leave-active,.hello-enter-active{ ... } </style>
- 如果要打开页面时就启用动画,添加
appear
属性 - 不一定需要配置每一个属性,可以用CSS写一个
@keyfrrames
动画效果,然后在v-enter-active
和v-leave-active
中调用 - 如果多个元素需要使用动画则使用
transition-group
包裹起来,并为每一个子元素添加key
- 如果要打开页面时就启用动画,添加
三、Vue与ajax
3.1、Vue-cli 配置代理
简单模式
在vue配置文件里添加
devServer:{ proxy:"url" }
复杂模式
devServer: { proxy: { // 配置所有以/api开头的请求 '/api': { target: 'http://127.0.0.1:5000', changeOrigin: true, ws: true, pathRewrite: { '^/api': '' } } } }
- 在
target
里面配置代理服务器 - 使用
pathRewrite
将修改后的请求服务器url复原
- 在
四、Vuex
4.1、Vuex使用
在main.js内导入store
import Vue from 'vue' import App from './App.vue' import store from './store'; Vue.config.productionTip = false new Vue({ store, render: h => h(App), }).$mount('#app')
- 在src目录下创建store文件夹,文件夹内再创建index.js文件
在index.js内写入内容
import Vue from 'vue'; //导入vuex import vuex from 'vuex'; //安装vuex Vue.use(vuex); //创建store对象 const actions = { jia(context , value){ context.commit('JIA',value) } }; const mutations = { JIA(state , value){ state.sum += value } }; const state = { sum:0, }; //导出store对象 export default new vuex.Store({ actions, mutations, state, });
使用
<template> <div class="show"> <h1>MyTest</h1> <h3>结果为:{{$store.state.sum</h3> <button @click="addNum">add</button> </div> </template> <script> export default { name: "List", data() { return { n:1 }; }, methods: { addNum(n) { this.$store.dispatch('jia',this.n) }, }, }; </script>
- 组件中使用数据:
$store.state.xxx
- 组件中使用数据:
4.2、getters配置
- 概念:当state中的数据需要经过加工后再使用时,可以使用
getters
加工 在store.js中追加
getters
配置...... const gettrts = { sum(){ ...... } } //导出store对象 export default new vuex.Store({ ...... getters });
- 组件中使用数据:
$store.getters.xxx
- 组件中使用数据:
4.3、map映射函数
(以mapstate为例)
- 原理:mapstate是一个包装函数自动生成
this.$store.state.xxx
的回调函数 - 用途:映射
state
中的数据为计算属性 用法
// 导入 import {mapState,mapGetters,mapActions,mapMutations} from 'vuex' export default { // mapState,mapGetters写在computed里面 computed: { // 第一种写法:对象写法 ...mapState({sum:'sum',count:'count'}) // 第二种写法:数组写法 ...mapState(['sum',count']) }, // 这两个必须写在methods里面 methods:{ ...mapActions(['jia']), ...mapMutations(['JIA']) } }
<!--页面调用---> <div>sum}}</div> <div>{{count}}</div> <button @click='JIA'></button>
- 对于数组写法,属性名和属性值必须相同,同时必须加上引号
- 对于
mapMutations
,mapActions
,如果需要传参,则需要在使用的位置也传一份,否则默认为event
4.4、Vuex模块化
store index.js内配置模块化导出
import Vue from 'vue'; import vuex from 'vuex'; Vue.use(vuex); // 模块化 const countOptions = { // 命名空间 namespaced
template内容
<template> <div> <h3>结果为:{{sum</h3> <!--传参,否则默认为event--> <button @click="JIA(n)">+</button> </div> </template>
Vue文件内使用-map方式
import {mapState,mapGetters,mapActions,mapMutations} from 'vuex' export default { name: 'Count', data() { return { n: 1 } }, computed: { // 模块名 + 模块内的state名 ...mapState('countOptions',['sum']), }, methods:{ // 模块名 + 模块内的actions名、mutations名 ...mapActions('countOptions',['JIA']), ...mapMutations('countOptions',['JIA']) } }
第二种使用方式:直接读取
import {mapState,mapGetters,mapActions,mapMutations} from 'vuex' export default { name: 'Count', data() { return { n: 1 } }, computed:{ // 直接读取state countSum(){ return this.$store.state.countOptions.sum }, // 直接读取getters countOddOrEven(){ return this.$store.getters['countOptions/oddOrEven'] }, }, methods:{ // 直接调用actions countJia(){ this.$store.dispatch('countOptions/JIA',this.n) }, // 直接调用mutations countJian(){ this.$store.commit('countOptions/JIAN',this.n) }, } }
五、路由
路由是一组组key:value
的组合,key为路径,value可能是function或component:
使用路由制作单页面应用,做到局部刷新的效果,优化使用和加载
5.1、路由使用
npm安装vue-router,在src下创建
router/index.js
// 导入VueRouter import VueRouter from "vue-router"; // 导入组件 import About from "../views/About"; import Home from "../views/Home"; export default new VueRouter({ routes: [ { // 路由路径 path: "/about", // 路由组件 component:About }, { path: "/home", component:Home } ] })
main.js内导入使用
import Vue from 'vue' import App from './App.vue' // 导入使用 import VueRouter from 'vue-router' import router from './router' Vue.use(VueRouter) Vue.config.productionTip = false new Vue({ router, render: h => h(App), }).$mount('#app')
使用
<router-link active-class="active" to="/about">About</router-link> <router-view></router-view>
<router-link></router-link>
浏览器会被替换为a标签active-class
可配置高亮样式<router-view></router-view>
内容展示区
注意
- 一般把路由组件放在
src/views
或者src/pages
内,和一般组件区分开 - 每一个路由组件都有自己的
$route
,但对于路由器全局共用一个$router
- 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
- 一般把路由组件放在
5.2、多级路由
使用children配置项
routes:[ { path:'/about', component:About, }, { path:'/home', component:Home, // 通过children配置子级路由 children:[ { path:'news', // 此处不要带斜杠 component:News }, { path:'message', // 此处不要写斜杆 component:Message } ] } ]
使用
<router-link to="/home/news">News</router-link>
注意
- 子级路由不需要加斜杆
- 使用时需要写好完整的路径
5.3、路由query参数
传参
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法 --> <router-link :to="{ path:'/home/message/detail', query:{ id: m.id, title: m.title } }" >跳转</router-link>
接收参数
$route.query.xxx
的形式
5.4、路由其他参数
路由命名
为具体的路由配置
name
属性来简化路由的跳转routes:[ { name:'guanyu' path:'/about', component:About, } ]
使用
<!-- 字符串写法 --> <router-link :to="{name: guanyu}">跳转</router-link> <!-- 对象写法 --> <router-link :to="{ name:'guanyu' query:{ id: 12 } }" >跳转</router-link>
params参数
配置路由,声明接收params参数
routes:[ { path:'/about/:id/:title', //使用占位符声明接收params参数 component:About, } ]
传递参数
路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="/about/666/你好">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ path:'/about' params:{ id:666, title:'你好' } }" >跳转</router-link>
- 参数的接收:
$route.params.xxx
路由的 props 配置
启用路由props配置后,需要在组件的props内接收参数,然后才能使用
{ path:'detail/:id', component:Detail, //第一种写法:props值为对象,以key-value的组合传递给组件 // props:{a:900} //第二种写法:props值为布尔值,为true时,把路由收到的params参数传递给组件本身的props // props:true //第三种写法:props值为函数,函数返回的对象中每一组key-value传递给组件 props($route){ return { id: $route.query.id, title: $route.query.title } } }
5.5、replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为push和replace。push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
- 使用:
<router-link replace> News </router-link>
5.6、编程式路由导航
不借助<router-link>
实现路由跳转,调用的是this.$router
内置的函数
this.$router.push({})
与this.$router.replace({})
:内传的对象与<router-link>
中的to相同this.$router.forward()
:前进this.$router.back()
:后退this.$router.go(n)
:可前进也可后退,n为正数前进n步,为负数后退n步
5.7、缓存路由组件
让不展示的路由组件保持挂载,不被销毁
// 缓存一个路由组件
<keep-alive include="News"> // include中写想要缓存的组件名,不写表示全部缓存
<router-view></router-view>
</keep-alive>
// 缓存多个路由组件
<keep-alive :include="['News','Message']">
<router-view></router-view>
</keep-alive>
5.8、路由守卫
activated
和deactivated
是路由组件所独有的两个钩子,仅在keep-alive
包裹的情况下起效用
activated
路由组件被激活时触发,deactivated
路由组件失活时触发
路由守卫对路由进行权限控制
全局路由守卫
路由的使用需要在创建路由后对其进行配置,最后再单独暴露出来
const router = new VueRouter({ routes:[ { name:'guanyv', path:'/about', component:About, meta:{title:'关于',isAuth='true'} //meta可以为每个路由配置自定义内容 } ] }) ... export default router
前置路由守卫(跳转前调用)
router.beforeEach((to,from,next) => { if(to.meta.isAuth){ //判断元素的meta属性内的isauth自定义配置 if(localStorage.getItem('school')==='atguigu'){ next() //next函数对内容进行放行 }else{ alert('学校名不对,无权限查看!') } }else{ next() } })
后置路由守卫(跳转后调用)
router.afterEach(function(to,from) { ... })
独享路由守卫(使用
beforeEnter
函数)const router = new VueRouter({ routes:[ { name:'guanyv', path:'/about', component:About, meta:{title:'关于',isAuth='true'}, //meta可以为每个路由配置自定义内容 beforeEnter(to,from,next){ //beforeEnter配置独享 if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') } } } ] }) ... export default router
- 独享路由没有后置守卫,但是可以与全局后置守卫混用
组件内路由守卫
<template> <h2>About组件</h2> </template> <script> export default { name:'About', ... // 进入该组件时被调用 beforeRouteEnter (to, from, next) { console.log('about路由被调用',to,from) if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert('学校名不对,无权限查看!') } }, // 离开该组件时被调用 beforeRouteLeave (to, from, next) { console.log('About离开',to,from) next() } } </script>
5.9、hash与history模式
url中的hash值:\#及其后面的内容就是hash值
hash值的内容不会传给服务器
- hash模式:以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法;兼容性较好
- history模式:兼容性和hash模式相比略差;应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
使用
const router = new VueRouter({
mode:'history',
...
})
export default router