课程名称:Vue Element+Node.js开发企业通用管理后台系统
课程章节: 第4章 Vuex和Vue-router进阶
主讲老师:Sam
课程内容:
今天学习的内容包括:
- vuex 原理解析
- vue-router 原理解析
- vue-router 路由守卫
- vue-router 路由元信息
主要围绕 vue 全家桶的 vuex 和 vue-router 进阶内容展开。
课程收获:
- vuex 原理解析
vuex 的原理关键:使用 Vue 实例进行状态管理
<html>
<head>
<title>vuex 原理解析</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="root">{{data}}</div>
<div id="root2">{{data2}}</div>
<div id="root3">
<button @click="change">change</button>
</div>
<script>
function registerPlugin(Vue) {
//定义vuex对象
const vuex = {}
//_vm属性是一个vue实例
vuex._vm = new Vue({
data: {
message: 'hello vue.js'
}
})
//state就是vue实例
vuex.state = vuex._vm
//定义mutations
vuex.mutations = {
setMessage(value) {
vuex.state.message = value
}
}
//定义初始化方法
function init() {
//在每个实例下都挂载一个 $store 属性
this.$store = vuex
}
//对所有vue实例,都在beforeCreate调用init方法
Vue.mixin({
beforeCreate: init
})
}
Vue.use(registerPlugin)
new Vue({
el: '#root',
computed: {
data() {
return this.$store.state.message
}
}
})
new Vue({
el: '#root2',
computed: {
data2() {
return this.$store.state.message
}
}
})
new Vue({
el: '#root3',
methods: {
change() {
const newValue = this.$store.state.message + '.'
this.$store.mutations.setMessage(newValue)
}
}
})
</script>
</body>
</html>
上述示例中,模拟了3个 vue 实例,帮助理解 vuex 状态管理应用。并创建了一个简易的 vuex 对象,通过在对象上挂载属性
- vue-router 实现原理
vue-router 实例化时会初始化this.history
,不同mode
对应不同的history
constructor (options: RouterOptions = {}) {
this.mode = mode
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
在监听路由变化的时候,主要是对原生事件的监听:
- hash 模式
window.addEventListener('hashchange',()=>{
this.current=window.location.hash.slice(1)
})
- history 模式
window.addEventListener("popstate",()=>{
this.current = location.pathname
})
vue-router 还提供了两个组件 <router-view>
和 <router-link>
。使用 vue 所开发的页面是一个单组件页面,只包含了 App.vue ,在 App.vue 里面通过<router-view>
来切换组件。
- vue-router 路由守卫
所谓路由守卫就是路由的钩子函数,它和组件的生命周期钩子函数类似。路由守卫可以分为:全局守卫和局部守卫。
- 全局守卫即每个路由都会触发。
router.beforeEach((to, from, next) => {
console.log('beforeEach', to, from)
next()
})
router.beforeResolve((to, from, next) => {
console.log('beforeResolve', to, from)
next()
})
router.afterEach((to, from) => {
console.log('afterEach', to, from)
})
如设置了全局守卫,并在组件中设置了组件的生命周期钩子函数,执行过程会发现路由会在组件的生命周期钩子函数前执行。
- 局部守卫(会写在 .vue 文件中)
beforeRouteEnter (to, from, next) {
// 不能获取组件实例 `this`
console.log('beforeRouteEnter', to, from)
next()
},
//当前组件发生变化的时候触发(如url参数变化)
beforeRouteUpdate (to, from, next) {
console.log('beforeRouteUpdate', to, from)
next()
},
beforeRouteLeave (to, from, next) {
console.log('beforeRouteLeave', to, from)
next()
}
如设置了局部守卫,并在组件中设置了组件的生命周期钩子函数,执行过程为:beforeRouteEnter->beforeCreate->created->beforeMount->mounted。
4. 路由元信息
路由元信息的主要作用为当前组件增加一些额外的参数信息,这个信息并不是通过 url 参数传递过来。
场景一:动态设置 title
- 通过 meta 定义路由元信息
const routes = [
{ path: '/a', component: A, meta: { title: 'Custom Title A' } }
]
- 使用 meta 信息动态修改标题
router.beforeEach((to, from, next) => {
console.log('beforeEach', to, from)
if (to.meta && to.meta.title) {
document.title = to.meta.title
} else {
document.title = 'default title'
}
next()
})
除了视频中演示的这种场景之外,日常还会在 meta 元信息中设置权限控制。
routes: [{
path: '/login',
name: 'login',
meta: {
roles: ['admin', 'user']
},
component: () => import('@/components/Login')
}]
最后,附上一张课程学习截图,ending~