【小慕讀書】—— 後臺管理系統學習:Vuex 和 Vue-router 進階
前言:最近在學習Vue+Element UI+Node.js小慕讀書中後臺管理系統開發課程,這裡對學習過程作個筆記,方便自己和大家翻閱。
一、Vuex 原理解析
Vuex 的原理關鍵:使用 Vue 例項管理狀態
<body> <div id="root">{{data}}</div> <div id="root2">{{data2}}</div> <div id="root3"> <button @click="change">change</button> </div> <script> function registerPlugin(Vue) { const vuex = {} vuex._vm = new Vue({ //_vm是Vue例項 data: { message: 'hello vue.js' } }) vuex.state = vuex._vm vuex.mutations = { setMessage(value) { vuex.state.message = value } } function init() { this.$store = vuex } Vue.mixin({ //全域性的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) //Vue響應式 前兩個Vue例項的message都會變化 } } }) </script> </body>
二、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}`) } } }
這裡以 HashHistory 為例,vue-router 的 push 方法實現如下: (實際呼叫的是Hashhistory的push方法)
push (location: RawLocation, onComplete?: Function, onAbort?: Function) { // $flow-disable-line if (!onComplete && !onAbort && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { this.history.push(location, resolve, reject) }) } else { this.history.push(location, onComplete, onAbort) } }
HashHistory 具體實現了 push 方法:
function pushHash (path) {
if (supportsPushState) {
pushState(getUrl(path))
} else {
window.location.hash = path
}
}
對路由的監聽通過 hash 相應的事件監聽實現:
window.addEventListener(
supportsPushState ? 'popstate' : 'hashchange',
() => {
const current = this.current
if (!ensureSlash()) {
return
}
this.transitionTo(getHash(), route => {
if (supportsScroll) {
handleScroll(this.router, route, current, true)
}
if (!supportsPushState) {
replaceHash(route.fullPath)
}
})
}
)
除此之外,vue-router 還提供了兩個元件:
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
三、vue-router 路由守衛
建立 router.js:
import Vue from 'vue'
import Route from 'vue-router'
import HelloWorld from './components/HelloWorld'
Vue.use(Route)
const routes = [
{ path: '/hello-world', component: HelloWorld }
]
const router = new Route({
routes
})
export default router
在 main.js 中引用 router,並加入 vue 例項:
import router from './router'
new Vue({
render: h => h(App),
router
}).$mount('#app')
四、全域性守衛
進入每一個路由都會觸發的鉤子函式
注意:因為寫在vue-router中,所以全域性守衛都是沒有辦法獲得Vue例項的。
//router.js
router.beforeEach((to, from, next) => { //當路由進入之前可以觸發的操作
console.log('beforeEach', to, from)
next()
})
router.beforeResolve((to, from, next) => { //當路由被解析之前被呼叫 Vue2.5新特性
console.log('beforeResolve', to, from)
next()
})
router.afterEach((to, from) => { //當路由進入之後可以觸發的事件
console.log('afterEach', to, from)
})
整個路由守衛執行是在元件生命週期函式之前的:
beforeEach(全域性守衛)、befforeResolve(全域性守衛)、afterEach(全域性守衛)
beforeCreate、created、beforeMount、mouted
五、區域性守衛
只適合在當前路由使用,是區域性的路由守衛。(寫在和元件的生命週期函式同一級)
1.to:表示當前路由,即要進入的路由
2.from:表示從哪來的,
3.next() 表示下一步要幹啥,next('/addGoods')就表示下一步,調到路由/addGoods
//A.vue
beforeRouteEnter (to, from, next) { //在需要進入的元件中呼叫
// 不能獲取元件例項 `this`, 因為在元件生命週期beforeCreate之前
console.log('beforeRouteEnter', to, from)
next()
},
beforeRouteUpdate (to, from, next) { //在複用(更新)的元件中呼叫
console.log('beforeRouteUpdate', to, from)
next()
},
beforeRouteLeave (to, from, next) { //在離開的元件中呼叫
console.log('beforeRouteLeave', to, from)
next()
}
- 進入元件:beforeEach(全域性守衛)、beforeRouteEnter(區域性守衛)、beforeResolve(全域性守衛)、afterEach(全域性守衛)、beforeCreate、created、beforeMount、mounted
- 更新元件:beforeEach(全域性守衛)、beforeRouteUpdate(區域性守衛)、beforeResolve(全域性守衛)、afterEach(全域性守衛)
- 離開元件:beforeRouteLeave(區域性守衛)、beforeEach(全域性守衛)、beforeResolve(全域性守衛)、afterEach(全域性守衛)、beforeDestory
六、路由元資訊
通過 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()
})
七、路由 API
使用 router.addRoutes 動態新增路由
使用場景:選單路由的許可權賦值
addRoute() {
this.$router.addRoutes([{
path: '/b', component: B, meta: { title: 'Custom Title B' },
}])
}
此時可以訪問到 B 元件
<router-link to='/b'>to B</router-link>
注:專案來自慕課網