vue3+vue-router+Ts+vite+pinia+element Plus搭建前端工程

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. 配置環境信息

  1. 根目錄新建.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文件的所以不用配置
  1. 同理配置testing(測試環境);release(預發環境);production(生產環境)
  2. 安裝 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

  1. 在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配置使用

  1. 安裝插件:axios 和 js-cookie
pnpm i axios -D
pnpm i js-cookie 
  1. 在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;
  1. 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 配置并使用

  1. 安裝pinia-plugin-persist 用于倉庫持久化
pnpm install pinia-plugin-persist
  1. 在根目錄新建一個store 文件夾 新建 index.ts 文件
import { createPinia } from 'pinia'
// 引入持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
// 使用該插件
store.use(piniaPluginPersist)
//導出
export default store
  1. 在main.ts文件引入
//引入倉庫
import pinia from '@/store/index';

app
    .use(pinia)//使用
    .mount('#app')
  1. 存儲配置
#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 頁面緩存配置

  1. 我們之前在學習vue-router時,給每個路由都寫了meta,里面寫了keepAlive,現在是用它的時候了
  {
    path: '/',
    component: () => import('./views/index'),
    name: 'index',
    meta: {
      title: '首頁',
      keepAlive: true,
    },
  },
  1. 現在要把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 代碼格式校驗及整理

  1. vscode下載prettier 插件


    image.png
  2. 根目錄創建.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. 問題整理

image.png
pnpm i @types/webpack-env @types/node -D
#配置tsconfig.json
{
   "compilerOptions": {
       ...
       "types": [
           "node",
           "webpack-env"
       ]
   },
   ...
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容