美文网首页
Vue Router3.x/Vue Router4.x 保姆级教

Vue Router3.x/Vue Router4.x 保姆级教

作者: 洪锦一 | 来源:发表于2023-01-13 11:40 被阅读0次

    Vue Router3

    1.动态路由匹配

    动态路径参数 以冒号开头

    设置单个参数

    // 路由配置
    { 
        path: '/user/:id',
        name:'user'
        component: User 
    }
    
    // 跳转匹配路由
    this.$router.push('/user/8'); // 第一种方式
    this.$router.push({ name: 'user', params: { id: 8 } }); // 第二种方式
    
    // 获取方式
    this.$route.params
    
    // 输出结果
    {id: '8'}
    

    也可以设置多个参数

    // 路由配置
    { 
        path: '/user/:id/:type',
        name:'user'
        component: User 
    }
    
    // 跳转匹配路由
    this.$router.push('/user/8/one');
    this.$router.push({ name: 'user', params: { id: 8,type:'one' } });
    
    // 获取方式
    this.$route.params
    
    // 输出结果
    {id: '8', type: 'one'}
    

    2.嵌套路由

    要在页面嵌套别的组件,需要配置父路由的children属性,在父页面添加 router-view 占位符

    当路径为 /nestRoute/zhangsan 时候加载 zhangsan 的组件,/nestRoute/lisi 加载 lisi 组件

    const router = new VueRouter({
        routes: [
            {
            path: '/nestRoute',
            component: nestRoute,
            children: [
                { 
                path: 'zhangsan',
                component: zhangsan
                },
                { 
                path: 'lisi',
                component: lisi
                }
            ]
            }
        ]
    }) 
    

    注意:以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。

    3.编程式的导航

    router、routes、route的区别

    1、router:路由器对象(new的路由器对象),包含一些操作路由的功能函数,来实现编程式导航。一般指的是在任何组件内访问路由。如:路由编程式导航的$router.push()

    2、routes:指创建vue-router路由实例的配置项。用来配置多个route路由对象

    3、route:指路由对象表示当前激活的路由的状态信息。如:this.$route指的是当前路由对象,path/meta/query/params

    声明式导航

    router-link 会生成a标签

    router-link 等同于router.push()

    编程式导航

    一、this.$router.replace() 它不会向 history 添加新记录,不能后退

    二、this.$router.push() 这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

    该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:

    • 字符串
      router.push('home')

    • 对象
      router.push({ path: 'home' })

    • 命名的路由 router里面配置的name名字 params 动态路径参数,以冒号开头 ,如果路由里面配置了/user/:userId 在地址栏显示,如果不配置不在地址栏显示,在页面也可以使用params拿到传过来的参数
      router.push({ name: 'user', params: { userId: '123' }})

    • 带查询参数,变成 /register?plan=private
      router.push({ path: 'register', query: { plan: 'private' }})

    注意:如果提供了 path,params 会被忽略

    const userId = '123'
    
    router.push({ name: 'user', params: { userId }}) ====> /user/123
    
    router.push({ path: `/user/${userId}` }) ====> /user/123
    
    // 这里的 params 不生效
    router.push({ path: '/user', params: { userId }}) ====> /user
    

    同样的规则也适用于 router-link 组件的 to 属性。

    router.go

    这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)

    // 在浏览器记录中前进一步,等同于 history.forward()
    router.go(1)
    
    // 后退一步记录,等同于 history.back()
    router.go(-1)
    
    // 前进 3 步记录
    router.go(3)
    
    // 如果 history 记录不够用,那就默默地失败呗
    router.go(-100)
    router.go(100)  
    

    操作 History

    你也许注意到 router.push、 router.replace 和 router.go 跟

    window.history.pushState、 window.history.replaceState 和 window.history.go (opens new window)好像,实际上它们确实是效仿 window.history API 的。

    因此,如果你已经熟悉 Browser History APIs (opens new window),那么在 Vue Router 中操作 history 就是超级简单的。

    还有值得提及的,Vue Router 的导航方法 (push、 replace、 go) 在各类路由模式 (history、 hash 和 abstract) 下表现一致。

    4.命名路由

    有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给路由设置name属性。

      const router = new VueRouter({
        routes: [
          {
            path: '/user/:userId',
            name: 'user',
            component: User
          }
        ]
      })
    

    要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象:

      <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
    

    这跟代码调用 router.push() 是一回事:

      router.push({ name: 'user', params: { userId: 123 } })
    

    5.命名视图

    同级展示多个视图,而不是嵌套展示。例如:企业官网header、content、footer 三个视图,这个时候命名视图就派上用场了。如果router-view 没有设置名字,那么默认为default

      <router-view class="head"></router-view>
    
      <router-view class="cont" name="content"></router-view>
      
      <router-view class="foot" name="footer"></router-view>
    

    一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):

      const router = new VueRouter({
        routes: [
          {
            path: 'website',
            components: {
              default: () => import('@/views/vue/route/nameView/header'),
              content: () => import('@/views/vue/route/nameView/content'),
              footer: () => import('@/views/vue/route/nameView/footer')
            }
          }
        ]
      })
    

    嵌套命名视图

    我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 router-view 组件。我们以一个设置面板为例:

      /settings/emails                                       /settings/profile
      +-----------------------------------+                  +------------------------------+
      | UserSettings                      |                  | UserSettings                 |
      | +-----+-------------------------+ |                  | +-----+--------------------+ |
      | | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |
      | |     +-------------------------+ |                  | |     +--------------------+ |
      | |     |                         | |                  | |     | UserProfilePreview | |
      | +-----+-------------------------+ |                  | +-----+--------------------+ |
      +-----------------------------------+                  +------------------------------+
    
    
      //嵌套命名视图
      
      <div>
        <h1>User Settings</h1>
        <NavBar/>
        <router-view/>
        <router-view name="helper"/>
      </div>
    
      
      {
        path: '/settings',
        // 你也可以在顶级路由就配置命名视图
        component: UserSettings,
        children: [{
          path: 'emails',
          component: UserEmailsSubscriptions
        }, {
          path: 'profile',
          components: {
            default: UserProfile,
            helper: UserProfilePreview
          }
        }]
      }
    

    6.重定向和别名

    重定向

    重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:
    const router = new VueRouter({
    routes: [
    { path: '/a', redirect: '/b' }
    ]
    })

      重定向的目标也可以是一个命名的路由:
      const router = new VueRouter({
        routes: [
          { path: '/a', redirect: { name: 'foo' }}
        ]
      })
    
    
      甚至是一个方法,动态返回重定向目标:
      const router = new VueRouter({
        routes: [
          { path: '/a', redirect: to => {
            // 方法接收 目标路由 作为参数
            // return 重定向的 字符串路径/路径对象
            const { hash, query, params } = to
            if(hash=='') return {name:'',hash:''}
            if(query=='') return {path:'',query:null}
            if(params=='') return {'/a/:id'}
            else return {'/a'}
          }}
        ]
      })
    

    别名

    /a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

      const router = new VueRouter({
        routes: [
          { path: '/a', component: A, alias: '/b' }
        ]
      })
    
      “别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
    

    7.通过props传参

    // 路由配置
    {
        path: '/routeParam/:id',
        name: 'RouteParam',
        component: () => import('@/views/vue/route/routeParam'),
        meta: { title: '路由组件传参' },
        // props: true, 布尔模式
        // props: { name: 'zhangsan'}  对象模式
        props: (route) => ({    //函数模式
            name: 'zhangsan',
            id: route.params.id,
            // hh:route.query.id
        })
    },
    

    正常传参

    $router.push({ name: 'RouteParam', params: { id: 333 } })
    
    通过 this.$route.params 获取参数
    

    通过布尔模式传参

    通过 props 解耦,在路由中设置 props:true,在页面中添加props: ['id'],在页面直接获取id就行

    对于包含命名视图的路由,你必须分别为每个命名视图添加 props 选项:

    路径  path: '/routeParam/:id',
    
    $router.push('/routeParam/666')
    
    获取直接使用 {{ id }}
    

    对象模式

    如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。

     const router = new VueRouter({
        routes: [
            {
            path: '/routeParam/:id',
            component: Promotion,
            props: { name: 'zhangsan' }
            }
        ]
    })
    
    export default {
        props: ['id', 'name'],
    };
    
    页面直接使用 {{name}} 获取参数
    

    函数模式

    你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。

    const router = new VueRouter({
        routes: [
            {
                path: '/search',
                component: SearchUser,
                props: route => ({ query: route.query.q })
            }
        ]
    })
    
    获取方式 通过 {{ name }}
    export default {
      props: ['id', 'name','hh'],
    }
    

    8.导航守卫

    全局前置守卫

    当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。

    router.beforeEach((to, from, next) => {
        console.log(to);
        console.log(from);
        next()
    })
    

    to: 即将要进入的目标 路由对象

    from: 当前导航正要离开的路由

    next: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数

    全局解析守卫

    在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

    全局后置钩子

    你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

    router.afterEach((to, from) => {
        // ...
    })
    

    路由独享的守卫

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

    const router = new VueRouter({
        routes: [
            {
                path: '/foo',
                component: Foo,
                beforeEnter: (to, from, next) => {
                    // ...
                }
            }
        ]
    })
    

    这些守卫与全局前置守卫的方法参数是一样的。

    组件内的守卫

    可以在组件中定义守卫,可以在路由组件内直接定义以下路由导航守卫:

    • beforeRouteEnter

    • beforeRouteUpdate (2.2 新增)

    • beforeRouteLeave

    export default {
        beforeRouteEnter(to, from, next) {
            // 在渲染该组件的对应路由被 confirm 前调用
            // 不!能!获取组件实例 `this`
            // 因为当守卫执行前,组件实例还没被创建
        },
        beforeRouteUpdate(to, from, next) {
            // 在当前路由改变,但是该组件被复用时调用
            // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
            // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
            // 可以访问组件实例 `this`
        },
        beforeRouteLeave(to, from, next) {
            // 导航离开该组件的对应路由时调用
            // 可以访问组件实例 `this`
        },
    };
    

    完整的导航解析流程

    1、导航被触发。

    2、在失活的组件里调用 beforeRouteLeave 守卫。

    3、调用全局的 beforeEach 守卫。

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

    5、在路由配置里调用 beforeEnter。

    6、解析异步路由组件。

    7、在被激活的组件里调用 beforeRouteEnter。

    8、调用全局的 beforeResolve 守卫 (2.5+)。

    9、导航被确认。

    10、调用全局的 afterEach 钩子。

    11、触发 DOM 更新。

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

    9.路由元信息

    定义路由的时候可以配置 meta 字段:

    const router = new VueRouter({
        routes: [
            {
                path: '/foo',
                component: Foo,
                children: [
                    {
                    path: 'bar',
                    component: Bar,
                    // a meta field
                    meta: { requiresAuth: true }
                    }
                ]
            }
        ]
    })
    

    routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录

    例如,根据上面的路由配置,/foo/bar 这个 URL 将会匹配父路由记录以及子路由记录。

    一个路由匹配到的所有路由记录会暴露为 route 对象 (还有在导航守卫中的路由对象) 的route.matched 数组。因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段。

    在全局导航守卫中检查元字段:

    router.beforeEach((to, from, next) => {
        if (to.matched.some(record => record.meta.requiresAuth)) {
            if (!auth.loggedIn()) {
            next({
                path: '/login',
                query: { redirect: to.fullPath }
            })
            } else {
                next()
            }
        } else {
            next() // 确保一定要调用 next()
        }
    })
    

    10.过渡动效

    单个路由的过渡

    <transition name="slide-right">
        <router-view></router-view>
    </transition>
    
    
    // 添加样式
    .slide-left-enter, .slide-right-leave-to {
        opacity: 0;
        transform: translateX(100%)
    }
    
    .slide-left-leave-to, .slide-right-enter {
        opacity: 0;
        transform: translateX(-100%)
    }
    
    .slide-left-enter-active, .slide-left-leave-active, .slide-right-enter-active, .slide-right-leave-active {
        transition: 1.5s;
        position: absolute;
        top:0;
    }
    

    11.数据获取

    有时候,进入某个路由后,需要从服务器获取数据。例如,在渲染用户信息时,你需要从服务器获取用户的数据。我们可以通过两种方式来实现:

    1、导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。

    当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。

    2、导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。从技术角度讲,两种方式都不错 —— 就看你想要的用户体验是哪种。

    通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter 守卫中获取数据,当数据获取成功后只调用 next 方法。

    12.滚动行为

    只有在全局下才可以起作用,body有滚动条才可以,

    scrollBehavior(to, from, savedPosition) {
        // return 期望滚动到哪个的位置
        console.log(savedPosition);
        return {y:200}
    }
    

    13.捕获所有路由或 404 Not found 路由

    匹配所有路径
    { path: '*', redirect: '/404', hidden: true }

      匹配以 `/user-` 开头的任意路径
      { path: '/user-*', redirect: '/404', hidden: true }
    

    注意:通配符的路由应该放在最后

    当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:

      给出一个路由 { path: '/user-*' }
      this.$router.push('/user-admin')
      this.$route.params.pathMatch ===> 'admin'
    
      给出一个路由 { path: '*' }
      this.$router.push('/non-existing')
      this.$route.params.pathMatch ===> '/non-existing'
    

    14. 路由组件传参的方式(总结)

    通过 params 传递

    路由配置

    const routes = [
      // 动态段以冒号开始
      { path: 'details/:id', name: "details", component: Details },
    ]
    

    传参方式

    // 字符串路径
    this.$router.push('/details/001')
    
    // 带有路径的对象
    this.$router.push({path: '/details/001'})
    
    // 命名路由,路由配置时,需要 name 字段
    this.$router.push({ name: 'details', params: { id: '001' } })
    
    // 注意,如果提供了 path,params 会被忽略:`params` 不能与 `path` 一起使用
    router.push({ path: '/details', params: { id: '001' } }) // -> /details
    

    获取方式

    this.$route.params
    

    通过 query 传递

    这种情况下 query (查询参数)传递的参数会显示在 url 后面,如:/details/001?kind=car。

    路由配置

    const routes = [
      { path: 'details/:id', name: "details", component: Details },
    ]
    

    传参方式

    // 使用 query 时,以下三种方式都是可行的:
    this.$router.push('/details/001?kind=car')
    
    this.$router.push({ path: '/details/001', query: { kind: "car" }})
    
    this.$router.push({ name: 'details', params: { id: '001' }, query: { kind: 'car' }})
    

    获取方式

    this.$route.query
    

    通过 hash 传递

    通过此方式,url 路径中带有 hash,例如:/details/001#car。

    路由配置

    const routes = [
      { path: 'details/:id', name: "details", component: Details },
    ]
    

    传参方式

    // 使用 hash 时,以下三种方式都是可行的(同 query):
    this.$router.push('/details/001#car')
    
    this.$router.push({ path: '/details/001', hash: '#car'})
    
    this.$router.push({ name: 'details', params: { id: '001' }, hash: 'car'})
    

    获取方式

    $route.hash.slice(1)
    

    通过 props 传递

    在组件中使用 $route 会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但我们可以通过 props 配置来解除这种行为。

    以解耦的方式使用 props 进行参数传递,主要是在路由配置中进行操作。

    1. 布尔模式
      当 props 设置为 true 时,route.params 将被设置为组件的 props。

    路由配置中,增加 props 字段,并将值 设置为 true

    const User = {
      props: ['id'], // 组件中通过 props 获取 id
      template: '<div>User {{ id }}</div>'
    }
    
    const routes = [{ path: '/user/:id', component: User, props: true }]
    

    注意:对于有命名视图的路由,你必须为每个命名视图定义 props 配置:

    const routes = [
      {
        path: '/user/:id',
        components: { default: User, sidebar: Sidebar },
        // 为 User 提供 props
        props: { default: true, sidebar: false }
      }
    ]
    
    1. 对象模式

    当 props 是一个对象时,它将原样设置为组件 props。当 props 是静态的时候很有用。

    路由配置

    const routes = [
      {
        path: '/hello',
        component: Hello,
        props: { name: 'World' }
      }
    ]
    

    组件中获取数据

    const Hello = {
      props: {
        name: {
          type: String,
          default: 'Vue'
        }
      },
      template: '<div> Hello {{ name }}</div>'
    }
    

    <Hello /> 组件默认显示 Hello Vue,但路由配置了 props 对象,当路由跳转到 /hello 时,会显示传递过来的 name, 页面会显示为 Hello World。

    1. 函数模式

    可以创建一个返回 props 的函数。这允许你将参数转换为其他类型,将静态值与基于路由的值相结合等等。

    使用函数模式时,返回 props 的函数接受的参数为路由记录 route。

    路由配置

    // 创建一个返回 props 的函数
    const dynamicPropsFn = (route) => {
      return { name: route.query.say + "!" }
    }
    const routes = [
      {
        path: '/hello',
        component: Hello,
        props: dynamicPropsFn
      }
    ]
    

    组件获取数据

    // 当 URL 为 /hello?say=World 时, 将传递 {name: 'World!'} 作为 props 传给 Hello 组件。
    const Hello = {
      props: {
        name: {
          type: String,
          default: 'Vue'
        }
      },
      template: '<div> Hello {{ name }}</div>'
    }
    

    注意:请尽可能保持 props 函数为无状态的,因为它只会在路由发生变化时起作用。如果你需要状态来定义 props,请使用包装组件,这样 vue 才可以对状态变化做出反应。

    通过 Vuex 进行传递

    1. store 存储状态

    2. A 组件更改 store 中的状态

    3. B 组件从 store 中获取

    通过前端本地存储等方式

    1. Local Storage;

    2. Session Storage;

    3. IndexedDB;

    4. Web SQL;

    5. Cookies。

    Vue Router4

    1.index.js

    3.x的写法
    这种写法是比较通用的,配置的是动态路由,前台只配置常用的几个即可。

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    const routes = [{
      path: '/',
      name: '首页',
      component: () =>
        import( /* webpackChunkName: "page" */ '@/views/index'),
      meta: {
        requireAuth: true,
      },
      children: [{
        path: '/index',
        name: '首页',
        component: () =>
          import( /* webpackChunkName: "page" */ '@/views/wel'),
        meta: {
          requireAuth: true,
        }
      }]
    }]
    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    export default router
    

    4.x的写法
    导入createRouter, createWebHistory这两个方法,使用createWebHistory方法创建一个routerHistory对象,使用 createRouter 创建路由器。

    import { createRouter, createWebHistory } from "vue-router";
    import login from "../views/login.vue";
    import index from "../views/index.vue";
    const routes = [
      {
        path: "/login",
        name: "登录",
        component: login,
        meta: {
          requireAuth: false,
        },
      }, {
        path: "/",
        name: "首页",
        component: index,
        meta: {
          requireAuth: true,
        },
      },
    ];
    const router = createRouter({
      history: createWebHistory(process.env.BASE_URL),
      routes
    });
    export default router;
    

    2.创建方式

    3.x的写法

    import VueRouter from "vue-router"'
    const router = new VueRouter({
        // options
        ......
    })
    

    4.x的写法

    import { createRouter } from "vue-router"
    const router = createRouter({
        // opyions.....
    })
    

    3.路由模式

    3.x的写法

    const router = new VueRouter({
        mode: 'hash' / 'history'
    })
    

    4.x的写法

    import {createRouter, createWebHashHistory,createWebHashHistory} from 'vue-router'
    const router = createRouter({
        history:createWebHashHistory() / createWebHashHistory()
    })
    

    4.动态路由匹配

    3.x的写法

    { path: '*',component: 404page }
    

    4.x的写法

    // 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
    { path:'/:pathMatch(.*)*',component: NotFound  },
    
    // 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
    { path: '/user-:afterUser(.*)', component: UserGeneric  },
    

    使用以前的*语法会报错,也无法解析到任意路径上。

    5.重定向

    3.x的写法

    {
        path: '*',
        redirect: Home
    }
    

    4.x的写法

    {
        path: '/:pathMatch(.*)*', // 需要使用正则去匹配
        redirect: Home,
    }
    

    6.挂载方式

    3.x的写法

    import router from './router.js'
    
    new Vue({
        router
    })
    

    4.x的写法

    import { createApp } from 'vue'import router from './router.js'
    import App from './App.vue'
    
    createApp(App).use(router).mount('#app');
    

    7.件中的使用

    3.x的写法

    export default({       
        methods:{         
            linkToHome(){           
                this.$router.push({path:'/'   })
            }
        }
    })
    

    4.x的写法
    因为setup中不能访 this,所以提供两个api来获取 router 和 route , useRouter() 和 useRoute()

    import { useRouter,useRoute } from "vue-router"
    
    export default({      
        setup(){
          const router = useRouter();
          const route = useRoute();
          const linkToHome = () => {
            router.push({path:'/'})
          }
          return{ linkToHome }
        }
    })
    

    8.导航守卫

    由于 vue3 composition api的原因,beforeRouteUpdate 和 beforeRouteLeave被替换为 onBeforeRouteUpdate 和 onBeforeRouteLeave

    9.路由的匹配语法

    在参数中自定义正则

    当定义像 :userId 这样的参数时,我们内部使用以下的正则 ([^/]+) (至少有一个字符不是斜杠 / )来从 URL 中提取参数。这很好用,除非你需要根据参数的内容来区分两个路由。想象一下,两个路由 /:orderId 和 /:productName,两者会匹配完全相同的 URL,所以我们需要一种方法来区分它们。最简单的方法就是在路径中添加一个静态部分来区分它们:

    const routes = [
      // 匹配 /o/3549
      { path: '/o/:orderId' },
      // 匹配 /p/books
      { path: '/p/:productName' },
    ]
    

    但在某些情况下,我们并不想添加静态的 /o /p 部分。由于,orderId 总是一个数字,而 productName 可以是任何东西,所以我们可以在括号中为参数指定一个自定义的正则:

    const routes = [
      // /:orderId -> 仅匹配数字
      { path: '/:orderId(\\d+)' },
      // /:productName -> 匹配其他任何内容
      { path: '/:productName' },
    ]
    

    可重复的参数

    如果你需要匹配具有多个部分的路由,如 /first/second/third,你应该用 *(0 个或多个)和 +(1 个或多个)将参数标记为可重复:

    const routes = [
      // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
      { path: '/:chapters+' },
    
      // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
      { path: '/:chapters*' },
    ]
    

    这将为你提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要你传递一个数组:

    // 给定 { path: '/:chapters*', name: 'chapters' },
    router.resolve({ name: 'chapters', params: { chapters: [] } }).href
    // 产生 /
    router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
    // 产生 /a/b
    
    // 给定 { path: '/:chapters+', name: 'chapters' },
    router.resolve({ name: 'chapters', params: { chapters: [] } }).href
    // 抛出错误,因为 `chapters` 为空 
    

    这些也可以通过在右括号后添加它们与自定义正则结合使用:

    const routes = [
      // 仅匹配数字
      // 匹配 /1, /1/2, 等
      { path: '/:chapters(\\d+)+' },
      // 匹配 /, /1, /1/2, 等
      { path: '/:chapters(\\d+)*' },
    ]
    

    Sensitive 与 strict 路由配置

    默认情况下,所有路由是不区分大小写的,并且能匹配带有或不带有尾部斜线的路由。例如,路由 /users 将匹配 /users、/users/、甚至 /Users/。这种行为可以通过 strict 和 sensitive 选项来修改,它们可以既可以应用在整个全局路由上,又可以应用于当前路由上:

    const router = createRouter({
      history: createWebHistory(),
      routes: [
        // 将匹配 /users/posva 而非:
        // - /users/posva/ 当 strict: true
        // - /Users/posva 当 sensitive: true
        { path: '/users/:id', sensitive: true },
        // 将匹配 /users, /Users, 以及 /users/42 而非 /users/ 或 /users/42/
        { path: '/users/:id?' },
      ]
      strict: true, // applies to all routes
    })
    

    可选参数

    你也可以通过使用 ? 修饰符(0 个或 1 个)将一个参数标记为可选:

    const routes = [
      // 匹配 /users 和 /users/posva
      { path: '/users/:userId?' },
      // 匹配 /users 和 /users/42
      { path: '/users/:userId(\\d+)?' },
    ]
    

    请注意,* 在技术上也标志着一个参数是可选的,但 ? 参数不能重复。

    相关文章

      网友评论

          本文标题:Vue Router3.x/Vue Router4.x 保姆级教

          本文链接:https://www.haomeiwen.com/subject/mxegcdtx.html