硅谷甄選運營平臺
此次教學課程為硅谷甄選運營平臺項目,包含運營平臺項目模板從0到1開發,以及數據大屏幕、權限等業務。
此次教學課程涉及到技術棧包含***:vue3+TypeScript+vue-router+pinia+element-plus+axios+echarts***等技術棧。
一、vue3組件通信方式
通信倉庫地址:https://gitee.com/jch1011/vue3_communication.git
不管是vue2還是vue3,組件通信方式很重要,不管是項目還是面試都是經常用到的知識點。
比如:vue2組件通信方式
**props:**可以實現父子組件、子父組件、甚至兄弟組件通信
自定義事件:可以實現子父組件通信
全局事件總線$bus:可以實現任意組件通信
**pubsub:**發布訂閱模式實現任意組件通信
vuex:集中式狀態管理容器,實現任意組件通信
ref:父組件獲取子組件實例VC,獲取子組件的響應式數據以及方法
**slot:**插槽(默認插槽、具名插槽、作用域插槽)實現父子組件通信…
1.1props
props可以實現父子組件通信,在vue3中我們可以通過defineProps獲取父組件傳遞的數據。且在組件內部不需要引入defineProps方法可以直接使用!
父組件給子組件傳遞數據
<Child info="我愛祖國" :money="money"></Child>
子組件獲取父組件傳遞數據:方式1
let props = defineProps({info:{type:String,//接受的數據類型default:'默認參數',//接受默認數據},money:{type:Number,default:0
}})
子組件獲取父組件傳遞數據:方式2
let props = defineProps(["info",'money']);
子組件獲取到props數據就可以在模板中使用了,但是切記props是只讀的(只能讀取,不能修改)
1.2自定義事件
在vue框架中事件分為兩種:一種是原生的DOM事件,另外一種自定義事件。
原生DOM事件可以讓用戶與網頁進行交互,比如click、dbclick、change、mouseenter、mouseleave…
自定義事件可以實現子組件給父組件傳遞數據
1.2.1原生DOM事件
代碼如下:
<pre @click="handler">我是祖國的老花骨朵</pre>
當前代碼級給pre標簽綁定原生DOM事件點擊事件,默認會給事件回調注入event事件對象。當然點擊事件想注入多個參數可以按照下圖操作。但是切記注入的事件對象務必叫做$event.
<div @click="handler1(1,2,3,$event)">我要傳遞多個參數</div>
在vue3框架click、dbclick、change(這類原生DOM事件),不管是在標簽、自定義標簽上(組件標簽)都是原生DOM事件。
1.2.2自定義事件
自定義事件可以實現子組件給父組件傳遞數據.在項目中是比較常用的。
比如在父組件內部給子組件(Event2)綁定一個自定義事件
<Event2 @xxx="handler3"></Event2>
在Event2子組件內部觸發這個自定義事件
<template><div><h1>我是子組件2</h1><button @click="handler">點擊我觸發xxx自定義事件</button></div>
</template><script setup lang="ts">
let $emit = defineEmits(["xxx"]);
const handler = () => {$emit("xxx", "法拉利", "茅臺");
};
</script>
<style scoped>
</style>
我們會發現在script標簽內部,使用了defineEmits方法,此方法是vue3提供的方法,不需要引入直接使用。defineEmits方法執行,傳遞一個數組,數組元素即為將來組件需要觸發的自定義事件類型,此方執行會返回一個$emit方法用于觸發自定義事件。
當點擊按鈕的時候,事件回調內部調用$emit方法去觸發自定義事件,第一個參數為觸發事件類型,第二個、三個、N個參數即為傳遞給父組件的數據。
需要注意的是:代碼如下
<Event2 @xxx="handler3" @click="handler"></Event2>
正常說組件標簽書寫@click應該為原生DOM事件,但是如果子組件內部通過defineEmits定義就變為自定義事件了
let $emit = defineEmits(["xxx",'click']);
1.3全局事件總線
全局事件總線可以實現任意組件通信,在vue2中可以根據VM與VC關系推出全局事件總線。
但是在vue3中沒有Vue構造函數,也就沒有Vue.prototype.以及組合式API寫法沒有this,
那么在Vue3想實現全局事件的總線功能就有點不現實啦,如果想在Vue3中使用全局事件總線功能
可以使用插件mitt實現。
mitt:官網地址:https://www.npmjs.com/package/mitt
1.4v-model
v-model指令可是收集表單數據(數據雙向綁定),除此之外它也可以實現父子組件數據同步。
而v-model實指利用props[modelValue]與自定義事件[update:modelValue]實現的。
下方代碼:相當于給組件Child傳遞一個props(modelValue)與綁定一個自定義事件update:modelValue
實現父子組件數據同步
<Child v-model="msg"></Child>
在vue3中一個組件可以通過使用多個v-model,讓父子組件多個數據同步,下方代碼相當于給組件Child傳遞兩個props分別是pageNo與pageSize,以及綁定兩個自定義事件update:pageNo與update:pageSize實現父子數據同步
<Child v-model:pageNo="msg" v-model:pageSize="msg1"></Child>
1.5useAttrs
在Vue3中可以利用useAttrs方法獲取組件的屬性與事件(包含:原生DOM事件或者自定義事件),次函數功能類似于Vue2框架中 a t t r s 屬性與 attrs屬性與 attrs屬性與listeners方法。
比如:在父組件內部使用一個子組件my-button
<my-button type="success" size="small" title='標題' @click="handler"></my-button>
子組件內部可以通過useAttrs方法獲取組件屬性與事件.因此你也發現了,它類似于props,可以接受父組件傳遞過來的屬性與屬性值。需要注意如果defineProps接受了某一個屬性,useAttrs方法返回的對象身上就沒有相應屬性與屬性值。
<script setup lang="ts">
import {useAttrs} from 'vue';
let $attrs = useAttrs();
</script>
1.6ref與$parent
ref,提及到ref可能會想到它可以獲取元素的DOM或者獲取子組件實例的VC。既然可以在父組件內部通過ref獲取子組件實例VC,那么子組件內部的方法與響應式數據父組件可以使用的。
比如:在父組件掛載完畢獲取組件實例
父組件內部代碼:
<template><div><h1>ref與$parent</h1><Son ref="son"></Son></div>
</template>
<script setup lang="ts">
import Son from "./Son.vue";
import { onMounted, ref } from "vue";
const son = ref();
onMounted(() => {console.log(son.value);
});
</script>
但是需要注意,如果想讓父組件獲取子組件的數據或者方法需要通過defineExpose對外暴露,因為vue3中組件內部的數據對外“關閉的”,外部不能訪問
<script setup lang="ts">
import { ref } from "vue";
//數據
let money = ref(1000);
//方法
const handler = ()=>{
}
defineExpose({money,handler
})
</script>
$parent可以獲取某一個組件的父組件實例VC,因此可以使用父組件內部的數據與方法。必須子組件內部擁有一個按鈕點擊時候獲取父組件實例,當然父組件的數據與方法需要通過defineExpose方法對外暴露
<button @click="handler($parent)">點擊我獲取父組件實例</button>
1.7provide與inject
provide[提供]
inject[注入]
vue3提供兩個方法provide與inject,可以實現隔輩組件傳遞參數
組件組件提供數據:
provide方法用于提供數據,此方法執需要傳遞兩個參數,分別提供數據的key與提供數據value
<script setup lang="ts">
import {provide} from 'vue'
provide('token','admin_token');
</script>
后代組件可以通過inject方法獲取數據,通過key獲取存儲的數值
<script setup lang="ts">
import {inject} from 'vue'
let token = inject('token');
</script>
1.8pinia
pinia官網:https://pinia.web3doc.top/
pinia也是集中式管理狀態容器,類似于vuex。但是核心概念沒有mutation、modules,使用方式參照官網
1.9slot
插槽:默認插槽、具名插槽、作用域插槽可以實現父子組件通信.
默認插槽:
在子組件內部的模板中書寫slot全局組件標簽
<template><div><slot></slot></div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
在父組件內部提供結構:Todo即為子組件,在父組件內部使用的時候,在雙標簽內部書寫結構傳遞給子組件
注意開發項目的時候默認插槽一般只有一個
<Todo><h1>我是默認插槽填充的結構</h1>
</Todo>
具名插槽:
顧名思義,此插槽帶有名字在組件內部留多個指定名字的插槽。
下面是一個子組件內部,模板中留兩個插槽
<template><div><h1>todo</h1><slot name="a"></slot><slot name="b"></slot></div>
</template>
<script setup lang="ts">
</script><style scoped>
</style>
父組件內部向指定的具名插槽傳遞結構。需要注意v-slot:可以替換為#
<template><div><h1>slot</h1><Todo><template v-slot:a> //可以用#a替換<div>填入組件A部分的結構</div></template><template v-slot:b>//可以用#b替換<div>填入組件B部分的結構</div></template></Todo></div>
</template><script setup lang="ts">
import Todo from "./Todo.vue";
</script>
<style scoped>
</style>
作用域插槽
作用域插槽:可以理解為,子組件數據由父組件提供,但是子組件內部決定不了自身結構與外觀(樣式)
子組件Todo代碼如下:
<template><div><h1>todo</h1><ul><!--組件內部遍歷數組--><li v-for="(item,index) in todos" :key="item.id"><!--作用域插槽將數據回傳給父組件--><slot :$row="item" :$index="index"></slot></li></ul></div>
</template>
<script setup lang="ts">
defineProps(['todos']);//接受父組件傳遞過來的數據
</script>
<style scoped>
</style>
父組件內部代碼如下:
<template><div><h1>slot</h1><Todo :todos="todos"><template v-slot="{$row,$index}"><!--父組件決定子組件的結構與外觀--><span :style="{color:$row.done?'green':'red'}">{{$row.title}}</span></template></Todo></div>
</template><script setup lang="ts">
import Todo from "./Todo.vue";
import { ref } from "vue";
//父組件內部數據
let todos = ref([{ id: 1, title: "吃飯", done: true },{ id: 2, title: "睡覺", done: false },{ id: 3, title: "打豆豆", done: true },
]);
</script>
<style scoped>
</style>
二、搭建后臺管理系統模板
2.1項目初始化
今天來帶大家從0開始搭建一個vue3版本的后臺管理系統。一個項目要有統一的規范,需要使用eslint+stylelint+prettier來對我們的代碼質量做檢測和修復,需要使用husky來做commit攔截,需要使用commitlint來統一提交規范,需要使用preinstall來統一包管理工具。
下面我們就用這一套規范來初始化我們的項目,集成一個規范的模版。
2.1.1環境準備
- node v16.14.2
- pnpm 8.0.0
2.1.2初始化項目
本項目使用vite進行構建,vite官方中文文檔參考:cn.vitejs.dev/guide/
pnpm:performant npm ,意味“高性能的 npm”。pnpm由npm/yarn衍生而來,解決了npm/yarn內部潛在的bug,極大的優化了性能,擴展了使用場景。被譽為“最先進的包管理工具”
pnpm安裝指令
npm i -g pnpm@8.0.0
項目初始化命令:
pnpm create vite
進入到項目根目錄pnpm install安裝全部依賴.安裝完依賴運行程序:pnpm run dev
運行完畢項目跑在http://127.0.0.1:5173/,可以訪問你得項目啦
2.2項目配置
一、eslint配置
eslint中文官網:http://eslint.cn/
ESLint最初是由Nicholas C. Zakas 于2013年6月創建的開源項目。它的目標是提供一個插件化的javascript代碼檢測工具
首先安裝eslint
pnpm i eslint -D
生成配置文件:.eslint.cjs
npx eslint --init
.eslint.cjs配置文件
module.exports = {//運行環境"env": { "browser": true,//瀏覽器端"es2021": true,//es2021},//規則繼承"extends": [ //全部規則默認是關閉的,這個配置項開啟推薦規則,推薦規則參照文檔//比如:函數不能重名、對象不能出現重復key"eslint:recommended",//vue3語法規則"plugin:vue/vue3-essential",//ts語法規則"plugin:@typescript-eslint/recommended"],//要為特定類型的文件指定處理器"overrides": [],//指定解析器:解析器//Esprima 默認解析器//Babel-ESLint babel解析器//@typescript-eslint/parser ts解析器"parser": "@typescript-eslint/parser",//指定解析器選項"parserOptions": {"ecmaVersion": "latest",//校驗ECMA最新版本"sourceType": "module"//設置為"script"(默認),或者"module"代碼在ECMAScript模塊中},//ESLint支持使用第三方插件。在使用插件之前,您必須使用npm安裝它//該eslint-plugin-前綴可以從插件名稱被省略"plugins": ["vue","@typescript-eslint"],//eslint規則"rules": {}
}
1.1vue3環境代碼校驗插件
# 讓所有與prettier規則存在沖突的Eslint rules失效,并使用prettier進行代碼檢查
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
# 運行更漂亮的Eslint,使prettier規則優先級更高,Eslint優先級低
"eslint-plugin-prettier": "^4.2.1",
# vue.js的Eslint插件(查找vue語法錯誤,發現錯誤指令,查找違規風格指南
"eslint-plugin-vue": "^9.9.0",
# 該解析器允許使用Eslint校驗所有babel code
"@babel/eslint-parser": "^7.19.1",
安裝指令
pnpm install -D eslint-plugin-import eslint-plugin-vue eslint-plugin-node eslint-plugin-prettier eslint-config-prettier eslint-plugin-node @babel/eslint-parser
1.2修改.eslintrc.cjs配置文件
// @see https://eslint.bootcss.com/docs/rules/module.exports = {env: {browser: true,es2021: true,node: true,jest: true,},/* 指定如何解析語法 */parser: 'vue-eslint-parser',/** 優先級低于 parse 的語法解析配置 */parserOptions: {ecmaVersion: 'latest',sourceType: 'module',parser: '@typescript-eslint/parser',jsxPragma: 'React',ecmaFeatures: {jsx: true,},},/* 繼承已有的規則 */extends: ['eslint:recommended','plugin:vue/vue3-essential','plugin:@typescript-eslint/recommended','plugin:prettier/recommended',],plugins: ['vue', '@typescript-eslint'],/** "off" 或 0 ==> 關閉規則* "warn" 或 1 ==> 打開的規則作為警告(不影響代碼執行)* "error" 或 2 ==> 規則作為一個錯誤(代碼不能執行,界面報錯)*/rules: {// eslint(https://eslint.bootcss.com/docs/rules/)'no-var': 'error', // 要求使用 let 或 const 而不是 var'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允許多個空行'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off','no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off','no-unexpected-multiline': 'error', // 禁止空余的多行'no-useless-escape': 'off', // 禁止不必要的轉義字符// typeScript (https://typescript-eslint.io/rules)'@typescript-eslint/no-unused-vars': 'error', // 禁止定義未使用的變量'@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 類型'@typescript-eslint/no-non-null-assertion': 'off','@typescript-eslint/no-namespace': 'off', // 禁止使用自定義 TypeScript 模塊和命名空間。'@typescript-eslint/semi': 'off',// eslint-plugin-vue (https://eslint.vuejs.org/rules/)'vue/multi-word-component-names': 'off', // 要求組件名稱始終為 “-” 鏈接的單詞'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的變量<template>被標記為未使用'vue/no-mutating-props': 'off', // 不允許組件 prop的改變'vue/attribute-hyphenation': 'off', // 對模板中的自定義組件強制執行屬性命名樣式},
}
1.3.eslintignore忽略文件
dist
node_modules
1.4運行腳本
package.json新增兩個運行腳本
"scripts": {"lint": "eslint src","fix": "eslint src --fix",
}
二、配置prettier
有了eslint,為什么還要有prettier?eslint針對的是javascript,他是一個檢測工具,包含js語法以及少部分格式問題,在eslint看來,語法對了就能保證代碼正常運行,格式問題屬于其次;
而prettier屬于格式化工具,它看不慣格式不統一,所以它就把eslint沒干好的事接著干,另外,prettier支持
包含js在內的多種語言。
總結起來,eslint和prettier這倆兄弟一個保證js代碼質量,一個保證代碼美觀。
2.1安裝依賴包
pnpm install -D eslint-plugin-prettier prettier eslint-config-prettier
2.2.prettierrc.json添加規則
{"singleQuote": true,"semi": false,"bracketSpacing": true,"htmlWhitespaceSensitivity": "ignore","endOfLine": "auto","trailingComma": "all","tabWidth": 2
}
2.3.prettierignore忽略文件
/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*
通過pnpm run lint去檢測語法,如果出現不規范格式,通過pnpm run fix 修改
三、配置stylelint
stylelint為css的lint工具。可格式化css代碼,檢查css語法錯誤與不合理的寫法,指定css書寫順序等。
我們的項目中使用scss作為預處理器,安裝以下依賴:
pnpm add sass sass-loader stylelint postcss postcss-scss postcss-html stylelint-config-prettier stylelint-config-recess-order stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order stylelint-config-standard-scss -D
3.1.stylelintrc.cjs
配置文件
官網:https://stylelint.bootcss.com/
// @see https://stylelint.bootcss.com/module.exports = {extends: ['stylelint-config-standard', // 配置stylelint拓展插件'stylelint-config-html/vue', // 配置 vue 中 template 樣式格式化'stylelint-config-standard-scss', // 配置stylelint scss插件'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 樣式格式化'stylelint-config-recess-order', // 配置stylelint css屬性書寫順序插件,'stylelint-config-prettier', // 配置stylelint和prettier兼容],overrides: [{files: ['**/*.(scss|css|vue|html)'],customSyntax: 'postcss-scss',},{files: ['**/*.(html|vue)'],customSyntax: 'postcss-html',},],ignoreFiles: ['**/*.js','**/*.jsx','**/*.tsx','**/*.ts','**/*.json','**/*.md','**/*.yaml',],/*** null => 關閉該規則* always => 必須*/rules: {'value-keyword-case': null, // 在 css 中使用 v-bind,不報錯'no-descending-specificity': null, // 禁止在具有較高優先級的選擇器后出現被其覆蓋的較低優先級的選擇器'function-url-quotes': 'always', // 要求或禁止 URL 的引號 "always(必須加上引號)"|"never(沒有引號)"'no-empty-source': null, // 關閉禁止空源碼'selector-class-pattern': null, // 關閉強制選擇器類名的格式'property-no-unknown': null, // 禁止未知的屬性(true 為不允許)'block-opening-brace-space-before': 'always', //大括號之前必須有一個空格或不能有空白符'value-no-vendor-prefix': null, // 關閉 屬性值前綴 --webkit-box'property-no-vendor-prefix': null, // 關閉 屬性前綴 -webkit-mask'selector-pseudo-class-no-unknown': [// 不允許未知的選擇器true,{ignorePseudoClasses: ['global', 'v-deep', 'deep'], // 忽略屬性,修改element默認樣式的時候能使用到},],},
}
3.2.stylelintignore忽略文件
/node_modules/*
/dist/*
/html/*
/public/*
3.3運行腳本
"scripts": {"lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
}
最后配置統一的prettier來格式化我們的js和css,html代碼
"scripts": {"dev": "vite --open","build": "vue-tsc && vite build","preview": "vite preview","lint": "eslint src","fix": "eslint src --fix","format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\"","lint:eslint": "eslint src/**/*.{ts,vue} --cache --fix","lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"},
當我們運行pnpm run format
的時候,會把代碼直接格式化
四、配置husky
在上面我們已經集成好了我們代碼校驗工具,但是需要每次手動的去執行命令才會格式化我們的代碼。如果有人沒有格式化就提交了遠程倉庫中,那這個規范就沒什么用。所以我們需要強制讓開發人員按照代碼規范來提交。
要做到這件事情,就需要利用husky在代碼提交之前觸發git hook(git在客戶端的鉤子),然后執行pnpm run format
來自動的格式化我們的代碼。
安裝husky
pnpm install -D husky
執行
npx husky-init
會在根目錄下生成個一個.husky目錄,在這個目錄下面會有一個pre-commit文件,這個文件里面的命令在我們執行commit的時候就會執行
在.husky/pre-commit
文件添加如下命令:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm run format
當我們對代碼進行commit操作的時候,就會執行命令,對代碼進行格式化,然后再提交。
五、配置commitlint
對于我們的commit信息,也是有統一規范的,不能隨便寫,要讓每個人都按照統一的標準來執行,我們可以利用commitlint來實現。
安裝包
pnpm add @commitlint/config-conventional @commitlint/cli -D
添加配置文件,新建commitlint.config.cjs
(注意是cjs),然后添加下面的代碼:
module.exports = {extends: ['@commitlint/config-conventional'],// 校驗規則rules: {'type-enum': [2,'always',['feat','fix','docs','style','refactor','perf','test','chore','revert','build',],],'type-case': [0],'type-empty': [0],'scope-empty': [0],'scope-case': [0],'subject-full-stop': [0, 'never'],'subject-case': [0, 'never'],'header-max-length': [0, 'always', 72],},
}
在package.json
中配置scripts命令
# 在scrips中添加下面的代碼
{
"scripts": {"commitlint": "commitlint --config commitlint.config.cjs -e -V"},
}
配置結束,現在當我們填寫commit
信息的時候,前面就需要帶著下面的subject
'feat',//新特性、新功能
'fix',//修改bug
'docs',//文檔修改
'style',//代碼格式修改, 注意不是 css 修改
'refactor',//代碼重構
'perf',//優化相關,比如提升性能、體驗
'test',//測試用例修改
'chore',//其他修改, 比如改變構建流程、或者增加依賴庫、工具等
'revert',//回滾到上一個版本
'build',//編譯相關的修改,例如發布版本、對項目構建或者依賴的改動
配置husky
npx husky add .husky/commit-msg
在生成的commit-msg文件中添加下面的命令
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm commitlint
當我們 commit 提交信息時,就不能再隨意寫了,必須是 git commit -m ‘fix: xxx’ 符合類型的才可以,需要注意的是類型的后面需要用英文的 :,并且冒號后面是需要空一格的,這個是不能省略的
六、強制使用pnpm包管理器工具
團隊開發項目的時候,需要統一包管理器工具,因為不同包管理器工具下載同一個依賴,可能版本不一樣,
導致項目出現bug問題,因此包管理器工具需要統一管理!!!
在根目錄創建scritps/preinstall.js
文件,添加下面的內容
if (!/pnpm/.test(process.env.npm_execpath || '')) {console.warn(`\u001b[33mThis repository must using pnpm as the package manager ` +` for scripts to work properly.\u001b[39m\n`,)process.exit(1)
}
配置命令
"scripts": {"preinstall": "node ./scripts/preinstall.js"
}
當我們使用npm或者yarn來安裝包的時候,就會報錯了。原理就是在install的時候會觸發preinstall(npm提供的生命周期鉤子)這個文件里面的代碼。
三、項目集成
3.1集成element-plus
硅谷甄選運營平臺,UI組件庫采用的element-plus,因此需要集成element-plus插件!!!
官網地址:https://element-plus.gitee.io/zh-CN/
pnpm install element-plus @element-plus/icons-vue
入口文件main.ts全局安裝element-plus,element-plus默認支持語言英語設置為中文
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
//@ts-ignore忽略當前文件ts類型的檢測否則有紅色提示(打包會失敗)
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {locale: zhCn
})
Element Plus全局組件類型聲明
// tsconfig.json
{"compilerOptions": {// ..."types": ["element-plus/global"]}
}
配置完畢可以測試element-plus組件與圖標的使用.
3.2src別名的配置
在開發項目的時候文件與文件關系可能很復雜,因此我們需要給src文件夾配置一個別名!!!
// vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({plugins: [vue()],resolve: {alias: {"@": path.resolve("./src") // 相對路徑別名配置,使用 @ 代替 src}}
})
TypeScript 編譯配置
// tsconfig.json
{"compilerOptions": {"baseUrl": "./", // 解析非相對模塊的基地址,默認是當前目錄"paths": { //路徑映射,相對于baseUrl"@/*": ["src/*"] }}
}
3.3環境變量的配置
項目開發過程中,至少會經歷開發環境、測試環境和生產環境(即正式環境)三個階段。不同階段請求的狀態(如接口地址等)不盡相同,若手動切換接口地址是相當繁瑣且易出錯的。于是環境變量配置的需求就應運而生,我們只需做簡單的配置,把環境狀態切換的工作交給代碼。
開發環境(development)
顧名思義,開發使用的環境,每位開發人員在自己的dev分支上干活,開發到一定程度,同事會合并代碼,進行聯調。
測試環境(testing)
測試同事干活的環境啦,一般會由測試同事自己來部署,然后在此環境進行測試
生產環境(production)
生產環境是指正式提供對外服務的,一般會關掉錯誤報告,打開錯誤日志。(正式提供給客戶使用的環境。)
注意:一般情況下,一個環境對應一臺服務器,也有的公司開發與測試環境是一臺服務器!!!
項目根目錄分別添加 開發、生產和測試環境的文件!
.env.development
.env.production
.env.test
文件內容
# 變量必須以 VITE_ 為前綴才能暴露給外部讀取
NODE_ENV = 'development'
VITE_APP_TITLE = '硅谷甄選運營平臺'
VITE_APP_BASE_API = '/dev-api'
NODE_ENV = 'production'
VITE_APP_TITLE = '硅谷甄選運營平臺'
VITE_APP_BASE_API = '/prod-api'
# 變量必須以 VITE_ 為前綴才能暴露給外部讀取
NODE_ENV = 'test'
VITE_APP_TITLE = '硅谷甄選運營平臺'
VITE_APP_BASE_API = '/test-api'
配置運行命令:package.json
"scripts": {"dev": "vite --open","build:test": "vue-tsc && vite build --mode test","build:pro": "vue-tsc && vite build --mode production","preview": "vite preview"},
通過import.meta.env獲取環境變量
3.4SVG圖標配置
在開發項目的時候經常會用到svg矢量圖,而且我們使用SVG以后,頁面上加載的不再是圖片資源,
這對頁面性能來說是個很大的提升,而且我們SVG文件比img要小的很多,放在項目中幾乎不占用資源。
安裝SVG依賴插件
pnpm install vite-plugin-svg-icons -D
在vite.config.ts
中配置插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {return {plugins: [createSvgIconsPlugin({// Specify the icon folder to be cachediconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],// Specify symbolId formatsymbolId: 'icon-[dir]-[name]',}),],}
}
入口文件導入
import 'virtual:svg-icons-register'
3.4.1svg封裝為全局組件
因為項目很多模塊需要使用圖標,因此把它封裝為全局組件!!!
在src/components目錄下創建一個SvgIcon組件:代表如下
<template><div><svg :style="{ width: width, height: height }"><use :xlink:href="prefix + name" :fill="color"></use></svg></div>
</template><script setup lang="ts">
defineProps({//xlink:href屬性值的前綴prefix: {type: String,default: '#icon-'},//svg矢量圖的名字name: String,//svg圖標的顏色color: {type: String,default: ""},//svg寬度width: {type: String,default: '16px'},//svg高度height: {type: String,default: '16px'}})
</script>
<style scoped></style>
在src文件夾目錄下創建一個index.ts文件:用于注冊components文件夾內部全部全局組件!!!
import SvgIcon from './SvgIcon/index.vue';
import type { App, Component } from 'vue';
const components: { [name: string]: Component } = { SvgIcon };
export default {install(app: App) {Object.keys(components).forEach((key: string) => {app.component(key, components[key]);})}
}
在入口文件引入src/index.ts文件,通過app.use方法安裝自定義插件
import gloablComponent from './components/index';
app.use(gloablComponent);
3.5集成sass
我們目前在組件內部已經可以使用scss樣式,因為在配置styleLint工具的時候,項目當中已經安裝過sass sass-loader,因此我們再組件內可以使用scss語法!!!需要加上lang=“scss”
<style scoped lang="scss"></style>
接下來我們為項目添加一些全局的樣式
在src/styles目錄下創建一個index.scss文件,當然項目中需要用到清除默認樣式,因此在index.scss引入reset.scss
@import reset.scss
在入口文件引入
import '@/styles'
但是你會發現在src/styles/index.scss全局樣式文件中沒有辦法使用 變量 . 因此需要給項目中引入全局變量 變量.因此需要給項目中引入全局變量 變量.因此需要給項目中引入全局變量.
在style/variable.scss創建一個variable.scss文件!
在vite.config.ts文件配置如下:
export default defineConfig((config) => {css: {preprocessorOptions: {scss: {javascriptEnabled: true,additionalData: '@import "./src/styles/variable.scss";',},},},}
}
@import "./src/styles/variable.less";
后面的;
不要忘記,不然會報錯!
配置完畢你會發現scss提供這些全局變量可以在組件樣式中使用了!!!
3.6mock數據
安裝依賴:https://www.npmjs.com/package/vite-plugin-mock
pnpm install -D vite-plugin-mock mockjs
在 vite.config.js 配置文件啟用插件。
import { UserConfigExport, ConfigEnv } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'
export default ({ command })=> {return {plugins: [vue(),viteMockServe({localEnabled: command === 'serve',}),],}
}
在根目錄創建mock文件夾:去創建我們需要mock數據與接口!!!
在mock文件夾內部創建一個user.ts文件
//用戶信息數據
function createUserList() {return [{userId: 1,avatar:'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',username: 'admin',password: '111111',desc: '平臺管理員',roles: ['平臺管理員'],buttons: ['cuser.detail'],routes: ['home'],token: 'Admin Token',},{userId: 2,avatar:'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',username: 'system',password: '111111',desc: '系統管理員',roles: ['系統管理員'],buttons: ['cuser.detail', 'cuser.user'],routes: ['home'],token: 'System Token',},]
}export default [// 用戶登錄接口{url: '/api/user/login',//請求地址method: 'post',//請求方式response: ({ body }) => {//獲取請求體攜帶過來的用戶名與密碼const { username, password } = body;//調用獲取用戶信息函數,用于判斷是否有此用戶const checkUser = createUserList().find((item) => item.username === username && item.password === password,)//沒有用戶返回失敗信息if (!checkUser) {return { code: 201, data: { message: '賬號或者密碼不正確' } }}//如果有返回成功信息const { token } = checkUserreturn { code: 200, data: { token } }},},// 獲取用戶信息{url: '/api/user/info',method: 'get',response: (request) => {//獲取請求頭攜帶tokenconst token = request.headers.token;//查看用戶信息是否包含有次token用戶const checkUser = createUserList().find((item) => item.token === token)//沒有返回失敗的信息if (!checkUser) {return { code: 201, data: { message: '獲取用戶信息失敗' } }}//如果有返回成功信息return { code: 200, data: {checkUser} }},},
]
安裝axios
pnpm install axios
最后通過axios測試接口!!!
3.7axios二次封裝
在開發項目的時候避免不了與后端進行交互,因此我們需要使用axios插件實現發送網絡請求。在開發項目的時候
我們經常會把axios進行二次封裝。
目的:
1:使用請求攔截器,可以在請求攔截器中處理一些業務(開始進度條、請求頭攜帶公共參數)
2:使用響應攔截器,可以在響應攔截器中處理一些業務(進度條結束、簡化服務器返回的數據、處理http網絡錯誤)
在根目錄下創建utils/request.ts
import axios from "axios";
import { ElMessage } from "element-plus";
//創建axios實例
let request = axios.create({baseURL: import.meta.env.VITE_APP_BASE_API,timeout: 5000
})
//請求攔截器
request.interceptors.request.use(config => {return config;
});
//響應攔截器
request.interceptors.response.use((response) => {return response.data;
}, (error) => {//處理網絡錯誤let msg = '';let status = error.response.status;switch (status) {case 401:msg = "token過期";break;case 403:msg = '無權訪問';break;case 404:msg = "請求地址錯誤";break;case 500:msg = "服務器出現問題";break;default:msg = "無網絡";}ElMessage({type: 'error',message: msg})return Promise.reject(error);
});
export default request;
3.8API接口統一管理
在開發項目的時候,接口可能很多需要統一管理。在src目錄下去創建api文件夾去統一管理項目的接口;
比如:下面方式
//統一管理咱們項目用戶相關的接口import request from '@/utils/request'import type {loginFormData,loginResponseData,userInfoReponseData,} from './type'//項目用戶相關的請求地址enum API {LOGIN_URL = '/admin/acl/index/login',USERINFO_URL = '/admin/acl/index/info',LOGOUT_URL = '/admin/acl/index/logout',}
//登錄接口
export const reqLogin = (data: loginFormData) =>request.post<any, loginResponseData>(API.LOGIN_URL, data)
//獲取用戶信息export const reqUserInfo = () =>request.get<any, userInfoReponseData>(API.USERINFO_URL)//退出登錄export const reqLogout = () => request.post<any, any>(API.LOGOUT_URL)
四、項目的資源地址
賈成豪老師代碼倉庫地址:https://gitee.com/jch1011/vue3_admin_template-bj1.git
項目在線文檔:
服務器域名:http://sph-api.atguigu.cn
swagger文檔:
http://139.198.104.58:8209/swagger-ui.html
http://139.198.104.58:8212/swagger-ui.html#/
echarts:國內鏡像網站
https://www.isqqw.com/echarts-doc/zh/option.html#title
http://datav.aliyun.com/portal/school/atlas/area_selector