vuex-router-sync 源码解析

vuex-router-sync:路由状态管理,保持 vue-router 和 vuex 存储同步。

import { sync } from 'vuex-router-sync'
import router from '@/router'
import store from '@/store'

sync(store,router)

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

vuex-router-sync.png

第1步:vuex模块动态注册

const moduleName = (options || {}).moduleName || 'route' 
store.registerModule(moduleName, {
     namespaced: true,
     state: cloneRoute(router.currentRoute),	// route 全部属性
     mutations: {
       	 // 改变 state 值
         'ROUTE_CHANGED'(state, transition) {
             store.state[moduleName] = cloneRoute(transition.to, transition.from)
         }
     }
 })

第2步:store.watch => vueVm.$watch

watch(fn: Function, callback: Function, options?: Object): Function

响应式地侦听 fn 的返回值,当值改变时调用回调函数。

  • fn 接收 store 的 state 作为第一个参数,其 getter 作为第二个参数。
  • callback(newVal, oldVal),回调函数
  • 最后接收一个可选的对象参数表示 Vue 的 vm.$watch 方法的参数
const storeUnwatch = store.watch(
  	// 监听 state[moduleName]
    state => state[moduleName],
    route => {
        const {
            fullPath
        } = route
        if (fullPath === currentPath) {
            return
        }
        if (currentPath != null) {
            isTimeTraveling = true
          	// 路由跳转
            router.push(route)
        }
        currentPath = fullPath
    }, {
        sync: true
    }
)

第3步:vue-router 全局后置导航钩子,钩子不会接受 next 函数也不会改变导航本身

// 监听路由变化
router.afterEach((to, from) => {
    if (isTimeTraveling) {
        isTimeTraveling = false
        return
    }
    currentPath = to.fullPath
  	// 触发 mutation
    store.commit(moduleName + '/ROUTE_CHANGED', {
        to,
        from
    })
})

为了避免循环调用,isTimeTraveling 为true时,代表是当前组件触发的路由跳转,router.afterEach 监听到不做任何处理。
这里需要注意的点是,我们通过 @/router@store 来获取相关实例!当然 vueVM.$options 也可以获取!

发布了256 篇原创文章 · 获赞 868 · 访问量 118万+

猜你喜欢

转载自blog.csdn.net/ligang2585116/article/details/94410789