重学vue(2, 3)及其生态+TypeScript 之 vue-router4.x(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 重学vue(2, 3)及其生态+TypeScript 之 vue-router4.x

两种路由模式


  • hash模式


{
        history: createWebHashHistory()
    }


  • history模式


{
        history: createWebHistory()
    }


内置组件


router-link: 切换到指定的组件。


下面介绍一下他的常用属性


  • to属性:是一个字符串,或者是一个对象


<!-- 字符串 -->
    <router-link to="/home">Home</router-link>
    <!-- 渲染结果 -->
    <a href="/home">Home</a>
    <!-- 使用 v-bind 的 JS 表达式 -->
    <router-link :to="'/home'">Home</router-link>
    <!-- 同上 -->
    <router-link :to="{ path: '/home' }">Home</router-link>
    <!-- 命名的路由 -->
    <router-link :to="{ name: 'user', params: { userId: '123' }}">User</router-link>
    <!-- 带查询参数,下面的结果为 `/register?plan=private` -->
    <router-link :to="{ path: '/register', query: { plan: 'private' }}">
      Register
    </router-link>


  • replace属性:设置 replace 属性的话,当点击时,会调用 router.replace(),而不是 router.push()。


  • active-class属性:设置激活a元素后应用的class,默认是router-link-active。如果父路径相同就会添加给a元素这个class。


  • exact-active-class属性:链接精准激活时,应用于渲染的 <a> 的 class,默认是router-link-exact-active。只有父子路径都相同时,才会添加这个class。


  • custom属性: 如果设置为ture, 他表示将当前router-link包裹的元素外的a标签去除。在使用 v-slot 创建自定义 RouterLink 时很有用。我们可以自定义跳转逻辑


  • v-slot指令: 接收作用域插槽传递的props。用于自定义router-link。 在vue-router3.x的时候,router-link有一个tag属性,可以决定router-link到底渲染成什么元素。但是在vue-router4.x开始,该属性被移除了。而给我们提供了更加具有灵活性的v-slot的方式来定制渲染的内容。


v-slot如何使用呢?


  • 首先,在router-link上设置custom属性,表示我们整个元素要自定义。如果不写,那么自定义的内容会被包裹在一个 a 元素中。


  • 其次,我们使用v-slot来作用域插槽来获取内部传给我们的值:


  • href:解析后的 URL。


  • route:解析后的规范化的route对象。


  • navigate:触发导航的函数。相当于router-link中的to属性做的事情。跳转页面到指定路径。


  • isActive:是否匹配的状态。相当于router-link中的active-class属性,如果匹配到了自动添加router-link-activeclass属性。我们可以通过isActive的值来自定义active-class值。


  • isExactActive:是否是精准匹配的状态。相当于router-link中的exact-active-class属性,如果匹配到了自动添加router-link-exact-activeclass属性。我们可以通过isExactActive的值来自定义exact-active-class值。


<router-link 
    to="/home"
    v-slot="props"
    custom
>
  <button @click="props.navigate">{{props.href}} 跳转到home</button>
  <button @click="props.navigate">跳转到home, 可以将props.navigate添加到多个元素上</button>
  <span :class="{'active': props.isActive}">{{props.isActive}}</span>
  <span :class="{'active': props.isActive}">{{props.isExactActive}}</span>
  <!-- <p>{{props.route}}</p> -->
 </router-link>


网络异常,图片无法展示
|


router-view: 切换路径,他就自动匹配到对应的组件。


  • name: 当我们需要多个视图,而不是嵌套展示。我们就可以通过name属性来匹配到route中提供的components组件。


网络异常,图片无法展示
|


  • v-slot指令: 接收作用域插槽传递的props。可以用于  和  组件来包裹你的路由组件。


其中提供两个props:


  • Component:要渲染的组件。即当前路由匹配到的组件。


<router-view v-slot="{ Component, route }">
      <transition>
        <keep-alive>
          <component
            :is="Component"
          />
        </keep-alive>
      </transition>
    </router-view>


  • route:解析出的标准化路由对象。即当前的路由对象。


路由懒加载


当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。也可以提高首屏的渲染效率。


其实路由懒加载就是给component属性传入一个工厂函数,并且返回一个promise对象。


component: () => import("../pages/home.vue")


动态路由


记得当时学习vue2的时候,了解到动态路由一头雾水。其实我们可以把它理解为为url传递参数,并在页面中获取到该参数,做一些事情。


很多时候我们需要将给定匹配模式的路由映射到同一个组件:例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但是用户的ID是不同的。在Vue Router中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数。


网络异常,图片无法展示
|


那么在User中如何获取到对应的值呢?


  • 在template中,直接通过 $route.params获取值。


  • 在created中,通过 this.$route.params获取值。


  • 在setup中,我们要使用 vue-router库给我们提供的一个hook useRoute。该Hook会返回一个Route对象,对象中保存着当前路由相关的值。

网络异常,图片无法展示
|


我们也可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。$route.params上保存的就是动态参数对象。


错误页面处理


当我们访问没有路由映射的页面时,我们需要给用户一些提示。


对于哪些没有匹配到的路由,我们通常会匹配到固定的某个页面。比如NotFound的错误页面中,这个时候我们可编写一个根路径下的动态路由用于匹配所有的页面。我们可以通过 $route.params.pathMatch 获取到传入的参数。


// 这种匹配是将错误路径以"/"作为分隔符,分割错误参数,并将其传入到patchMath数组中。
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }
  // 这种匹配是将错误路径当成整体传入到pathMatch属性中
  { path: '/:pathMatch(.*)', name: 'NotFound', component: NotFound }


