安装

npm install vue-router@next

设置路由

import { createRouter, createWebHistory } from "vue-router";

// 引入
import Home from "@/views/Home.vue";
import About from "@/views/About.vue";

// 路由信息
let routes = [
  {
    path: "/",
    name: 'home',
    component: Home,
  },
  {
    path: "/about",
    name: 'about',
    component: About,
  },
];

// 路由器
const router = createRouter({
  history: createWebHistory(), // HTML5模式
  routes,
});

export default router;

引入路由

import { createApp } from 'vue'
  import App from './App.vue'

  // 引入插件
  import router from "@/store/index";
  // 安装router插件
  createApp(App).use(router).mount('#app')

挂载路由

在App.vue中

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

路由跳转

嵌套路由

在项目中,想要嵌套路由,要配置children属性

// 文件目录结构
src
————views
————————Home
————————————components
————————————————HomeAside.vue
————————————————HomeHeader.vue
————————————————HomeMain.vue
————————————Home.vue
————App.vue  

例如,在App.vue中

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

<template>
  <RouterView/>
</template>

<style lang="scss">
  @import '@/styles/reset.scss';
  @import '@/styles/common.scss';
  @import '@/styles/iconfont.scss';
</style>

而在子路由中HomeMain组件中

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

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

<style lang="scss" scoped>

</style>

在router.js下的配置

import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'

// 主页面
import Home from '@/views/Home/Home.vue'
// 登录注册
import Login from '@/views/Login/Login.vue'
import Register from '@/views/Register/Register.vue'
// 信息维护
import Charts from '@/views/Charts/Charts.vue'
import Information from '@/views/Information/Information.vue'
import Performance from '@/views/Performance/Performance.vue'
import TagManage from '@/views/TagManage/TagManage.vue'
import AccountManage from '@/views/AccountManage/AccountManage.vue'

declare module 'vue-router' {
  interface RouteMeta {
    auth?: boolean;
    menu?: boolean;
    title?: string;
    icon?: string;
  }
}

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    redirect: '/maintenance',
    meta: {
      auth: true,
      menu: true,
      title: '信息维护',
      icon: '#icon-yonghuweihu'
    },
    children: [
      {
        path: '/maintenance',
        name: 'Maintenance',
        redirect: '/charts',
        meta: {
          auth: true,
          menu: true,
          title: '信息维护',
          icon: '#icon-yonghuweihu'
        },
        children:[
          {
            path: '/charts',
            name: 'Charts',
            component: Charts,
            meta: {
              auth: true,
              menu: true,
              title: '数据展示',
              icon:  '#icon-a-007_shujufenxi'             
            }
          },
          {
            path: '/information',
            name: 'Information',
            component: Information,
            meta: {
              auth: true,
              menu: true,
              title: '员工信息',
              icon: '#icon-yuangongguanli'
            }
          },
          {
            path: '/performance',
            name: 'Performance',
            component: Performance,
            meta: {
              auth: true,
              menu: true,
              title: '绩效成绩',
              icon: '#icon-jixiaopinggu'
            }
          },
          {
            path: '/tagManage',
            name: 'TagManage',
            component: TagManage,
            meta: {
              auth: true,
              menu: true,
              title: '标签管理',
              icon: '#icon-biaoqian'
            }
          },
          {
              path: '/accountManage',
              name: 'AccountManage',
              component: AccountManage,
              meta: {
                auth: true,
                menu: true,
                title: '账号管理',
                icon: '#icon-zhanghaoguanli1'
              }
          },
          {    
              path: '/employeePortrait',
              name: 'EmployeePortrait',
              component: EmployeePortrait,
              meta: {
                  auth: true,
                  menu: true,
                  title: '员工画像',
                  icon: '#icon-yonghuhuaxiang1'
              }
          }
        ]
      }
    ]
  },
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/register',
    name: 'register',
    component: Register
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

路由传参

query传参
<template>
  <div class="container">
    <!-- 传参 -->
    <router-link v-for="product in arrs" class="item" :key="blog.id" :to="{ name: 'productdetail', query: { id: product.id } }">
    </router-link>
  </div>
</template>

