【Vue3.x】整合Router

106 阅读4分钟

1. Install

Official Website: router.vuejs.org/zh/guide/

不用单独装,创建项目的时候已经安装了

npm install vue-router@4

main.ts

import './assets/main.css'

import { createApp } from 'vue'
import { createPinia, storeToRefs } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate';
import ElementPlus from 'element-plus';
import 'element-plus/theme-chalk/index.css';
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import './assets/iconfont/iconfont.css'

import App from './App.vue'
import router from './router/index'
import i18n from './i18n';

const app = createApp(App)

const pinia = createPinia()
pinia.use(
   createPersistedState({
      auto: true
   })
)
app.use(pinia)
   .use(router)
   .use(ElementPlus)
   .use(i18n)

for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
   app.component(key, component)
   }
app.mount('#app')

2. Technology

Vue3.x + Vite + Pinia + Router + ElementPlux +I18n + axios + TypeScript

perl
复制代码
  "dependencies": {
    "@element-plus/icons-vue": "^2.3.1",
    "axios": "^1.7.0",
    "element-plus": "^2.7.3",
    "moment": "^2.24.0",
    "pinia": "^2.1.7",
    "pinia-plugin-persist": "^1.0.0",
    "pinia-plugin-persistedstate": "^3.2.1",
    "vue": "^3.4.21",
    "vue-i18n": "^9.5.0",
    "vue-router": "^4.3.0"
  },

3. Constructure

vue-demo
├── public/          # static files
│   └── favicon.ico  # title icon (可以多個,切換路由titile也切換) 
├── src/             # project root
│   ├── assets/      # images, icons, etc.靜態資源
│   ├── components/  # common components - 客製化頁面
│   ├── layouts/     # layout containers -header, footer,sidebar, etc.
│   ├── scss/        # scss styles
│   ├── config/      # 封裝http
│   ├── i18n/        # 多語言切換
│   │   ├── locales/        # 多語言切換
│   │   │   ├── en.ts       # 中文
│   │   │   ├── zh.ts       # 英文
│   │   │   └── xxx.ts      # 其他文
│   │   └── index.ts        # I18N切換
│   ├── router/           # routes config
│   │   └── index.ts      # I18N切換
│   ├── stores/           # pinia templage
│   │   └── user.ts       # pinia user
│   ├── views/pages       # Route apge,路由導航的頁面
│   │   ├── dashboard     # 儀錶盤頁面
│   │   ├── login         # 登錄頁面、註冊頁面
│   │   └── ....          # etc..
│   ├── App.vue      # 三個標籤 template /script  /style
│   └── main.ts      # 加載所有組件,掛載都index.html
│
├── .env.devlopment  # 多環境配置,在package.json啟動腳本中設定讀取
├── .env.production  # 多環境配置,在package.json啟動腳本中設定讀取
├── env.d.ts         # vue識別所有格式的文件
├── index.html       # 入口文件,main.ts
├── package.json     # dependency
└── vite.config.ts   # project config,install plugin,proxy

4. Setting

4.1 index.ts

/src/router/index.ts 这是入门级

import { createMemoryHistory, createRouter } from 'vue-router'

import HomeView from './HomeView.vue' 
import AboutView from './AboutView.vue' 

