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
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
//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>