vue3 Router

本文详细介绍了Vue3中vue-router的安装、配置、使用,包括命名路由、编程式导航、路由历史记录、路由传参、嵌套路由、命名视图、重定向、别名以及路由守卫的用法,是Vue3应用开发的重要参考资料。

vue3 Router

参考学习笔记来自 作者:小满zs
vue-router_小满zs的博客-CSDN博客

1. 安装配置

(1)安装vue-router

// vue2
npm install vue-router@3 -S

// vue3
npm install vue-router@4 -S

(2)配置路由

  • 在src目录下创建router文件夹并新建index.ts
//引入路由对象
import { createRouter, createWebHistory, createWebHashHistory, createMemoryHistory, RouteRecordRaw } from 'vue-router'
 
//路由数组的类型 RouteRecordRaw
// 定义一些路由
// 每个路由都需要映射到一个组件。
const routes: Array<RouteRecordRaw> = [{
    path: '/',
    component: () => import('../components/a.vue')
},{
    path: '/register',
    component: () => import('../components/b.vue')
}]
 
 
 
const router = createRouter({
    history: createWebHistory(),
    routes
})
 
// 导出router
export default router

(3)使用路由

  • 在main.ts 挂载
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

export const app = createApp(App)

app.use(router)

app.mount('#app')
  • 使用路由
<template>
  <div>
    <h1>使用路由</h1>
    <div>
    <!--使用 router-link 组件进行导航 -->
    <!--通过传递 `to` 来指定链接 -->
    <!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
      <router-link tag="div" to="/">跳转a</router-link>
      <router-link tag="div" style="margin-left:200px" to="/register">跳转b</router-link>
    </div>
    <hr />
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
  </div>
</template>

2. 命名路由

为路由提供name属性,有如下优点

  • 没有硬编码的 URL
  • params 的自动编码/解码。
  • 防止你在 url 中出现打字错误。
  • 绕过路径排序(如显示一个)
const routes:Array<RouteRecordRaw> = [
    {
        path:"/",
        name:"Login",
        component:()=> import('../components/login.vue')
    },
    {
        path:"/reg",
        name:"Reg",
        component:()=> import('../components/reg.vue')
    }
]
    <h1>小满最骚</h1>
    <div>
      <router-link :to="{name:'Login'}">Login</router-link>
        <!--改变router-link 的跳转方式-->
      <router-link style="margin-left:10px" :to="{name:'Reg'}">Reg</router-link>
    </div>
    <hr />

3. 编程式导航

(1)字符串模式

import { useRouter } from 'vue-router'
const router = useRouter()
 
const toPage = () => {
  router.push('/reg')
}

(2)对象模式

import { useRouter } from 'vue-router'
const router = useRouter()
 
const toPage = () => {
  router.push({
    path: '/reg'
  })
}

(3)命名式 路由模式

import { useRouter } from 'vue-router'
const router = useRouter()
 
const toPage = () => {
  router.push({
    name: 'Reg'
  })
}

(4)a标签跳转

 <a href="/reg">rrr</a>

4. 路由历史记录

(1)replace

采用replace进行页面的跳转会同样也会创建渲染新的Vue组件,但是在history中其不会重复保存记录,而是替换原有的vue组件

import { useRouter } from 'vue-router'
const router = useRouter()
 
const toPage = (url: string) => {
  router.replace(url)
}

(2)go

const next = () => {
  //前进 数量不限于1
  router.go(1)
}
 
const prev = () => {
  //后退
  router.go(-1)
}

(3)back

const prev = () => {
  //后退
  router.back()
}

5. 路由传参

区别

  • query 传参配置的是 path,而 params 传参配置的是name,在 params中配置 path 无效

  • query 在路由配置不需要设置参数,而 params 必须设置

  • query 传递的参数会显示在地址栏中

  • params传参刷新会无效,但是 query 会保存传递过来的值,刷新不变 ;

(1)Query路由传参

  • 传输参数
type Item = {
    name:string;
    price:number;
    id:number;
}
// 省略item的内容
const toDetail = (item: Item) => {
    router.push({
        path: '/reg',
        query: item
    })
}
  • 接收参数
import { useRoute } from 'vue-router';
const route = useRoute()

cosnt  name =  route.query?.name
cosnt  price  =  route.query?.price
cosnt id = route.query?.id

(2)Params路由传参

传入的参数页面刷新会丢失

  • 传输参数
type Item = {
    name:string;
    price:number;
    id:number;
}
const toDetail = (item: Item) => {
    router.push({
        name: 'Reg',
        params: item
    })
}
  • 接收参数
import { useRoute } from 'vue-router';
const route = useRoute()

cosnt  name =  route.query?.name
cosnt  price  =  route.query?.price
cosnt id = route.query?.id

