Vue-Router4 入门

本文详细介绍了如何在Vue3项目中,特别是在使用Vite的情况下,初始化并配置vue-router,包括手动引入、路由模式、编程式导航、路由传参、嵌套路由、命名视图、重定向与别名、导航守卫以及滚动行为。同时,讨论了动态路由的实现,展示了如何根据用户权限动态管理路由。
摘要由CSDN通过智能技术生成

1. 安装

初始化Vue3项目(推荐使用vite):

// vue
npm init vue@latest
// vite
npm init vite@latest

安装vue-router:

npm i vue-router -S

2. 引入路由

使用(npm init vue@latest)初始化项目时,选择router后,会自动安装并使用 vue-router。使用(npm init vite@latest)时,需要手动引入路由:

  1. 在src文件夹下创建router文件,并定义index.ts:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    {
      path: '/login',
      name: 'login',
      // 动态引入,可以实现组件懒加载以及代码分包
      component: () => import('../views/HomeView.vue')
    },
    {
      path: '/register',
      name: 'register',
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
  1. main.ts 中引入路由
import router from './router'
app.use(router)
  1. app.vue 中使用路由:
// 路由连接
<RouterLink to="/">login</RouterLink>&nbsp;
<RouterLink to="/register">register</RouterLink>
// 路由容器
<RouterView></RouterView>

3. vue-router4 与 vue-router3 的区别

  1. 引入router的方式:
// vue-router3中:
import Router from 'vue-router'
// vue-router4 中, 引入创建 router 的 hooks:
import { createRouter } from 'vue-router'
const router = createRouter(options)
  1. 路由模式
    vue-router3中模式选项为 mode,而 vue-router4中模式选项对应的是 history。
    router3 中三种模式与router4中三种模式对应关系:
    哈希模式(url带#号):
    router3 hash ===> router4 createWebHashHistory ;
    history模式:
    router3 history ===> router4 createWebHistory ;
    服务端渲染 SSR:
    router3 abstact ===> router4 createMemoryHistory
    hash 模式是基于 window.location.hash 实现的,这种模式会在url中生成一个#号,#后面包括#就是hash,我们可以通过添加事件 hashchange 来监听url的变化。
    history 模式是基于 H5 中的 history API 来实现的。我们可以通过 popstate 事件来监听url的变化,跳转到新页面时可以使用 history.pushState({}, title, ‘/login’),但是这个方法只会改变url的路径,并不会被 popstate 监听到,所以我们调用这个方法后,需要手动刷新。

4. 编程式导航

使用 router-link 跳转时,to 属性如果直接写地址的话,容易写错,我们可以使用name 属性:

<RouterLink :to="{name: 'login'}">login</RouterLink>

使用 replace 不产生历史记录:

<RouterLink replace :to="{name: 'login'}">login</RouterLink>

如果不想使用 router-link 路由链接进行跳转时,我们可以使用编程式导航:

import { useRouter } from 'vue-router';
const router = useRouter()
const toPage = (path: string) => {
  // 字符串 方式
  router.push(path)

  // 对象 方式
  /* router.push({
    path
  }) */

  // 命名式  path 对应的式路由的 name 值
  /* router.push({
    name: path
  }) */

  // replace 不产生历史记录
  // router.replace(path)
}
// 向前 2 级
const next = () => {
  router.go(2)
}
// 后退 1 级
const back = () => {
  router.back()
}
// 向前 1 级
const forward = () => {
	router.forward()
}

5. 路由传参

vue-router 路由传参有两种方式: query 传参 和 params 传参
query 传参(参数会显示在url上):

// 传参
import { useRouter } from 'vue-router';
router.push({ 
    path: '/register', // 可以用 path ,也可以用 name
    // name: 'register',
    query: item
})
// 接收
import { useRoute } from 'vue-router';
const route = useRoute()
const query = route.query

params 传参(参数不会显示在url上,但刷新页面参数会丢失):
Vue Router的2022-8-22 这次更新后,params 无法向之前 那样进行获取
之前的写法:

router.push({
    name: 'register', // 这里必须要用 name
    params: item
  })
// 接收
const route = useRoute()
const params = route.params

现在可以使用这几种方式:

  1. 将 params 存储在 pinia 或 vuex 仓储中
  2. 使用动态路由匹配
// 路由:
  {
     path:'/register/:id/:name/:price',
     name: 'register',
     component: () => import('../views/AboutView.vue')
  }
// 跳转:
  router.push({
    name: 'register',
    params: item // 这里的参数要与路由中定义的参数一一对应
  })
  1. 使用 History API
// 跳转:
 router.push({
   name: 'register',
   state: item
 })
// 接收:
 const historyParams = history.state

6. 嵌套路由和命名视图

如果想做一个菜单栏,点击不同菜单,显示不同的内容,我们可以使用嵌套路由,将菜单作为父路由,内容区作为子路由。如果路由对应多个组件,可以使用命名视图,通过多个不同 name 属性的 routerview,来渲染对应的组件。
修改路由,index.ts:

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/user',
      name: 'user',
      component: () => import('../views/RootView.vue'),
      // 使用 children 属性,为父路由添加子路由
      children: [
        {
          path: 'user1',
          name: 'user1',
          // 注意这里是 components,如果不是对象,写 component
          components: {
          	// default 对应下方视图 <RouterView></RouterView>
            default: () => import('../components/A.vue')
          }
        },
        {
          path: 'user2',
          name: 'user2',
          // 多个组件要写 components
          components: {
          	// viewB 对应 <RouterView name="viewB"></RouterView>
            viewB: () => import('../components/B.vue'),
            // viewC 对应 <RouterView name="viewC"></RouterView>
            viewC: () => import('../components/C.vue')
          }
        },
      ]
    }
  ]
})