const routes = [ 
        {
            path: '/login',
            name: "login",
            component: Login,
            meta: {
                title: 'Login',  
            }
        },
        {
            path: '/',
            component: Layout,
            name: 'layout',
            children: [
                {
                    path: '/dashboard',
                    name: "dashboard",
                    component: Dashboard,
                    meta: {
                        title: 'Dashboard',  
                    }
                },
                {   

                    path: '/order',
                    component: Order,
                    name: 'order-manage',
                    meta: {
                        title: '订单管理',
                        icon: 'example'
                    },
                    children: [
                        {
                            path: '/order/list',
                            name: 'order-list',
                            component: OrderList,
                            meta: {
                              title: '订单列表',
                              icon: 'table'
                            }
                        },
                        {
                            path: '/order/product',
                            name: 'product-manage',
                            component: ProductManage,
                            meta: {
                              title: '生产管理',
                              icon: 'user'
                            },
                            children: [
                                {
                                    path: '/order/product/list',
                                    name: 'product-list',
                                    component: ProductionList,
                                    meta: {
                                      title: '生产列表',
                                        icon: 'table'
                                    }
                                },
                                {
                                    path: '/order/product/review',
                                    name: 'review-manage',
                                    component: ReviewManage,
                                    meta: {
                                      title: '审核管理',
                                        icon: 'eye'
                                    }
                                }
                            ]
                        },
                        {
                            path: '/order/returnGoods',
                            name: 'return-goods',
                            component: ReturnGoods,
                            meta: {
                              title: '退货管理',
                                icon: 'nested'
                            }
                        }
                    ]
                },
                {
                    path: '/goods',
                    component: Goods,
                    name: 'goods',
                    meta: {
                      title: '产品管理',
                        icon: 'user'
                    },
                    children: [
                        {
                            path: '/goods/list',
                            name: 'goods-list',
                            component: GoodsList,
                            meta: {
                              title: '产品列表',
                                icon: 'table'
                            }
                        },
                        {
                            path: '/goods/classify',
                            name: 'goods-classify',
                            component: GoodsClassify,
                            meta: {
                              title: '产品分类',
                                icon: 'tree'
                            }
                        }
                    ]
                },
                {
                    path: '/permission',
                    component: Permission,
                    name: 'permission',
                    meta: {
                      title: '权限管理',
                        icon: 'table'
                    },
                    children: [
                        {
                            path: '/permission/user',
                            name: 'user-manage',
                            component: UserManage,
                            meta: {
                              title: '用户管理',
                                icon: 'table'
                            }
                        },
                        {
                            path: '/permission/role',
                            name: 'role-manage',
                            component: RoleManage,
                            meta: {
                              title: '角色管理',
                                icon: 'eye'
                            }
                        },
                        {
                            path: '/permission/menu',
                            name: 'menu-manage',
                            component: MenuManage,
                            meta: {
                              title: '菜单管理',
                                icon: 'tree'
                            }
                        }
                    ]
                }
            ]
        },
        {
            path: '/403',
            name: 'Forbidden',
            component: Forbidden
        },
        {
            path: "/404",
            name: 'NoFound',
            component: NotFound
        }
    ]
] 
const router = createRouter({ 
    history: createMemoryHistory(), 
    routes, 
})
export default router;

4.2 request address

  • createWebHistory:地址干净
  • createWebHashHistory:地址携带#
import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router'
import { useUserStore } from '@/stores/user'
import HomeView from '../views/HomeView.vue'
import Dashboard from '../pages/dashboard/index.vue'


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

4.3 router parameters

params类似post方法,query类似get方法

1. 不带参数
<router-link :to="{name:'home'}"> 
<router-link :to="{path:'/home'}">

2.带参数
<router-link :to="{name:'home', params: {id:1}}"> 
<router-link :to="{name:'home', query: {id:1}}"> 

3.函数里面调用
    1. 不带参数
          this.$router.push('/home')
          this.$router.push({name:'home'})
          this.$router.push({path:'/home'})
    2. query传参
          this.$router.push({name:'home',query: {id:'1'}})
          this.$router.push({path:'/home',query: {id:'1'}})
    3. params传参
          this.$router.push({name:'home',params: {id:'1'}}) 

4.4 router props

image.png

4.4.1 xxxx**

<template>
    <ul>
        <li>编号:{{query.id}}</li>
        <li>标题:{{query.title}}</li>
        <li>内容:{{query.content}}</li>
    </ul>
</template>
<script setup lang="ts">
    import {toRefs} from 'vue'
    import {useRoute} from 'vue-router'
    
    const route = useRoute();
    let {query} = toRefs(route);
    
    onMounted(()=>{
        setTimeout(()=>{
            route.push('/order')
        },3000)
    })

</script>
<style>
</style>

4.4.2 自定义

<template>
    <div>
        <h2>接收路由参数</h2>
        <li>id号:{{id}} -- 价格:{{price}}</li>
    </div>