(3)动态路由传参

  • 传输参数
const routes:Array<RouteRecordRaw> = [
    {
        path:"/",
        name:"Login",
        component:()=> import('../components/login.vue')
    },
    {
        //动态路由参数
        path:"/reg/:id",
        name:"Reg",
        component:()=> import('../components/reg.vue')
    }
]
const toDetail = (item: Item) => {
    router.push({
        name: 'Reg',
        params: {
            id: item.id
        }
    })
}
  • 接收参数
import { useRoute } from 'vue-router';
import { data } from './list.json'
const route = useRoute()
 
 
const item = data.find(v => v.id === Number(route.params.id))

6. 嵌套路由

  • 编写路由
const routes: Array<RouteRecordRaw> = [{
    path: '/',
    name: 'Layout',
    component: () => import('../layout/index.vue'),
    children: [
        {
            // 登录
            path: '/login',
            name: 'Login',
            component: () => import('../views/login/index.vue'),
        },
        {
            // 注册
            path: '/register',
            name: 'Register',
            component: () => import('../views/register/index.vue'),
        }
    ]
}

]

  • 页面跳转

App.vue

<template>
  <router-view />
</template>

<script setup lang="ts"></script>

<style scoped></style>

layout.vue

<template>
<router-link to="/login"><div class="item">登录</div></router-link>
<router-link to="/register"><div class="item">注册</div></router-link>
<!-- 显示路由组件-->
<router-view></router-view>
</template>

8. 命名视图

命名视图可以在同一级(同一个组件)中展示更多的路由视图,而不是嵌套显示。

命名视图可以在同一级(同一个组件)中展示更多的路由视图,而不是嵌套显示。

命名视图的概念非常类似于“具名插槽”,并且视图的默认名称也是 default。

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
 
 
const routes: Array<RouteRecordRaw> = [
    {
        path: "/",
        components: {
            default: () => import('../components/layout/menu.vue'),
            header: () => import('../components/layout/header.vue'),
            content: () => import('../components/layout/content.vue'),
        }
    },
]
 
const router = createRouter({
    history: createWebHistory(),
    routes
})
 
export default router

对应组件使用

    <div>
        <router-view></router-view>
        <router-view name="header"></router-view>
        <router-view name="content"></router-view>
    </div>

9. 重定向 redirect

  • 字符串形式
const routes: Array<RouteRecordRaw> = [
    {
        path:'/',
        component:()=> import('../components/root.vue'),
        redirect:'/user1',
        children:[
            {
                path:'/user1',
                components:{
                    default:()=> import('../components/A.vue')
                }
            },
            {
                path:'/user2',
                components:{
                    bbb:()=> import('../components/B.vue'),
                    ccc:()=> import('../components/C.vue')
                }
            }
        ]
    }
]
  • 对象形式
const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        component: () => import('../components/root.vue'),
        redirect: { path: '/user1' },
        children: [
            {
                path: '/user1',
                components: {
                    default: () => import('../components/A.vue')
                }
            },
            {
                path: '/user2',
                components: {
                    bbb: () => import('../components/B.vue'),
                    ccc: () => import('../components/C.vue')
                }
            }
        ]
    }
]
  • 函数模式
const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        component: () => import('../components/root.vue'),
        redirect: (to) => {
            return {
                path: '/user1',
                query: to.query
            }
        },
        children: [
            {
                path: '/user1',
                components: {
                    default: () => import('../components/A.vue')
                }
            },
            {
                path: '/user2',
                components: {
                    bbb: () => import('../components/B.vue'),
                    ccc: () => import('../components/C.vue')
                }
            }
        ]
    }
]

10. 别名 alias

/ 别名为 /root,意味着当用户访问 /root时,URL 仍然是 /user,但会被匹配为用户正在访问 /

const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        component: () => import('../components/root.vue'),
        alias:["/root","/root2","/root3"],
        children: [
            {
                path: 'user1',
                components: {
                    default: () => import('../components/A.vue')
                }
            },
            {
                path: 'user2',
                components: {
                    bbb: () => import('../components/B.vue'),
                    ccc: () => import('../components/C.vue')
                }
            }
        ]
    }
]

11. 路由守卫

(1)全局前置守卫(白名单判断)

  • 使用格式

to: Route, 即将要进入的目标 路由对象;
from: Route,当前导航正要离开的路由;
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。

router.beforeEach((to, form, next) => {
    console.log(to, form);
    next()
})
  • 白名单案例
const whileList = ['/', '/login', '/register']
 
router.beforeEach((to, from, next) => {
    let token = localStorage.getItem('token')
    //白名单 有值 或者登陆过存储了token信息可以跳转 否则就去登录页面
    if (whileList.includes(to.path) || token) {
        next()
    } else {
        next({
            path:'/login'
        })
    }
})