父组件,RootView.vue:

<div>
    <h1>这是ROOT</h1>
    <RouterLink to="/user/user1">user1</RouterLink>&nbsp;
    <RouterLink to="/user/user2">user2</RouterLink>&nbsp;
    <RouterView></RouterView>
    // name 属性 指定渲染哪一个组件
    <RouterView name="viewB"></RouterView>
    <RouterView name="viewC"></RouterView>
</div>

7. 路由重定向 redirect 与 路由别名 alias

如果两个路由访问的页面是相同的,我们可以使用路由重定向:
例如 根路由 ‘/’ 自动跳转到登录页 ‘/login’ :

{
  path: '/',
  // 字符串形式
  redirect: '/login'
},

redirect 属性有三种写法,上述是 字符串形式。还有对象和回调函数形式。
对象形式:

{
  path: '/',
  // 字符串形式
  redirect: {
    name: 'login'
  }
},

回调函数形式:

{
  path: '/',
  // 字符串形式
  redirect: to => {
    console.log('to', to);
    return {
      name: 'login',
      query: {
        id: 1
      }
    }
  }
},

回调函数有个参数,这个参数包含路由相关的一些信息,比如 path、query、params、hash 等。
通过 alias 属性,我们可以给路由起一个别名,通过访问别名也可以访问相同页面:

{
  path: '/',
  alias: ['/main', '/main2'],
  component: () => import('../views/HomeView.vue')
},

别名可以起一个,也可以起多个,一个的话 alias 类型为字符串,多个就用 数组。

8. 导航守卫

全局前置守卫

如果希望用户未登录的时候,访问其他页面时,自动跳转到登录页,还有开启进度条,我们可以给路由添加一个前置守卫:

	const whiteList = ['/', '/login'] // 白名单 免登录
	router.beforeEach((to, from, next) => {
	  // 开启进度条
	  NProgress.start()
	  console.log(to.path);
	  if(whiteList.includes(to.path) || localStorage.getItem('token')){
	    next()
	  } else {
	    next('/')
	  }
	})

其中 to 表示 去哪里,from 表示从 哪里来,next 表示下一次去哪里,其中 next() 必须被调用。

全局后置守卫

一般在全局后置守卫中,我们可以做一些操作,比如关闭进度条:

// 路由后置守卫
router.afterEach((to, from) => {
  setTimeout(()=>{
    console.log(to, from);
    // 关闭进度条
    NProgress.done()
  }, 1000)
})

