• Vue项目实战


    Vue项目实战

    1、项目介绍

    1.1、对象

    有Vue2、Vue3组合api基础知识,TypeScript基础知识
    
    • 1

    1.2、涉及技术

    CSS3
    TypeScript
    Vue3.2
    Vuex4.x
    Vue Router4.x
    Vite2.x
    Element-Plus
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.3、技能

    1. 掌握Vue3.2语法糖的使用
    2. 掌握Vue3中组合api的使用
    3. 掌握组件中业务逻辑抽离的方法
    4. 掌握TypeScript在Vue3中的使用
    5. 掌握动态菜单、动态路由、按钮权限的实现方式
    6. Vue3中全局挂载使用方式
    7. Vue3父子组件的使用
    8. Vue3中Echarts的使用
    9. token、权限验证
    10. Vuex4.x +Ts在commit、getter、dispatch中的代码提示
    11. Icons图标动态生成

    2、项目创建

    在这里插入图片描述

    2.1、init

    新建vue存放目录,cmd进入存放目录,执行命令创建项目

    npm init vite@latest
    or
    yarn crerate vite
    
    • 1
    • 2
    • 3

    2.2、启动项目

    √ Project name: ... vue3-ts
    √ Select a framework: » vue
    √ Select a variant: » vue-ts
    
    Scaffolding project in D:\bigdata-ws\vue\vue3-ts...
    
    Done. Now run:
    
      cd vue3-ts
      npm install
      npm run dev
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.3、访问项目

    http://localhost:3000/
    
    • 1

    2.4、解决Network

    解决:Network: use --host to expose

    vite.config.ts配置文件,添加如下配置:

    export default defineConfig({
      plugins: [vue()],
      server: {
        host: '0.0.0.0', //Network: use `--host` to expose
        port: 8080,
        open: true
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.5、vite配置别名

    参考官网:https://vitejs.cn/config/#resolve-alias

    types/node
    npm install @types/node --save-dev
    npm run build
    
    • 1
    • 2
    vite.config.ts配置文件
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import { resolve } from 'path'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [vue()],
      server: {
        host: '0.0.0.0', //Network: use `--host` to expose
        port: 8080,
        open: true
      },
      resolve:{
        alias: [
          { 
            find: '@', 
            replacement:resolve(__dirname,'src') }
        ]
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.6、安装插件

    • 安装Vue Language Features(Volar);禁用Vuter插件,否则会冲突
    • 安装Element UI Snippets
    • 安装open in browser

    2.7、安装路由(vue-router)

    npm install vue-router@4
    npm run build
    
    • 1
    • 2
    2.7.1、src下创建router目录,然后创建index.ts文件
    //vue2-router
    const router = new VueRouter({
    	mode: history,
    	...
    })
    
    //vue-router
    import { createRouter,createWebHistory} from 'vue-router'
    
    const router = createRouter({
    	history: createWebHistory(),
    	...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    2.7.2、index.tx
    import { createRouter,createWebHistory,RouteRecordRaw } from "vue-router";
    import Layout from '@/components/HelloWorld.vue'
    
    const routes:Array = [
    	{
    		path:'/',
    		name:'home',
    		component:Layout
    	}
    ]
    
    //创建
    const router = createRouter({
    	history:createWebHistory(),
    	routes
    })
    
    //暴露 router
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    2.7.3、main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router/index'
    
    createApp(App)
    .use(router)
    .mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.7.3、修改App.vue
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.8、安装Vuex

    2.8.1、官网
    https://vuex.vuejs.org/zh/
    
    • 1
    2.8.2、安装vuex
    npm install vuex@next --save
    or
    yarn add vuex@next --save
    
    • 1
    • 2
    • 3
    2.8.3、src下创建store目录,然后创建index.ts文件
    // store.ts
    import { InjectionKey } from 'vue'
    import { createStore, Store } from 'vuex'
    
    // 为 store state 声明类型
    export interface State {
      count: number
    }
    
    // 定义 injection key
    export const key: InjectionKey> = Symbol()
    
    export const store = createStore({
      state: {
        count: 0
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    2.8.4、main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router/index'
    import { store,key } from './store/index'
    
    createApp(App)
    .use(router)
    .use(store,key)
    .mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    2.8.5、index.tx
    // store.ts
    import { InjectionKey } from 'vue'
    import { createStore, useStore as baseUseStore, Store } from 'vuex'
    
    export interface State {
      count: number
    }
    
    export const key: InjectionKey> = Symbol()
    
    export const store = createStore({
      state: {
        count: 0
      },
    	mutations: {
    		setCount(state:State,count:number){
    			state.count = count;
    		}
    	},
    	getters: {
    		getCount(state:State){
    			return state.count;
    		}
    	}
    })
    
    // 定义自己的 `useStore` 组合式函数
    export function useStore () {
      return baseUseStore(key)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    2.8.6、HelloWorld.vue
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.9、eslint、css预处理器sass

    2.9.1、ts使用@符号引入
    tsconfig.json
    {
      "compilerOptions": {
        "target": "esnext",
        "useDefineForClassFields": true,
        "module": "esnext",
        "moduleResolution": "node",
        "strict": true,
        "jsx": "preserve",
        "sourceMap": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "esModuleInterop": true,
        "lib": ["esnext", "dom"],
        //解决打包报`vue-tsc --noEmit && vite build`的错误,忽略所有的声明文件(*.d.ts)的类型检查
        "skipLibCheck": true,
        "baseUrl": ".",
        "paths": {
          "@/*": [
            "src/*"
          ]
        }
      },
      "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
      //ts排除的文件
      "exclude": ["node_modules"],
      "references": [{ "path": "./tsconfig.node.json" }]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    修改HelloWorld.vue
    import { useStore } from '../store';
    修改为
    import { useStore } from '@/store';
    
    • 1
    • 2
    • 3
    验证
    npm run build
    npm run dev
    
    • 1
    • 2
    2.9.2、Eslint
    npm install --save-dev eslint-plugin-vue
    
    • 1
    2.9.3、新建.eslintrc.js文件

    注:src目录平级位置

    module.exports = {
    	root: true,
    	parserOptions: {
    		sourceType: 'module'
    	},
    	parser: 'vue-eslint-parser',
    	extends: ['plugin:vue/vue3-essential','plugin:vue/vue3-strongly-recomended','plugin:vue/vue3-recomended'],
    	env: {
    		browser: true,
    		node: true,
    		es6: true
    	},
    	rules: {
    		'no-console': 'off',
    		//禁止使用拖尾逗号
    		'comma-dangle': [2,'never']
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    2.9.4、添加css预处理器sass
    npm install -D sass sass-loader
    
    • 1

    2.10、element-plus

    2.10.1、官网
    https://element-plus.gitee.io/zh-CN/guide/installation.html
    
    • 1
    2.10.2、安装element-plus
    npm install element-plus --save
    
    • 1
    2.10.3、main.ts中引入

    https://element-plus.gitee.io/zh-CN/guide/quickstart.html

    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router/index'
    import { store,key } from '@/store/index'
    //引入element-plus
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    
    createApp(App)
    .use(router)
    .use(store,key)
    .use(ElementPlus)
    .mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    2.10.4、测试

    在HelloWorld.vue页面加入按钮

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、主界面布局

    3.1、插件安装

    禁用Vetur
    安装Vue Language Features(Volar)
    安装Element UI Snippets
    
    • 1
    • 2
    • 3

    3.2、前置知识

    1、setup语法糖中,组件的使用方式
    	setup语法糖中,引入的组件开源直接使用,无需再通过components进行注册,并且无法制定当前组件的名字,它会自动以文件名为主,不用再写name属性了。
    	setup语法糖中,定义的数据和方法,直接可以在模板中使用,无需return。
    
    2、ref使用
    	定义:const xxx = ref(sss)
    	作用:定义一个响应式的数据
    	js中操作,需要使用xxx.value
    	模板中使用不需要 .value
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.3、index.html添加样式,设置高度

    
    
      
        
        
        
        Vite App
      
      
        
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.4、新建layout目录

    3.4.1、Index.vue

    https://element-plus.gitee.io/zh-CN/component/container.html

    在src下创建layout目录,再创建Index.vue页面

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    3.4.2、修改路由

    在src下router目录,修改index.ts中的路由

    import { createRouter,createWebHistory,RouteRecordRaw } from "vue-router";
    // import Layout from '@/components/HelloWorld.vue'
    import Layout from '@/layout/index.vue'
    
    const routes:Array = [
    	{
    		path:'/',
    		name:'home',
    		component:Layout
    	}
    ]
    
    //创建
    const router = createRouter({
    	history:createWebHistory(),
    	routes
    })
    
    //暴露 router
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    3.4.3、Index.vue样式
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4、左侧导航菜单

    4.1、前置知识

    https://github.com/vuejs/rfcs/tree/master/active-rfcs
    https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
    
    • 1
    • 2
    4.1.1、抽离头部组件

    在layout目录下新建header目录,然后新建Header.vue组件

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.1.2、引入头部

    在layout目录下的Index.vue中引入Header.vue组件

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4.2、Menu菜单

    https://element-plus.gitee.io/zh-CN/component/menu.html#可折叠的菜单

    4.2.1、MenuBar.vue

    在layout目录先创建menu目录,新建MenuBar.vue

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    4.2.2、引入左侧导航栏

    在layout目录下的Index.vue页面引入左侧导航栏

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    4.2.3、抽离MenuItem.vue组件
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    setup语法糖父子组件传值的方法
    	父组件传值给子组件,通过属性绑定方式
    	子组件通过defineProps接收,无需显示的引入
    	插槽的使用
    reactive:响应式数据定义,适用于对象类型
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.3、导航菜单logo

    4.3.1、解决::v-deep警告
    [@vue/compiler-sfc] ::v-deep usage as a combinator has been deprecated. Use :deep() instead.
    
    • 1
    MenuBar.vue
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    4.3.2、MenuLogo.vue

    新建src/layout/menu/MenuLogo.vue

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    4.3.3、MenuBar.vue

    在src/layout/menu/MenuBar.vue中引入MenuLogo.vue

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194

    4.4、Element Plus图标

    4.4.1、vue3 setup语法糖
    https://v3.cn.vuejs.org/api/sfc-script-setup.html
    https://github.com/vuejs/rfcs/tree/master/active-rfcs
    
    • 1
    • 2
    4.4.2、前置知识
    • element plus图标使用

      https://element-plus.gitee.io/zh-CN/component/icon.html

    4.4.3、Element Plus图标基本使用
    安装
    npm install @element-plus/icons
    
    • 1
    引入图标
    import { Fold } from '@element-plus/icons'
    
    • 1
    使用方式
    
    
    • 1
    Header.vue
    //局部引用图标
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    4.4.4、Element Plus动态生成菜单图标
    图标注册为全局组件

    https://v3.cn.vuejs.org/api/sfc-script-setup.html#使用组件

    在main.ts把图标注册为全局组件

    方式一
    main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router/index'
    import { store,key } from '@/store/index'
    //引入element-plus
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    //统一导入element-icon图标
    import * as  Icons from '@element-plus/icons'
    
    const app = createApp(App);
    
    app.use(router)
    .use(store,key)
    .use(ElementPlus)
    .mount('#app')
    
    //全局注册组件
    //方式一
    //typeof获取一个对象的类型
    //keyof获取某种类型的所有键
    Object.keys(Icons).forEach(
    	(key)=>{
    		console.log(key)
    		// app.component(key,Icons[key])
    		app.component(key,Icons[key as keyof typeof Icons])
    	}
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    MenuBar.vue
    	{
    		path: '/dashboard',
    		component: "Layout",
    		meta: {
    			title: "首页",
    			icon: "HomeFilled",
    			roles: ["sys:manage"]
    		},
    		children: []
    	},
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    MenuItem.vue
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    方式二
    main.ts
    import { createApp,createVNode } from 'vue'
    import App from './App.vue'
    import router from './router/index'
    import { store,key } from '@/store/index'
    //引入element-plus
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    //统一导入element-icon图标
    import * as  Icons from '@element-plus/icons'
    
    const app = createApp(App);
    
    app.use(router)
    .use(store,key)
    .use(ElementPlus)
    .mount('#app')
    
    //全局注册组件
    //方式二
    const Icon = (props: {icon: string})=>{
    	const { icon } = props
    	return createVNode(Icons[icon as keyof typeof Icons]);
    };
    app.component('Icon',Icon);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    MenuItem.vue
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    解决type ‘string’ can’t be used to index type ‘typeof’ 字符串不能做下标的错,在tsconfig.json的compilerOptions中添加如下配置

    方式一

    "suppressExcessPropertyErrors": true,	//解决用字符串做下标报错
    
    • 1

    方式二

    key as keyof typeof Icons
    
    • 1

    5、路由配置与页面创建

    5.1、前置

    5.1.1、vue3 setup语法糖文档
    https://v3.cn.vuejs.org/api/sfc-script-setup.html
    https://github.com/vuejs/rfcs/tree/master/active-rfcs
    https://router.vuejs.org/zh/installation.html
    
    • 1
    • 2
    • 3
    5.1.2、代码模板配置
    • 首先在vscode编辑器中打开,[文件]->[首选项]->[用户片段]->[新代码片段]->取名vue.json->回车

    • 把下面代码粘进去,其中prefix里面的内容就是快捷键

      {
        "Print to console": {
          "prefix": "vue",
          "body": [
            "",
            "",
            "",
            ""
          ],
          "description": "Log output to console"
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 新建.vue结尾文件,代码区域输入 vue 回车,即可生成定义的模板代码

    5.1.3、功能分析

    点击左侧菜单,能够在内容展示区展示对应页面

    5.1.4、前置知识
    在setup里面没有访问this,所以不能再直接访问this.$router或this.$route;使用useRouter和useRoute替代;
    const router = useRouter() ---> this.$router
    const route = useRoute() ---> this.$route
    
    • 1
    • 2
    • 3

    5.2、添加路由

    5.2.1、index.ts

    在router/index.ts添加路由

    import { createRouter,createWebHistory,RouteRecordRaw } from "vue-router";
    // import Layout from '@/components/HelloWorld.vue'
    import Layout from '@/layout/index.vue'
    
    const routes:Array = [
    	{
    		path:'/',
    		name:'home',
    		component:Layout,
    		redirect: '/dashboard',
    		children: [
    			{
    				path: '/dashboard',
    				component: ()=>import('@/layout/dashboard/Index.vue'),
    				name: 'dashboard',
    				meta: {
    					title: '首页',
    					icon: 'HomeFilled'
    				},
    			},
    		],
    	},
    	{
    		path:'/system',
    		name:'system',
    		component:Layout,
    		meta: {
    			title: "系统管理",
    			icon: "Menu",
    			roles: ["sys:manage"],
    			parentId: 0,
    		},
    		children: [
    			{
    				path: "/department",
    				component: ()=>import('@/views/system/department/department.vue'),
    				name: 'department',
    				meta: {
    					title: "机构管理",
    					icon: "Document",
    					roles: ["sys:dept"]
    				}
    			},
    			{
    				path: "/userList",
    				component: ()=>import('@/views/system/user/UserList.vue'),
    				name: "userList",
    				meta: {
    					title: "用户管理",
    					icon: "Avatar",
    					roles: ["sys:user"]
    				},
    			},
    			{
    				path: "/roleList",
    				component:()=>import('@/views/system/role/RoleList.vue'),
    				name: "roleList",
    				meta: {
    					title: "角色管理",
    					icon: "Tools",
    					roles: ["sys:role"]
    				},
    			},
    			{
    				path: "/menuList",
    				component: ()=>import('@/views/system/menu/MenuList.vue'),
    				name: "menuList",
    				meta: {
    					title: "权限管理",
    					icon: "Document",
    					roles: ["sys:menu"]
    				},
    			},
    		]
    	},
    	{
    		path: "/goods",
    		component: Layout,
    		name: "goods",
    		meta: {
    			title: "商品管理",
    			icon: "Shop",
    			roles: ["sys:goods"]
    		},
    		children: [
    			{
    				path: "/goodsCategory",
    				component: ()=>import('@/views/goods/goodscategory/goodsCategoryList.vue'),
    				name: "goodsCategory",
    				meta: {
    					title: "商品分类",
    					icon: "Sell",
    					roles: ["sys:goodsCategory"]
    				}
    			}
    		]
    	},
    	{
    		path: "/systemConfig",
    		component: Layout,
    		name: "systemConfig",
    		meta: {
    			title: "系统工具",
    			icon: "Setting",
    			roles: ["sys:systemConfig"]
    		},
    		children: [
    			{
    				path: "/document",
    				component: ()=>import('@/views/system/config/systemDocument.vue'),
    				name: "https://42.193.158.170:8089/swagger-ui/index.html",
    				meta: {
    					title: "接口文档",
    					icon: "Document",
    					roles: ["sys:document"]
    				},
    			},
    		],
    	},
    
    ]
    
    
    //创建
    const router = createRouter({
    	history:createWebHistory(),
    	routes
    })
    
    //暴露 router
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    5.2.2、新建相关模块
    dashboard
    Index.vue

    src/layout/dashboard/Index.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    views
    goods

    src/views/goods/goodscategory/goodsCategoryList.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    system

    src/views/system/config/systemDoument.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    src/views/system/department/department.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    src/views/system/menu/MenuList.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    src/views/system/role/RoleList.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    src/views/system/user/UserList.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    router-view

    src/layout/Index.vue

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    Menu属性

    https://element-plus.gitee.io/zh-CN/component/menu.html#menu-属性
    src/layout/menu/MenBar.vue
    router 是否启用 vue-router 模式。 启用该模式会在激活导航时以 index 作为 path 进行路由跳转

    
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    src/layout/menu/MenBar.vue
    default-active 默认激活菜单的 index

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    6.2.3、index.ts

    https://element-plus.gitee.io/zh-CN/component/menu.html#menu-属性

    在src/store/index.ts

    // store.ts
    import { InjectionKey } from 'vue'
    import { createStore, useStore as baseUseStore, Store } from 'vuex'
    
    export interface State {
      count: number,
    	//collapse	是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)	boolean
    	collapse:boolean
    }
    
    export const key: InjectionKey> = Symbol()
    
    export const store = createStore({
      state: {
        count: 0,
    		collapse: false
      },
    	mutations: {
    		setCount(state:State,count:number){
    			state.count = count;
    		},
    		//设置collapse
    		setCollapse:(state: State,collapse: boolean)=>{
    			state.collapse = collapse;
    		}
    	},
    	getters: {
    		getCount(state:State){
    			return state.count;
    		},
    		//获取collapse
    		getCollapse:(state:State)=>{
    			return state.collapse;
    		}
    	}
    })
    
    // 定义自己的 `useStore` 组合式函数
    export function useStore () {
      return baseUseStore(key)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    6.2.4、Header.vue

    在src/layout/header/Header.vue中引入Collapse组件

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    6.2.5、MenuBar.vue

    在src/layout/menu/MenuBar.vue中,控制菜单展开和关闭

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212

    7、面包屑导航

    7.1、前置知识

    7.2、MenuLogo.vue添加动画

    7.2.1、animation

    在src/layout/menu/MenuBar.vue中添加动画样式

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    7.2.2、layout-logo

    在src/layout/menu/MenuBar.vue中的MenuLogo添加class

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.3、BredCum.vue

    在src/layout/header/下新建BredCum.vue组件
    https://element-plus.gitee.io/zh-CN/component/breadcrumb.html

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    7.3.1、Header.vue使用面包屑

    在src/layout/header/Header.vue中使用面包屑

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    7.3.2、Collapse.vue添加样式
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    7.3.3、获取面包屑导航数据

    在src/layout/header/BredCum.vue中

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    8、tabs选项卡

    8.1、前置知识

    1. vuex在组合API中的使用

      const store = useStore();
      
      • 1
    2. vue-router在组合API中的使用

      const route = useRoute();
      const router = useRouter();
      
      • 1
      • 2
    3. 响应式数据的定义;ref、reactive

    4. watch、computed的使用

    5. element plus组件Tabs标签的使用

    6. TypeScript中接口interface的使用,接口是一种规范

    8.2、功能分析

    1. 点击左侧菜单,右侧内容展示区显示对应的选项卡
    2. 点击右侧选项卡,左侧对应菜单也要相应的选中
    3. 解决刷新后,Tabs数据丢失的问题,window,addEventListener(“befor eunload”)

    8.3、Tabs.vue

    在src/layout/tabs目录下,新建Tabs.vue组件

    https://element-plus.gitee.io/zh-CN/component/tag.html

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155

    8.4、Tabs选项卡制作总结

    8.4.1、实现原理
    点击菜单,显示对应的选项卡
    	watch监听路由path的变化,把当前路由的title和path放到Tabls选项卡对用的数据里面
    选项卡的激活设置
    	把当前激活的选项卡v-mode绑定项为当前路由的path
    点击选项卡,左侧对应菜单激活
    	点击选项卡,跳转到对应的路由;只需要把选项卡的v-mode绑定项设为当前路由的path,左侧菜单便可自动激活
    关闭选项卡
    	首页不能关闭,关闭时,删除当前选项卡,重新设置vuex里面的选项卡数据;并跳转到新的路由;
    刷新浏览器时,选项卡数据丢失
    	window.addEventListener('beforeunload')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    8.4.2、TypeScript知识
    interface和type的基本使用
    typeof和keyof的使用
    反型、泛型约束的使用
    TppeScript模板字符串的基本使用
    TypeScript中文交叉类型、联合类型的基本使用
    Omit、Pick、Parameters、ReturnType的基本使用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    长度最小的子数组(滑动窗口)
    mysql集群使用nginx配置负载均衡
    无线互动会议室方案的视频显示系统
    《PNAS》和《Nature Communications》仿章鱼和蜗牛的粘液真空吸附,赋予了机器人吸盘新的“超能力”
    伦敦银走势图分析的新方法
    Huffman编码的Python与Matlab实现(附讲解)及编码效率与信源概率分布之间的关系
    PCA推导以及iris实例
    基于STM32的无线传感器网络(WSN)通信方案设计与实现
    STM32单片机的知识点总结
    深度学习之基于YoloV5安检仪危险品识别系统
  • 原文地址:https://blog.csdn.net/docsz/article/details/127862228