网络异常,图片无法展示
|


网络异常,图片无法展示
|


嵌套路由


有时候,一个页面也可能出现多个组件间相互切换,我们就可以定义子路由来匹配到这个组件。注意:我们也需要在对应的位置设置router-view来渲染子路由匹配到的组件。


如何来定义子路由呢? 我们只需要在路由映射对象中定义一个children属性然后来定义子路由的映射即可。但是有一些注意事项:


  • path属性不需要加/, 如果加上了/,它将映射的是一级路由。


  • 重定向传入的路由是完整的href


{
    path: "/home",
    name: "home",
    component: () => import(/* webpackChunkName: "home-chunk" */"../pages/Home.vue"),
    children: [
      {
        path: "",
        redirect: "/home/message"
      },
      {
        path: "message",
        component: () => import("../pages/HomeMessage.vue")
      },
      {
        path: "goods",
        component: () => import("../pages/HomeGoods.vue")
      }
    ]
  }


路由跳转时参数传递


  • 通过params, 即上面讲到的动态路由。


  • 通过$route.params获取


  • 通过query, 当我们跳转路由时,不管是通过router-link还是通过$router.push()等API, 我们都可以传入一个query对象,并且在query对象中设置传递的参数。


  • 通过$route.query获取


  • 通过meta, 在我们定义路由映射表的时候,我们可以在meta字段中定义一些数据。


  • 通过$route.meta获取


  • 通过props,在我们定义路由映射表时,我们可以传递一些props给组件。这个就可以作为组件的props。


const routes = [
      {
        path: '/search',
        component: SearchUser,
        // 这里可以返回一个函数,动态传参。也可以直接返回一个props
        props: route => ({ query: route.query.q }) 
      }
    ]


编程式导航


我们知道,切换路由我们可以通过router-link组件来完成。但是我们大多数还是通过书写代码来切换路由的。


  • 在options API中,我们可以通过vue-router提供的this.$router对象调用其API来切换路由。


  • 在setup中,我们可以通过vue-router提供的hook useRouter来调用其API切换路由。


setup() {
        const router = useRouter()
        const routerSkip = () => {
          router.push('/about')
          router.replace('/about')
        }
    }


切换路由的API


  • push: 这个方法会向 history 栈添加一个新的记录,可以点击回退上一个路径。


  • replace: 它在导航时不会向 history 添加新记录。取代当前的路径。


  • go: 该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步。


  • back: 在历史堆栈中后退一步。相当于go(-1)


  • forward: 在历史堆栈中前进一步。相当于go(1)router.pushrouter.replacerouter.gowindow.history.pushStatewindow.history.replaceStatewindow.history.go的翻版,它们确实模仿了 window.history 的 API。


注意:前两个API传入的参数和router-link中to属性是一样的。当同时传入pathparams,这会忽略params


动态添加路由


某些情况下我们可能需要动态的来添加路由。比如根据用户不同的权限,注册不同的路由。这个时候我们可以使用一个方法 addRoute


  • 添加一级路由。我们只需要向addRoute中添加一个参数。如果路由有一个 name字段,并且已经有一个与之名字相同的路由,它会先删除之前的路由。


// 动态添加路由
    const categoryRoute = {
      path: "/category",
      component: () => import("../pages/Category.vue")
    }
    // 添加顶级路由对象
    router.addRoute(categoryRoute);


  • 添加二级路由。我们需要传入当前路由(即路由的name字段)和添加的子路由。


// 添加二级路由对象
    router.addRoute("home", {
      path: "moment",
      component: () => import("../pages/HomeMoment.vue")
    })


动态删除路由


与动态添加路由对应。


删除路由有以下三种方式:


  • 方式一:添加一个name相同的路由。