后置守卫只有两个参数,其中 to 和 from 与前置守卫相同。

9. 路由元信息

路由元信息就是路由规则 route 中的 meta 对象,我们可以在 meta 中添加一些信息,比如标题 title,动画效果 transition,操作权限 等等,等到我们跳转到这个页面时,获取到路由的元信息,来对页面进行一些修改。下面举个例子:
为路由添加 title 和 transition,router/index.ts:

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import NProgress from 'nprogress'
import '@/assets/nprogress.less'
NProgress.configure({ showSpinner: true })

// 定义 元信息 的类型
declare module 'vue-router' {
  interface RouteMeta{
    title: string
    transition: string
  }
}

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/login',
      name: 'login',
      component: () => import('../views/HomeView.vue'),
      meta: {
        title: '登录',
        transition: 'animate__fadeInLeft'
      }
    },
    {
      path: '/register',
      name: 'register',
      component: () => import('../views/AboutView.vue'),
      meta: {
        title: '注册',
        transition: 'animate__fadeInDown'
      }
    }
  ]
})

// 路由前置守卫
const whiteList = ['/', '/login', '/register'] // 白名单
router.beforeEach((to, from, next) => {
  // 开启进度条
  NProgress.start()
  if(whiteList.includes(to.path) || localStorage.getItem('token')){
  	// 获取 元信息中的 title ,修改页面标题
    document.title = to.meta.title
    next()
  } else {
    document.title = from.meta.title
    next('/')
  }
})

// 路由后置守卫
router.afterEach((to, from) => {
  setTimeout(()=>{
    // 关闭进度条
    NProgress.done()
  }, 1000)
})

export default router

app.vue:

<template>
  <div>
    <h1>demo</h1>
    <!-- 路由导航 -->
    <RouterLink replace to="/">login</RouterLink>&nbsp;
    <RouterLink replace to="/register">register</RouterLink>&nbsp;
    <RouterView #default="{route, Component}">
      <!-- router-view 默认有一个slot,传递两个参数 route 和 Component -->
      <transition :enter-active-class="`animate__animated ${route.meta.transition}`">
      	<!-- 注意添加动画的组件只能有一个根元素 -->
        <component :is="Component"></component>
      </transition>
    </RouterView>       
  </div>
</template>

<script setup lang='ts'>
import 'animate.css'
</script>

上面的栗子中,我们通过获取路由中的元信息,修改页面标题,并为路由组件添加不同的动画效果。

10. 滚动行为

平时我们会发现这种情况,读一篇文章,读到一半后切换到另一个页面,然后再切换回来时,页面会自动滚动到之前看到的位置。这种情况我们可以使用路由的滚动行为 scrollBehavior 来实现:

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  // 滚动行为
  scrollBehavior: (to, from, savePosition) => {
    console.log(savePosition); // {top: 0, left: 0}
    if(savePosition){
      return savePosition
    } else {
      return {top: 0}
    }
  },
  routes: [
    {
      path: '/login',
      name: 'login',
      component: () => import('../views/HomeView.vue')
    },
    {
      path: '/register',
      name: 'register',
      component: () => import('../views/AboutView.vue')
    }
  ]
})

scrollBehavior 是一个函数,这个函数有三个参数: to, from , savePosition。其中 to,from 和路由守卫中的相同,savePosition 是一个对象,记录了路由组件滚动的位置,{top: 0, left: 0},top 表示距离页面顶部的位置,left 表示距离页面左侧的位置。如果页面没有滚动区域,则 savePosition 的值为 null。这个函数需要返回一个对象,router会根据这个对象,滚动到相应的位置。
scrollBehavior 支持异步:

scrollBehavior: (to, from, savePosition) => {
    // 异步
    return new Promise((r) => {
      setTimeout(()=>{
        r({
          top: 100
        })
      }, 2000)
    })
  }

11. 动态路由

一般情况下,我们会根据后端返回的菜单列表,动态的渲染路由,实现原理就是使用 router.addRoute() 和 router.removeRoute() ,向路由表中添加或删除路由匹配规则,实现不同的用户看到的菜单是不同的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值