(2)全局后置守卫(加载loading)

  • 使用格式

使用场景一般可以用来做loadingBar,

router.afterEach((to,from)=>{
    console.log(to, form);
})
  • 加载缓冲案例
<template>
    <div class="wraps">
        <div ref="bar" class="bar"></div>
    </div>
</template>
    
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
let speed = ref<number>(1)
let bar = ref<HTMLElement>()
let timer = ref<number>(0)
const startLoading = () => {
    let dom = bar.value as HTMLElement;
    speed.value = 1
    timer.value = window.requestAnimationFrame(function fn() {
        if (speed.value < 90) {
            speed.value += 1;
            dom.style.width = speed.value + '%'
            timer.value = window.requestAnimationFrame(fn)
        } else {
            speed.value = 1;
            window.cancelAnimationFrame(timer.value)
        }
    })
 
}
 
const endLoading = () => {
    let dom = bar.value as HTMLElement;
    setTimeout(() => {
        window.requestAnimationFrame(() => {
            speed.value = 100;
            dom.style.width = speed.value + '%'
        })
    }, 500)
 
}
 
 
defineExpose({
    startLoading,
    endLoading
})
</script>
    
<style scoped lang="less">
.wraps {
    position: fixed;
    top: 0;
    width: 100%;
    height: 2px;
    .bar {
        height: inherit;
        width: 0;
        background: blue;
    }
}
</style>

main.ts

import loadingBar from './components/loadingBar.vue'
const Vnode = createVNode(loadingBar)
render(Vnode, document.body)
console.log(Vnode);
 
router.beforeEach((to, from, next) => {
    Vnode.component?.exposed?.startLoading()
})
 
router.afterEach((to, from) => {
    Vnode.component?.exposed?.endLoading()
})

12 . 路由元信息 mate

通过路由记录的 meta 属性可以定义路由的元信息。使用路由元信息可以在路由中附加自定义的数据

  • 权限校验标识
  • 路由组件的过渡名称
  • 路由组件持久化缓存 (keep-alive) 的相关配置
  • 标题名称
  • 写入元信息
// ts定义元信息 ,为了更好的处理
declare module 'vue-router' {
  interface RouteMeta {
    title?: string
  }
}


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      component: () => import('@/views/Login.vue'),
      // 元信息
      meta: {
        title: "登录"
      }
    },
    {
      path: '/index',
      component: () => import('@/views/Index.vue'),
      meta: {
        title: "首页",
      }
    }
  ]
})

13. 路由过渡动效

  • vue组件的处理
 <!--route路由信息,Component跳转的组件-->
<router-view #default="{route,Component}">
        <transition  :enter-active-class="`animate__animated ${route.meta.transition}`">
            <component :is="Component"></component>
        </transition>
    </router-view>
  • router index.ts的处理
declare module 'vue-router'{
     interface RouteMeta {
        title:string,
        transition:string,
     }
}
 
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      component: () => import('@/views/Login.vue'),
      meta:{
         title:"登录页面",
         transition:"animate__fadeInUp",
      }
    },
    {
      path: '/index',
      component: () => import('@/views/Index.vue'),
      meta:{
         title:"首页!!!",
         transition:"animate__bounceIn",
      }
    }
  ]
})

14. 滚动行为

简介:使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样

  • 使用scrollBehavior实现滚动

scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

const router = createRouter({
  history: createWebHistory(),
  scrollBehavior: (to, from, savePosition) => {
    //  savePosition里的值 为 { left: number, top: number }
    console.log(to, '==============>', savePosition);
    return new Promise((r) => {
      setTimeout(() => {
        r({
          top: 10000
        })
      }, 2000);
    })
  },

scrollBehavior 返回滚动位置的对象信息 =>{ left: number, top: number }

const router = createRouter({
  history: createWebHistory(),
  scrollBehavior: (to, from, savePosition) => {
    return {
       top:200
    }
  },

15. 动态路由

(1)操作路由

  • 添加路由
router.addRoute({ path: '/about', component: About })
  • 删除路由
// 第一种
const removeRoute = router.addRoute(routeRecord)
removeRoute() // 删除路由如果存在的话

// 第二种
router.addRoute({ path: '/about', name: 'about', component: About })
// 删除路由
router.removeRoute('about')
  • 查看路由
  • router.hasRoute():检查路由是否存在。
  • router.getRoutes():获取一个包含所有路由记录的数组。

(2)代码实现

const initRouter = async () => {
    const result = await axios.get('http://localhost:9999/login', { params: formInline });
    result.data.route.forEach((v: any) => {
        router.addRoute({
            path: v.path,
            name: v.name,
                                    //这儿不能使用@
            component: () => import(`../views/${v.component}`)
        })
        router.push('/index')
    })
    console.log(router.getRoutes());
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值