我在写仿大众点评的时候遇到一个问题:虽然进入不同商品详情页,router的path也变了,但是页面的数据没有发生改变。然后我看了Vue.js的官网,看到了这样一段话:

提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。

然后我知道了可以通过使用watch 去监测 $route 对象和Vue Router 2.2 中引入的 beforeRouteUpdate 导航守卫两种方法去监测并获取数据。以下是两种方法的写法

watch (监测变化) $route 对象

1、在data属性定义数据

data() {
    return {
      dianpu: [],
      dianpuIndex: 0
    };
  },

2、在mounted()钩子函数中写vm.$nextTick

mounted() {
    this.$nextTick(() => {
      this.dianpuIndex = this.$route.params.index;
      this.dianpu = this.$store.state.dianpu[this.dianpuIndex];
    });
 }

3、写watch监听方法
必须写if条件,否则退出页面的时候会报错

watch: {
    $route(to, from) {
      if (to.path != "/home") {
        this.dianpuIndex = this.$route.params.index;
        this.dianpu = this.$store.state.dianpu[this.dianpuIndex];
      } 
    }
  },

导航守卫

什么是动态路由

在我写的vue项目中,猜你喜欢的商品很多,对所有商品详情页面都需要使用guessLikeDetails这个组件来渲染,所以需要使用动态路由。

export default new Router({
  // mode: 'hash',
  routes: [
    {
     // 动态路径参数 以冒号开头
      path: '/guessLikeDetails/:index',
      component: guessLikeDetails,
    },
  ],
  linkActiveClass: 'active'
})

导航守卫分全局的, 单个路由独享的, 或者组件级的。这里我们简单介绍一下路由独享的守卫

beforeEnter

可以在路由配置上直接定义 beforeEnter 守卫

{
      path: '/guessLikeDetails/:index',
      component: guessLikeDetails,
      beforeEnter: (to, from, next) => {
         console.log("to", to);
         console.log("from", from);
         console.log("next", next);
       }
 }
组件内的守卫

在这个项目中我是使用组件内的守卫beforeRouteEnter来监听数据的变化,以下是使用beforeRouteEnter的步骤:
1、同样是定义data的数据

data() {
    return {
      dianpu: [],
      dianpuIndex: 0
    };
  },

2、在vue组件里面写beforeRouteEnter
beforeRouteEnter不能获取组件实例 this,因为守卫在导航确认前被调用,因此新组件还没被创建。所以需要在next方法里传vm,vm就代表了组件实例。beforeRouteEnter在/guessLikeDetails/1直接跳转到/guessLikeDetails/2时不起作用,需要你从/guessLikeDetails/1退回到/home再进入/guessLikeDetails/2时才会监听数据的变化。

beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.dianpuIndex = to.params.index;
      vm.dianpu = vm.$store.state.dianpu[vm.dianpuIndex];
    });
  },
beforeRouteUpdate

beforeRouteUpdate能访问this,但是我打印出来的this不是vue实例。beforeRouteUpdate在/guessLikeDetails/1直接跳转到/guessLikeDetails/2时起作用。

beforeRouteUpdate: (to, from, next) => {
    console.log(this, "beforeRouteUpdate");
    console.log(this)
    next();
  },
beforeRouteLeave

这个this是vue实例,只在退出/guessLikeDetails/:index页面的时候才起作用,在页面/guessLikeDetails/1直接跳转到/guessLikeDetails/2时不起作用

beforeRouteLeave(to, from, next) { 
    console.log(this);
    next();
  },
为什么beforeRouteUpdate不起作用(即使路径发生变化)

有两个原因:
1、使用导航守卫必须去掉history模式
2、使用导航守卫必须在动态路径的vue组件中使用!!!
举个例子:虽然我写的路径切换在Guess-you-like-it.vue组件中,(guessLikeDetails组件import了Guess-you-like-it组件),但是你写导航守卫必须在guessLikeDetails组件中!!!!

ps:如果想要完整代码,欢迎下载我的github项目:仿大众点评
https://github.com/faimi/Fan_DAZHONGDIANPING.git