网络异常,图片无法展示
|


  • 方式二:通过removeRoute方法,传入路由的名称。


网络异常,图片无法展示
|


  • 方式三:通过addRoute方法的返回值回调。


网络异常,图片无法展示
|


当路由被删除时,所有的别名和子路由也会被同时删除


导航守卫


vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。在跳转之前,之后等状态时,做一些逻辑处理。类似于Express, Koa中的中间件。


下面我们来讲一讲全局前置守卫router.beforeEach。其他的守卫用法一致,只是调用时机不同而已。


它有三个参数:


  • to:即将进入的路由Route对象。


  • from:即将离开的路由Route对象。


  • next(可选):允许路由正常跳转。在vue-router3.x中,他是必传的,但是在4.x官方已不再建议使用。当不满足条件时,我们可以通过返回一个路径字符串或者一个对象来指定跳转。满足条件时,他会自动跳转。


它有返回值:


  • false:取消当前导航跳转。


  • 不返回或者undefined:进行默认导航跳转。


  • 返回一个路由地址。可以是一个string类型的路径,也可以是一个对象,对象中包含path、query、params等信息。 下面这个例子,就是当用户未登录的时候,不管访问任何页面,我们都让其跳转到login页面。


router.beforeEach((to, from) => {
      if (to.path !== "/login") {
        const token = window.localStorage.getItem("token");
        if (!token) {
          return "/login"
        }
      }
    })


其他的导航守卫,请访问官网:next.router.vuejs.org/zh/guide/ad…


完整的导航解析流程


  1. 导航被触发。


  1. 在失活的组件里调用 beforeRouteLeave 守卫。


  1. 调用全局的 beforeEach 守卫。


  1. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。


  1. 在路由配置里调用 beforeEnter


  1. 解析异步路由组件。


  1. 在被激活的组件里调用 beforeRouteEnter


  1. 调用全局的 beforeResolve 守卫(2.5+)。


  1. 导航被确认。


  1. 调用全局的 afterEach 钩子。


  1. 触发 DOM 更新。


  1. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。


相关文章
|
3月前
|
JavaScript 前端开发 安全
【技术革新】Vue.js + TypeScript:如何让前端开发既高效又安心?
【8月更文挑战第30天】在使用Vue.js构建前端应用时,结合TypeScript能显著提升代码质量和开发效率。TypeScript作为JavaScript的超集,通过添加静态类型检查帮助早期发现错误,减少运行时问题。本文通过具体案例展示如何在Vue.js项目中集成TypeScript,并利用其类型系统提升代码质量。首先,使用Vue CLI创建支持TypeScript的新项目,然后构建一个简单的待办事项应用,通过定义接口描述数据结构并在组件中使用类型注解,确保代码符合预期并提供更好的编辑器支持。
85 0
|
3月前
|
JavaScript 前端开发 安全
立等可取的 Vue + Typescript 函数式组件实战
立等可取的 Vue + Typescript 函数式组件实战
|
4月前
|
JavaScript 前端开发
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
51 0
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
|
5月前
|
JavaScript 安全 前端开发
Vue 3 中的 TypeScript
【6月更文挑战第15天】
84 6
|
6月前
|
JavaScript 前端开发 开发者
类型检查:结合TypeScript和Vue进行开发
【4月更文挑战第24天】TypeScript是JavaScript超集,提供类型注解等特性,提升代码质量和可维护性。Vue.js是一款高效前端框架,两者结合优化开发体验。本文指导如何配置和使用TypeScript与Vue:安装TypeScript和Vue CLI,创建Vue项目时选择TypeScript支持,配置`tsconfig.json`,编写`.tsx`组件,最后运行和构建项目。这种结合有助于错误检查和提升开发效率。
56 2
|
6月前
|
JavaScript 前端开发 开发者
Vue工具和生态系统: Vue.js和TypeScript可以一起使用吗?
【4月更文挑战第18天】Vue.js与TypeScript兼容,官方文档支持在Vue项目中集成TypeScript。TypeScript作为JavaScript超集,提供静态类型检查和面向对象编程,增强代码准确性和健壮性。使用TypeScript能提前发现潜在错误,提升代码可读性,支持接口和泛型,使数据结构和函数更灵活。然而,不是所有Vue插件都兼容TypeScript,可能需额外配置。推荐尝试在Vue项目中使用TypeScript以提升项目质量。
117 0
|
6月前
|
JavaScript 前端开发
在Vue中使用TypeScript的常见问题有哪些?
在Vue中使用TypeScript的常见问题有哪些?
101 2
|
1月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
48 0
|
1月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
2月前
|
存储 JavaScript
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
48 0
下一篇
无影云桌面