设置query: { id: product.id } }给路由传参

接收query传参
<template>
  <div class="container">
    <h2>{{ product.name }}</h2>
    <p>{{ product.description }}</p>
  </div>
</template>

<script>
  import sourceData from "@/data.json";
  import { useRoute } from "vue-router";
  export default {
    setup(props) {
      // 获取路由
      let route = useRoute();
      // 获取query参数
      let productId = route.query.id;

      return {
        blog: sourceData.find((product) => product.id == productId),
      };
    },
  };
</script>

通过route.query.id就能获取到传递的商品id, 然后就能显示对应的商品详细信息了。

动态路由

在碰到入商品页这种,大多商品页面逻辑都相同的,我们可以使用动态路由去实现

配置

<!-- router.js -->
let routes = [
  //...
  {
    <!-- 动态路由路径 -->
    path: '/productdetail/:id',
    name: "productdetail",
    component: () => import("@/views/ProductDetail.vue")
  }
];

传参

<template>
  <div class="container">
    <!-- 传参 -->
    <router-link v-for="product in arrs" class="item" :key="product.id" :to="{ name: 'productdetail', params: { id: product.id } }">
    </router-link>
  </div>
</template>

通过设置params:{ id: blog.id} 给动态路由传参

接收参数

let productId = route.params.id;

通过route.params.id就能获取传递的商品id,就能显示对应的商品详情页信息

路由守卫

独享守卫

<!-- router.js -->
{
  path: 'sign',
  name: 'sign',
  component: Sign,
  meta: {
    menu: true,
    title: '在线打卡签到',
    icon: 'calendar',
    auth: true
  },
  async beforeEnter(to, from, next){
    const usersStore = useUsersStore()
    const signsStore = useSignsStore()
    const newsStore = useNewsStore()
    const { infos: usersInfos } = storeToRefs(usersStore)
    const { infos: signsInfos } = storeToRefs(signsStore)
    const { info: newsInfo } = storeToRefs(newsStore)
    if( _.isEmpty(signsInfos.value) ){
      const res = await signsStore.getTimeAction({ userid: usersInfos.value._id })
      if(res.data.errcode === 0){
        signsStore.updateInfos(res.data.infos)
      }
      else{
        return;
      }
    }
    if( _.isEmpty(newsInfo.value) ){
      const res = await newsStore.getRemindAction({ userid: usersInfos.value._id })
      if(res.data.errcode === 0){
        newsStore.updateInfo(res.data.info)
      }
      else{
        return;
      }
    }
    next()
  }
}

全局守卫

在某些路由中需要一些特定的操作,譬如访问前必须是登录用户。这时候可以通过使用meta属性和全局守卫来实现。

router.beforeEach((to, from, next)=>{
  const usersStore = useUsersStore()
  const { token, infos } = storeToRefs(usersStore)
  if( to.meta.auth && _.isEmpty(infos.value) ){
    if(token.value){
      usersStore.infosAction().then((res)=>{
        if(res.data.errcode === 0){
          usersStore.updateInfos(res.data.infos)
          if(res.data.infos.permission.includes(to.name)){
            next()
          }
          else{
            next('/403')
          }
        }
      })
    }
    else{
      next('/login');
    }
  }
  else{
    if( token.value && to.path === '/login' ){
      next('/');
    }
    else{
      next();
    }
  }
})

组件内的路由守卫

<script setup>
import { ref } from '@vue/reactivity';
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import sourceData from "@/data.json";

// 定义props
const props = defineProps({
  catId: {
    type: Number,
    required: true,
  }
})

let arrs = ref([]);

let fetchData = (id) => {
  return id !== 0 ? sourceData.filter((blog) => blog.catId == id) : sourceData;
}

<!-- 组件内的路由守卫 -->
onBeforeRouteUpdate((to, from, next) => {
  arrs.value = fetchData(to.params.catId)
});

arrs.value = fetchData(props.catId);

</script>

对于一个带有动态参数的路径 /category/:catId,在 /category/1 和 /category/2 之间跳转的时候, 会触发onBeforeRouteUpdate的路由钩子函数,在钩子函数中可以进行数据的更新。