1. 技術棧介紹
vue3:組件封裝和拆分比Vue2更加細化和合理。
typescript:比js更加嚴格的類型檢查,能夠在編譯期就能發現錯誤。
vite:下一代前端開發和構建工具。
element plus:ui組件庫,比較熱門的vue組件庫之一。
axios:基于promise的網絡請求庫。
vue-router:路由控制。
keep-alive: 在組件切換過程中將狀態保留在內存中,防止重復渲染DOM,減少加載時間及性能消耗,提高用戶體驗性。
pinia:狀態管理類庫,比vuex更小,對ts的支持更友好。
volar插件:代碼補全和檢測工具,可以嘗試替換vetur,如果不替換的話,用ts的語法糖的時候會出現找不到默認的default的錯誤。
pnpm:比npm和yarn更強大的包管理工具,包安裝速度極快,磁盤空間利用效率高。
2. 開發環境準備
#全局安裝pnpm
npm i pnpm -g
3. 創建項目
# npm 6.x
npm init vite@latest my-vue-app --template vue-ts
# npm 7+, 需要額外的雙橫線
npm init vite@latest my-vue-app -- --template vue-ts
# yarn
yarn create vite my-vue-app --template vue-ts
# pnpm
pnpm create vite my-vue-app -- --template vue-ts
4. 引入vue-router
pnpm i vue-router@latest -D
5. 引入axios
pnpm i axios -D
6. 引入pinia
pnpm i pinia -D
7. 引入element-plus
pnpm i element-plus -D
項目搭建完成可以運行起來試試
pnpm run dev
8. 配置使用 element-plus
#配置src/main.ts文件
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 引入element-plus
import element from 'element-plus'
import 'element-plus/dist/index.css' // 不引入會導致ui樣式不正常
createApp(App).use(element).mount('#app')
9. 配置環境信息
- 根目錄新建.env.development(開發環境)文件
# 文件中配置變量以VITE_開頭, 后面接變量名 例如 VITE_ENV = "development" ,ENV為變量名
#環境
VITE_ENV = "development"
#基礎地址
VITE_BASE_PATH = "http://1920.1080.1.1"
#服務
VITE_BASE_API='/api'
#端口
VITE_PROT = 9527
#地址
VITE_PUBLIC_PATH='./'
#修改project命令, 在dev運行命令后加入 --mode 文件名 例如 "serve": "vite --mode development", 運行時自動讀取 .env.development文件
#build打包時默認是讀取.env.production文件的所以不用配置
- 同理配置testing(測試環境);release(預發環境);production(生產環境)
- 安裝 pnpm install dotenv 根據環境變量運行 使用配置詳見下方 vite.config.ts
pnpm install dotenv
10.自動引入組件和vue方法的插件
pnpm install -D unplugin-vue-components unplugin-auto-import //下載插件
//vite.config.js中配置
import AutoImport from 'unplugin-auto-import/vite' //自動引入api
import Components from 'unplugin-vue-components/vite' //按需自動引入組件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
//在plugins配置中配置
export default () => {
return defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()], //對于element puls的配置
imports: [
'vue', //自動引入的vue的ref等方法
'vue-router', //引入useRoute等方法
{ //對于vue-router的type的擴展,配置后可以直接使用
from: 'vue-router',
imports: ['RouteLocationRaw',],
type: true,
},],
dts: 'src/auto-imports.d.ts'
}),
Components({
resolvers: [ElementPlusResolver()], //對于element puls的配置
}),
],
})
}
//使用:
//在此處配置element plus后, 可以直接使用,仁和地方都不用再引入,自動按需引入的,在components.d.ts中可以看到生成文件
//import {ref} from "vue"這種引入也可省略, 直接使用即可, 具體引入的類型在src/auto-imports.d.ts文件中可見
//注意:修改vite.config.ts文件后需要重啟
11. 配置使用 vue-router
1.如果使用require需要安裝@types/node
cnpm i @types/node -D
//vite.config.js中配置
import { defineConfig, UserConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import AutoImport from 'unplugin-auto-import/vite' //自動引入api
import Components from 'unplugin-vue-components/vite' //按需自動引入組件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// @ts-ignore
import fs from 'fs'
// @ts-ignore
import dotenv from 'dotenv'
//在plugins配置中配置
export default defineConfig(({ mode }: UserConfig): UserConfig => {
// 根據環境變量加載環境變量文件
const ASR_ENV = dotenv.parse(fs.readFileSync(`.env.${mode}`))
return {
base: ASR_ENV.VITE_PUBLIC_PATH, // 環境路徑
server: {
open: true, // 是否主動喚醒瀏覽器
host: '0.0.0.0',
port: 9527,// ASR_ENV.VITE_PROT,
https: false,
proxy: {
[ASR_ENV.VITE_BASE_API]: {
target: `${ASR_ENV.VITE_BASE_PATH}`,
changeOrigin: true,
},
},
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'assets': path.resolve(__dirname, 'src/assets'),
'components': path.resolve(__dirname, 'src/components'),
'config': path.resolve(__dirname, 'src/config'),
'router': path.resolve(__dirname, 'src/router'),
'tools': path.resolve(__dirname, 'src/tools'),
'views': path.resolve(__dirname, 'src/views'),
'plugins': path.resolve(__dirname, 'src/plugins'),
'store': path.resolve(__dirname, 'src/store')
}
},
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()], //對于element puls的配置
imports: [
'vue', //自動引入的vue的ref等方法
'vue-router', //引入useRoute等方法
{ //對于vue-router的type的擴展,配置后可以直接使用
from: 'vue-router',
imports: ['RouteLocationRaw',],
type: true,
},],
dts: 'src/auto-imports.d.ts'
}),
Components({
resolvers: [ElementPlusResolver()], //對于element puls的配置
}),
],
css: {
preprocessorOptions: {
scss: {
charset: false,
},
},
},
build: {
outDir: 'dist', // 指定輸出路徑
assetsDir: 'static', // 指定生成靜態資源的存放路徑
minify: 'terser', // 混淆器,terser構建后文件體積更小 ,boolean | 'terser' | 'esbuild',默認使用esbuild
sourcemap: false, // 是否產出soucemap.json
manifest: false, // 是否產出maifest.json
// reportCompressedSize: true,
chunkSizeWarningLimit: 1500,
terserOptions: {
compress: {
drop_console: true, // 生產環境移除console
drop_debugger: true // 生產環境移除debugger
}
},
},
}
}
//使用:
//在此處配置element plus后, 可以直接使用,仁和地方都不用再引入,自動按需引入的,在components.d.ts中可以看到生成文件
//import {ref} from "vue"這種引入也可省略, 直接使用即可, 具體引入的類型在src/auto-imports.d.ts文件中可見
//注意:修改vite.config.ts文件后需要重啟
2.在src下新建一個router文件夾,作為vue-router的配置目錄。此目錄下再新建index.ts文件,編輯內容如下:
#配置router/index.ts文件
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const history = createWebHistory()
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'home',
component: () => import('@/views/home/index.vue'),
},
];
const router = createRouter({
history,
routes,
})
export default router
- 在views目錄下新建home目錄并新建index.vue
#index.vue頁面
<template>
<h2>{{ msg }}</h2>
<h2>{{ count }}</h2>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('今天天氣好晴朗')
const count = ref(710)
</script>
<style scoped>
</style>
4.在main.ts中引入vue-router
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 引入vue-router
import router from './router'
// 引入element-plus
import element from 'element-plus'
import 'element-plus/dist/index.css' // 不引入會導致ui樣式不正常
createApp(App).use(router).use(element).mount('#app')
12. axiox配置使用
- 安裝插件:axios 和 js-cookie
pnpm i axios -D
pnpm i js-cookie
- 在src下新建utils文件夾 創建auth.ts與request.ts文件
// auth.ts
// @ts-ignore
import Cookies from 'js-cookie';
const TokenKey = 'asr-token';
export const getToken = () => Cookies.get(TokenKey);
export const delToken = () => Cookies.remove(TokenKey);
// request.ts
import axios from 'axios'; // 引入axios
import Vrouter from '@/router'
import { getToken } from '@/utils/auth';
const Router = Vrouter;
console.log('import.meta.env.VITE_BASE_API', import.meta.env.VITE_BASE_API)
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API as string,
timeout: 99999,
});
// http request 攔截器
service.interceptors.request.use(
(config:any) => {
// 全局添加 token
if (getToken()) {
config.headers['asr-token'] = getToken();
}
return config;
},
(error) => {
console.error(error);
return Promise.reject(error);
},
);
// http response 攔截器
service.interceptors.response.use(
(response) => {
if (response.data.code === 9) {
// Router.replace('/rejectUser');
return
}
return response.data
},
(error) => {
if (error.response && error.response.status && error.response.status === 403) {
// logout().then(() => {
// // removeToken()
// });
}
// 網絡超時
if (error.message && error.message.includes('timeout')) {
console.error('請求超時');
return error.message;
}
if (error.response && error.response.status && error.response.status === 500) {
// 沒有權限
console.error('接口異常');
return error;
}
return error;
},
);
export default service;
- src下新建types類型文件夾:用于聲明類型
// /src/types/service/index.ts
interface resModel {
code:number
msg:string
data:any
[propname:string]:any
}
export interface requestModel {
<T>(data?: T): Promise<resModel>
}
4.src下新建 api文件,新建login.ts文件 用來寫接口配置
import request from '@/utils/request';
import { requestModel } from '@/types/service';
// 獲取用戶信息
export const getLogin: requestModel = () => request({
url: '/login',
method: 'get',
});
// 獲取用戶信息
export const getUserInfo: requestModel = () => request({
url: '/info',
method: 'get',
});
// 退出登錄
export const logout: requestModel = () => request({
url: '/quit',
method: 'post',
});
13. pinia 配置并使用
- 安裝pinia-plugin-persist 用于倉庫持久化
pnpm install pinia-plugin-persist
- 在根目錄新建一個store 文件夾 新建 index.ts 文件
import { createPinia } from 'pinia'
// 引入持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
// 使用該插件
store.use(piniaPluginPersist)
//導出
export default store
- 在main.ts文件引入
//引入倉庫
import pinia from '@/store/index';
app
.use(pinia)//使用
.mount('#app')
- 存儲配置
#src/store/login.ts
import { defineStore } from 'pinia'
//導出倉庫方法
export const loginStore = defineStore("login", {
state: () => ({
count: 0,
}),
getters: {
},
actions: {
//修改vccode的值
changeCount(value:number){
console.log('---loginStore---', value);
this.count=value
},
},
//持久化
persist:{
enabled:true,
strategies:[
{
key:'login',//存儲的key值
storage:localStorage,//存儲的位置
paths:['count'] //默認持久化state的全部,paths指定持久化的對象
}
]
},
})
14. keepAlive 頁面緩存配置
- 我們之前在學習vue-router時,給每個路由都寫了meta,里面寫了keepAlive,現在是用它的時候了
{
path: '/',
component: () => import('./views/index'),
name: 'index',
meta: {
title: '首頁',
keepAlive: true,
},
},
- 現在要把keepAlive寫在router-view里面,使用作用域插槽獲得頁面組件
<!-- src/App.vue -->
<template>
<router-view v-slot="slotProps">
<keep-alive>
<component :is="slotProps.Component"></component>
</keep-alive>
</router-view>
</template>
<script setup lang="ts">
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
15. prettier 代碼格式校驗及整理
-
vscode下載prettier 插件
image.png - 根目錄創建.prettierrc文件
{
"printWidth": 500, // 超過最大值換行
"tabWidth": 2, // 縮進字節數
"useTabs": true, // 縮進使用tab。 false使用空格
"semi": true, // 句尾添加分號
"singleQuote": true, // // 使用單引號代替雙引號
"quoteProps": "as-needed", //
"trailingComma": "es5",// 在對象或數組最后一個元素后面是否加逗號(在ES5中加尾逗號)
"jsxSingleQuote": true, // 在jsx中使用單引號代替雙引號
"jsxBracketSameLine": false, // 在jsx中把'>' 是否單獨放一行
"bracketSpacing": true,// 在對象,數組括號與文字之間加空格 "{ foo: bar }"
"arrowParens": "avoid", // (x) => {} 箭頭函數參數只有一個時是否要有小括號。avoid:省略括號
"insertPragma": false,
"disableLanguages":["vue"], // 不格式化vue文件,vue文件的格式化單獨設置
"proseWrap": "preserve", // 默認值。因為使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本樣式進行折行
"endOfLine": "auto", // 結尾是 \n \r \n\r auto
"htmlWhitespaceSensitivity": "css",
"format": {
"defaultFormatter": {
"html": "js-beautify-html",
"js": "prettier"
},
"defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "auto",
"wrap_line_length": 100,
"end_with_newline": false,
"semi": true,
"singleQuote": true
},
"prettier": {
"semi": true,
"singleQuote": true
}
}
}
}
3.根目錄下格式化忽略文件創建 .prettierignore文件
#.prettierignore文件
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*
4.使用格式化推薦兩種方式
a.配置整體格式化命令
運行后自動整體格式化,package.json中配置,每次提交代碼之前需要運行命令npm run prettier
#package.json
"script":{
"prettier ": "prettier --write ."
}
#運行命令 npm run prettier
b.每次保存文件后自動格式化
這是vscode的步驟,其他編輯器自行根據下面的方案處理。
1、打開編輯器設置頁面,輸入 files.autoSave 篩出設置項,并把設置項屬性選擇為 onFocuschange
2、輸入 editor.defaultFormatter ,將配置項選擇為Prettier (設置默認代碼格式化(美化)的插件為Prettier)
3、輸入 editor.formatOnSave ,勾選上 "保存時格式化文件。格式化程序必須可用,xxxxxxxx....."
16. 問題整理
pnpm i @types/webpack-env @types/node -D
#配置tsconfig.json { "compilerOptions": { ... "types": [ "node", "webpack-env" ] }, ... }