每周一个Vue小知识(一):@Component装饰器参数说明

1,658 阅读2分钟

关于在Vue中使用TypeScript时,基于vue-property-decorator的@Component装饰器参数说明

@Component装饰器接收一个对象(options:ComponentOptions = {}))作为参数,vue-property-decorator是这样声明的:

declare module 'vue/types/options' {
  interface ComponentOptions<V extends Vue> {
    router?: VueRouter
    beforeRouteEnter?: NavigationGuard<V>
    beforeRouteLeave?: NavigationGuard<V>
    beforeRouteUpdate?: NavigationGuard<V>
  }
}

由此可见@Component接受一个对象参数,该对象中可传可选参数路由router,以及Vue导航守卫beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。
vue-router导航守卫[官方文档]
“导航”表示路由正在发生改变。导航守卫就是监听组件或页面进入、修改、离开,通过跳转还是取消的方式守卫导航。

守卫钩子接受三个参数:

  • to: Route: 即将要进入的目标路由对象。到哪里去
  • from: Route: 当前导航正要离开的路由。从哪里来
  • next: NavigationGuardNext: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。要干什么
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。 **确保 next 函数在任何给定的导航守卫中都被严格调用一次。
//Home.vue

<template>
  <div class="home">
    <h1>{{ title }}</h1>
    <HomeComponent msg="Hello World" />
  </div>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator"; //导入Component装饰器
import HomeComponent from "@/components/HomeComponent.vue"; // 引入组件
import { NavigationGuardNext, Route } from "vue-router";

@Component({
  components: {
    HomeComponent,
  },
  beforeRouteEnter(to: Route, from: Route, next: NavigationGuardNext) {
    // 导航进入该组件的对应路由时调用,或者可以理解为从另一个页面跳转到当前页面
    console.log("*****Home***Enter*****");
    console.log("beforeRouteEnter", this); //undefined
    console.log("to", to);
    console.log("from", from);
    next((vm: any) => {
      console.log(vm); // vm就是当前组件的实例,相当于this
      // 因为当beforeRouteEnter钩子执行前,组件实例还未被创建
      // 所有需要通过传一个回调给next来访问组件实例
      // 在下面定义了一个title变量,我们来改变这个参数试试
      vm._data.title = "vmHomeTitle"; //不知道这样操作对不对,编译运行都没报错和警告,^_^
    });
  },
  beforeRouteUpdate(to: Route, from: Route, next: NavigationGuardNext) {
    // 在当前路由改变,但是该组件被复用时调用
    // 对于一个带有动态参数的路径 /home/:id,在 /home/1 和 /home/2 之间跳转的时候,
    // 由于会渲染同样的home组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问当前组件实例this
    console.log("*****Home***Update*****");
    console.log("Update", this); //当前组件实例
    console.log("to", to);
    console.log("from", from);
    console.log("next", next);
    // 注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。
    // 对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。
    next();
  },
  beforeRouteLeave(to: Route, from: Route, next: NavigationGuardNext) {
    // 导航离开该组件的对应路由时调用,或者可以理解为从当前页面跳转到另一个页面
    // 可以访问当前组件实例this
    console.log("*****Home***Leave*****");
    console.log("Leave", this); //当前组件实例
    console.log("to", to);
    console.log("from", from);
    console.log("next", next);
    // 这个离开守卫通常用来禁止用户在还未保存修改前突然离开。
    // 该导航可以通过 next(false) 来取消。
    const answer = window.confirm(
      "Do you really want to leave? you have unsaved changes!"
    );
    if (answer) {
      next();
    } else {
      next(false);
    }
  },
})
export default class Home extends Vue {
  private title = "HomeTitle";
}
</script>

//HomeComponent.vue

<template>
  <h1>{{ msg }}</h1>
</template>
<script lang='ts'>
import { Component, Vue, Prop } from "vue-property-decorator";

@Component
export default class HomeComponent extends Vue {
  @Prop() private msg!: string;
}
</script>
<style scoped>
</style>

**内容原创,整理不易,转载请注明出处!!!谢谢合作!**