Bootstrap

Vue3-Vite2-vueRouter4-Axios-Ts-Scss-ElementPlus-Prettier-Pinia

生命周期

Vue2           			vue3
beforeCreate  			-> setup()
created       			-> setup()
beforeMount   			-> onBeforeMount
mounted       			-> onMounted
beforeUpdate 			-> onBeforeUpdate
updated       			-> onUpdated
beforeDestroy 			-> onBeforeUnmount
destroyed     			-> onUnmounted
activated     			-> onActivated
deactivated   			-> onDeactivated

使用 vite 快速创建脚手架

Vite 需要 Node.js 版本 >= 12.0.0

# npm 6.x
npm init @vitejs/app 项目名 --template

# npm 7+, 需要额外的双横线:
npm init @vitejs/app 项目名 -- --template

# yarn
yarn create @vitejs/app 项目名 --template

cd 项目名
# 安装依赖
yarn
# 启动
yarn dev

prettier 安装&&使用

npm install prettier --save-dev

新建 prettier.js

module.exports = {
  tabWidth: 2,
  jsxSingleQuote: true,
  jsxBracketSameLine: true,
  printWidth: 100,
  singleQuote: true,
  semi: false,
  overrides: [
    {
      files: '*.json',
      options: {
        printWidth: 200,
      },
    },
  ],
  arrowParens: 'always',
}

项目下新建 .prettierignore

# 忽略格式化文件 (根据项目需要自行添加)
node_modules
dist

package.json 配置:

{
  "script": {
    "lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
    "prettier": "prettier --write ."
  }
}

配置预处理器 scss

npm install sass-loader --dev
npm install dart-sass --dev
npm install sass --dev

路由

新建router文件夹,新建router.ts

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Login',
    component: () => import('@/pages/login/Login.vue'), 
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

export default router

main.ts

import router from './router/index'
app.use(router)

vue-router4.x 支持 typescript,配置路由的类型是 RouteRecordRaw,这里 meta 可以让我们有更多的发挥空间,这里提供一些参考:

title:string; 页面标题,通常必选。
icon?:string; 图标,一般配合菜单使用。
auth?:boolean; 是否需要登录权限。
ignoreAuth?:boolean; 是否忽略权限。
roles?:RoleEnum[]; 可以访问的角色
keepAlive?:boolean; 是否开启页面缓存
hideMenu?:boolean; 有些路由我们并不想在菜单中显示,比如某些编辑页面。
order?:number; 菜单排序。
frameUrl?:string; 嵌套外链。

请求封装

yarn add axios

新建 service 文件夹,service 下新增 http.ts 文件以及 api 文件夹

import axios, { AxiosRequestConfig } from "axios";

// 设置请求头和请求路径
axios.defaults.baseURL = "/api";
axios.defaults.timeout = 10000;
axios.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8";
axios.interceptors.request.use(
  (config): AxiosRequestConfig<any> => {
    const token = window.sessionStorage.getItem("token");
    if (token) {
      //@ts-ignore
      config.headers.token = token;
    }
    return config;
  },
  (error) => {
    return error;
  }
);
// 响应拦截
axios.interceptors.response.use((res) => {
  if (res.data.code === 111) {
    sessionStorage.setItem("token", "");
    // token过期操作
  }
  return res;
});

interface ResType<T> {
  code: number;
  data?: T;
  msg: string;
  err?: string;
}
interface Http {
  get<T>(url: string, params?: unknown): Promise<ResType<T>>;
  post<T>(url: string, params?: unknown): Promise<ResType<T>>;
  upload<T>(url: string, params: unknown): Promise<ResType<T>>;
  download(url: string): void;
}

const http: Http = {
  get(url, params) {
    return new Promise((resolve, reject) => {
      axios
        .get(url, { params })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  },
  post(url, params) {
    return new Promise((resolve, reject) => {
      axios
        .post(url, JSON.stringify(params))
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  },
  upload(url, file) {
    return new Promise((resolve, reject) => {
      axios
        .post(url, file, {
          headers: { "Content-Type": "multipart/form-data" },
        })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  },
  download(url) {
    const iframe = document.createElement("iframe");
    iframe.style.display = "none";
    iframe.src = url;
    iframe.onload = function () {
      document.body.removeChild(iframe);
    };
    document.body.appendChild(iframe);
  },
};
export default http;

login.ts

import http from '@/service/http'
import * as T from './types'

const loginApi: T.ILoginApi = {
    login(params){
        return http.post('/login', params)
    }

}
export default loginApi

types.ts

export interface ILoginParams {
    userName: string
    passWord: string | number
}
export interface ILoginApi {
    login: (params: ILoginParams)=> Promise<any>
}

状态管理 pinia

# 安装
yarn add pinia@next

main.ts

# 引入
import { createPinia } from "pinia"
# 创建根存储库并将其传递给应用程序
app.use(createPinia())

创建store文件夹,index.ts

import { defineStore } from 'pinia'

export const store = defineStore({
  id: 'mian',
  state: () => ({
    name: '超级管理员',
  }),
  getters: {
    nameLength: (state) => state.name.length,
  },
  actions: {
    async insertPost(data:string){
      // 可以做异步
      // await doAjaxRequest(data);
      this.name = data;
    }
  },
})

组件内使用

<template>
  <div>{{ mainStore.name }}<br />{{ mainStore.nameLength }}</div>
  <button @click="updateName">修改</button>
</template>

<script setup lang="ts">
import {store} from '@/store/mian'

const stores= store()

const updateName = ()=>{
  // $patch 修改 store 中的数据
  stores.$patch({
    name: '名称被修改了'
  })
  // action使用方法
  stores.insertPost('名称被修改了')
}
</script>

环境变量配置

项目根目录新建:.env.development

NODE_ENV=development
VITE_APP_WEB_URL= 'http://192.168.3.11:8000'

项目根目录新建:.env.production

NODE_ENV=production
VITE_APP_WEB_URL= 'http://192.168.3.11:8000'

配置 package.json

"build:dev": "vue-tsc --noEmit && vite build --mode development",
"build:pro": "vue-tsc --noEmit && vite build --mode production",

Vite 常用基础配置

运行 代理 和 打包 配置

server: {
    host: '0.0.0.0',
    port: 3000,
    open: true,
    https: false,
    proxy: {}
},

生产环境去除 console debugger

build:{
  terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
  }
}

element-plus

npm install element-plus --save

yarn add element-plus

pnpm install element-plus

main.ts

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

app.use(ElementPlus)
;