</template>
<script setup lang="ts">
    import {toRefs} from 'vue'
    import {useRoute} from 'vue-router'
    
    const route = useRoute();
    let {query} = toRefs(route);
    
    onMounted(()=>{
        setTimeout(()=>{
            route.push('/order')
        },3000)
    })

</script>
<style>
</style>

4.5 advance

1.跳转
    this.$router.push:跳转到指定 url 路径,并向 history 栈中添加一个记录,点击后退会返回到上一个页面 ==>> 队列的方式(先进先出)
2.跳转没记录 
    this.$router.replace:跳转到指定 url 路径,但是 history 栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面) ==>> 栈的方式(先进后出)
3.返回
    this.$router.back:请求(返回)上一个记录路由
4.连跳
    this.$router.go:向前或者向后跳转n个页面,n可为正整数或负整数

4.6 receive parameter

<template>
    <ul>
        <li>编号:{{query.id}}</li>
        <li>标题:{{query.title}}</li>
        <li>内容:{{query.content}}</li>
    </ul>
</template>
<script setup lang="ts">
    import {toRefs} from 'vue'
    import {useRoute} from 'vue-router'
    
    const route = useRoute();
    let {query} = toRefs(route.params);
    
    onMounted(()=>{
        setTimeout(()=>{
            router.push('/order')
        },3000)
    })

</script>
<style>
</style>

4.7 跳轉

<script setup lang="ts">
    import {toRefs} from 'vue'
    import {useRouter} from 'vue-router'
    
    const router = useRouter();
    
    onMounted(()=>{
        setTimeout(()=>{
            router.push('/order')
        },3000)
    })

</script>

4.8 Add Router

添加router

import { ref, onMounted, onUnmounted } from 'vue'
import router from './index'
import dynamicRouter from './dynamic-router'


export function addRouter() {

  const routes = dynamicRouter.options.routes;
  routes.forEach( (every) =>{
    router.addRoute("layout",every);
   })
}

5. 路由守卫

修改導航後的title和icon

image.png

//permission
router.beforeEach((to, from, next) => {

    console.log("Routerto :",to)
    const userStore = useUserStore();

    if (to.path === "/") {
        if(userStore.getAuthenticated){
            next();
        }else{
            next({ path: "/login",force:true});
        }
        
    }else if(to.path === "/login"){
        if(userStore.getAuthenticated){
            next({ path: "/",force:true});
        }else{
            next();
        }
    }else if(to.path === "/dashboard"){
        next();
    }else if(to.path === "/order"){
        next();
    }else if(to.path === "/order/list"){
        next();
    }else if(to.path === "/goods"){
        next();
    }else if(to.path === "/goods/list"){
        next();
    }else if(to.path === "/permission"){
        next();
    }else if(to.path === "/permission/user"){
        next();
    }else if(to.path === "/permission/role"){
        next();
    }else{
        next({ path: "/404",force:true});
    }

 })
 
 //modify title & icon
 router.afterEach((to, from, next) => {
    if(to.meta && to.meta.title){
        document.title = to.meta.title;
    }
 })

6. Breadcrumb

創建Breadcrumb.vue,這裡用到了I18n多語言切換{{ $t(item.name) }}

<template>
  <el-breadcrumb separator="/">
    <el-breadcrumb-item 
      v-for="item in breadcrumbs"
      :key="item"
      :to="item.path"
      :active="item.active"
      >{{ $t(item.name) }}</el-breadcrumb-item>
  </el-breadcrumb>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import router from '@/router'
import { ElMessage } from 'element-plus'

  const breadcrumbs = ref()

  const getBreadcrumbs = () => {
    console.log("router===:",router)
    return router.currentRoute.value.matched.map((route) => {
      return {
        active: route.path === router.currentRoute.value.fullPath,
        name: route.name,
        path: `${router.options.history.base}${route.path}`,
      }
    })
  }

  router.afterEach(() => {
    breadcrumbs.value = getBreadcrumbs()
    console.log("111111",breadcrumbs.value)
  })

  onMounted(() => {
    breadcrumbs.value = getBreadcrumbs()
  })

</script>
<style scoped>
.el-breadcrumb {
    font-size: 14px;
    line-height: 2;
}
*, *::before, *::after {
    font-weight: bold;
}
</style>