# vue3-ts-elementPlus-pinia-echarts **Repository Path**: shi-weizhen/vue3-ts-element-plus-pinia-echarts ## Basic Information - **Project Name**: vue3-ts-elementPlus-pinia-echarts - **Description**: 比较完整的vue3项目构建过程 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-11-28 - **Last Updated**: 2023-03-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue3.2 + vite + ts + vue-router4 + pinia + elementPlus + echarts5 项目初始化 (代序) ### 一.项目搭建 全局安装`pnpm`,安装命令为 注意: 安装 `pnpm`, `node` 的版本号要大于 V14.19.0 ``` npm i pnpm -g ``` 在 VScode 里面下载插件`Vue Language Features(Volar)`,禁用掉 `Vetur`,不然代码会报一堆错误 接下来,我们开始构建项目 1.在需要创建项目文件目录下打开 `cmd` 运行下列命令 ``` pnpm create vite ``` 2.输入项目名称 ``` ? Project name: » vue3-ts-elementPlus-pinia-echarts ``` 3.选择一个框架 ``` ? Select a framework: » - Use arrow-keys. Return to submit. Vanilla > Vue React Preact Lit Svelte Others ``` 4.选择使用 `TypeScript` ``` ? Select a variant: » - Use arrow-keys. Return to submit. JavaScript > TypeScript Customize with create-vue ↗ Nuxt ↗ ``` 5.找到文件夹,用 vscode 打开,首先使用 `pnpm i` 安装依赖, 在使用命令 `pnpm dev`就可以启动项目了 这里注意: 如果安装依赖时出错,可以切换淘宝远 ``` pnpm config set registry https://registry.npmmirror.com/ ``` 项目启动成功,打开之后,可以看到如下所示 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16692713148370.png) ### 二.设置并约束代码风格 往往我们写代码的时候,最讨厌的是地下大部分的红色报错信息,并且格式错乱,所以可以配置一些相关信息,完善我们的代码风格 #### 配置 `eslint` 和 `prettier` 1.执行下列命令安装依赖 ``` pnpm i eslint -D pnpm i prettier -D pnpm i eslint-plugin-vue -D pnpm i eslint-plugin-prettier -D pnpm i eslint-config-prettier -D pnpm i @typescript-eslint/eslint-plugin -D pnpm i @typescript-eslint/parser -D pnpm i @vue/eslint-config-prettier -D pnpm i @vue/eslint-config-typescript -D ``` 2.项目下新建 `.eslintrc.js` 文件,并配置 `eslint` 的检验规则 ```javascript module.exports = { // ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找。 root: true, // 指定脚本的运行环境。每种环境都有一组特定的预定义全局变量。 env: { browser: true, es6: true, node: true, 'vue/setup-compiler-macros': true }, // 指定如何解析语法 parser: 'vue-eslint-parser', // 优先级低于parse的语法解析配置 parserOptions: { // js的版本 ecmaVersion: 2020, // 解析器 parser: '@typescript-eslint/parser', // 模块化方案 sourceType: 'module', ecmaFeatures: { jsx: true } }, // plugins: ['@typescript-eslint'], //定义了该eslint文件所依赖的插件 // 代表你启动哪些 lint 选项,如果多个规则直接有冲突的话,extends后面的选项会覆盖前面的。 extends: [ // 'eslint:recommended', // 防止错误或意外行为的规则 'plugin:vue/vue3-essential', // 大大提高代码可读性和/或开发体验的规则 'plugin:vue/vue3-strongly-recommended', // 加上强制执行主观社区默认值的规则,以确保一致性 'plugin:vue/vue3-recommended', // typescript-eslint推荐规则 'plugin:@typescript-eslint/recommended', 'prettier', // 使用prettier中的样式规范,且如果使得ESLint会检测prettier的格式问题,同样将格式问题以error的形式抛出 'plugin:prettier/recommended' ], rules: { // override/add rules settings here, such as: // 禁止不必要的分号 // '@typescript-eslint/no-extra-semi': 'off', // 如不禁用这条规则会导致命名为index或其他单字母组件名的文件报错,(不要求组件名称始终为多字) 'vue/multi-word-component-names': 0, // 允许属性之间使用驼峰命名,不强制要求使用 - 连字符 'vue/attribute-hyphenation': 0, // 不需要 props 的默认值 'vue/require-default-prop': 'off', // 禁止 v-for 指令或范围属性的未使用变量定义 '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' } ], 'no-unused-vars': [ 'error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' } ], '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-explicit-any': 'off' } } ``` 自定义规则,具体配置可参考:[https://eslint.vuejs.org/rules/](https://eslint.vuejs.org/rules/) 3.在项目下新建 `.eslintignore` 文件,配置 `eslint` 忽略检查的文件或目录 ``` dist/ es/ lib/ node_modules/ .gitignore *.sh *.md *.woff *.ttf .vscode .idea /public /docs .husky .local /bin Dockerfile ``` 4.项目下新建 `.prettierrc.js` 文件,配置 `prettier` 代码风格 ```javascript module.exports = { // 使用 2 个空格缩进 tabWidth: 2, // 不使用 tab 缩进,而使用空格 useTabs: false, // 行尾不需要分号 semi: false, // // jsx 标签的反尖括号需要换行 // jsxBracketSameLine: false, // // jsx 不使用单引号,而使用双引号 // jsxSingleQuote: false, // 箭头函数,只有一个参数的时候,不需要括号 arrowParens: 'avoid', // 使用单引号代替双引号 singleQuote: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }" bracketSpacing: true, // 换行符使用 lf endOfLine: 'lf', // 末尾不使用逗号 trailingComma: 'none', // 使用默认的折行标准 proseWrap: 'preserve' // 根据显示样式决定 html 要不要折行 // htmlWhitespaceSensitivity: 'css' } ``` 更多配置信息,可参考官网:[https://www.prettier.cn/docs/index.html](https://www.prettier.cn/docs/index.html) 这里有个细节,如果 vite 的版本大于 3 的话,文件的后缀名改为`cjs` 并且重新打开编辑器 5.项目下新建 `.prettierignore` ,配置 `prettier` 忽略文件 ``` dist/ es/ lib/ node_modules/ pnpm-lock.yaml pnpm-workspace.yaml CHANGELOG.md .local .output.js **/*.svg **/*.sh /public/* ``` 6.`package.json` 文件下添加以下配置 ```json "scripts": { "eslint:comment": "使用 ESLint 检查并自动修复 src 目录下所有扩展名为 .js 和 .vue 的文件", "eslint": "eslint --ext .tsx,.ts,.js,.vue --ignore-path .gitignore --fix src", "prettier:comment": "自动格式化当前目录下的所有文件", "prettier": "prettier --write" }, ``` #### 配置编辑器风格 1.项目下 `.vscode` 文件夹下新增两个文件 `extensions.json` 和 `settings.json`, 并配置以下信息 `extensions,json` ```json { "recommendations": [ "Vue.volar", "EditorConfig.EditorConfig", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", "streetsidesoftware.code-spell-checker", "jaskang.vsc-commitizen" ] } ``` `settings.json` ```json { "editor.tabSize": 2, "editor.wordWrap": "on", // #每次保存的时候自动格式化 "editor.formatOnSave": true, // #每次保存的时候将代码按eslint格式进行修复 "eslint.codeActionsOnSave": { "source.fixAll.eslint": true }, // #去掉代码结尾的分号 "prettier.semi": false, // #使用单引号替代双引号 "prettier.singleQuote": true, // #让函数(名)和后面的括号之间加个空格 "javascript.format.insertSpaceBeforeFunctionParenthesis": false, // 设置默认序列换行符为lf "files.eol": "\n", "vue3snippets.enable-compile-vue-file-on-did-save-code": false } ``` 2.在项目下新建 `.editorconfig` 文件,配置以下信息 ``` root = true # 匹配全部文件 [*] # 设置字符集 charset = utf-8 # 末尾行去掉尾随的空格 trim_trailing_whitespace = true # 末尾行后加多一行空行 insert_final_newline = true # <"tab" | "space"> 制表符类型 indent_style = space indent_size = 2 # <"lf" | "cr" | "crlf"> 换行符类型 end_of_line = lf ``` 更多配置信息,可参考官网:[http://editorconfig.org](http://editorconfig.org) #### 配置文件引用别名 在 `vite.config.ts` 下配置以下信息: ```javascript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, 'src') } } }) ``` #### 修改配置 `tsconfig.json` 文件 ``` { "compilerOptions": { // 使用的es版本 esnext表示最高 "target": "esnext", "useDefineForClassFields": true, // tsc编译后的规范文件 "module": "esnext", // 是否允许引入js文件 "allowJs": true, // 编译的模块化的方案 "moduleResolution": "node", // 是否采用严格模式 "strict": true, // 限制对空值的检查 "strictNullChecks": false, // jsx代码编译后的规范 "jsx": "preserve", // 生成编译前代码的映射文件 "sourceMap": true, "resolveJsonModule": true, // 将每个文件作为单独的模块 "isolatedModules": true, // 允许ts文件中,同时引入 es和commonJS规范的文件 "esModuleInterop": true, // 编译过程中需要引入的库文件的列表。 "lib": ["esnext", "dom"], // 跳过声明文件的类型检查 "skipLibCheck": true, // 开始查找ts文件的基础目录 "baseUrl": "./", // 路径别名,通过某个标识符指定特定的目录 "paths": { "@": ["src"], "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }], // ts编译和检查排除的文件或者文件夹 "exclude": ["node_modules", "dist", "**/*.js"] } ``` 至此,我们的代码风格及约束文件已经配置完毕,在之后的代码编辑中,能及时纠正格式错误,使代码书写更加规范,整洁,如有缺失遗漏的部分,望大家积极评论. ### 三.配置 husky +lint-staged 使用 `husky` 和 `lint-staged` 来帮助团队进行编码规范 `husky` 是 `Git Hook` 工具,可以设置 git 在各个阶段触发的命令. #### 1.执行以下命令安装 `husky` 注意: 执行以下命令之前,必须使用 `git init` 初始化 git 仓库 ``` pnpm dlx husky-init pnpm install ``` 可以看到,在 `package.json` 中添加了一个脚本 ``` "prepare": "husky install" ``` 并且在项目下创建了 `.husky` 目录 `husky` 包含了很多 `hook`, 这里,我么使用 `pre-commit` 来触发 `eslint` #### 2.安装 `lint-staged` 执行下列命令进行安装 ``` pnpm i lint-staged -D ``` 接下来结合 `prettier` 和 `eslint` 的配置信息在 `package.json` 中加入以下配置 ``` "lint-staged": { "*.{md,js,ts,tsx,vue,scss}": "prettier --write", "*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}": "eslint --fix" }, "husky":{ "hooks":{ "pre-commit": "lint-staged" } } ``` 使用 `husky` 生成 `pre-commit` 文件,触发 `lint-staged` ``` npx husky add .husky/pre-commit "npx --no-install lint-staged" ``` 可以看到: `.husky` 目录下生成了 `pre-commit` 文件,内容为: ``` ``` #### 3.配置代码提交规范 安装提交工具,执行以下命令 ``` pnpm i commitizen cz-conventional-changelog -D pnpm i cz-customizable commitlint-config-cz -D pnpm i @commitlint/cli @commitlint/config-conventional -D ``` 在项目下新建 `.cz-config.js` 文件,用于自定义提示信息,配置代码如下: ```javascript module.exports = { types: [ { value: 'feature', name: 'feature: 增加新功能' }, { value: 'fix', name: 'fix: 修复bug' }, { value: 'bug', name: 'bug: 测试反馈bug列表中的bug号' }, { value: 'ui', name: 'ui: 更新UI' }, { value: 'docs', name: 'docs: 文档变更' }, { value: 'style', name: 'style: 代码格式(不影响代码运行的变动)' }, { value: 'perf', name: 'perf: 性能优化' }, { value: 'refactor', name: 'refactor: 重构(既不是增加feature,也不是修复bug)' }, { value: 'release', name: 'release: 发布' }, { value: 'deploy', name: 'deploy: 部署' }, { value: 'test', name: 'test: 增加测试' }, { value: 'chore', name: 'chore: 构建过程或辅助工具的变动(更改配置文件)' }, { value: 'revert', name: 'revert: 回退' }, { value: 'build', name: 'build: 打包' } ], // override the messages, defaults are as follows messages: { type: '请选择提交类型:', customScope: '请输入您修改的范围(可选):', subject: '请简要描述提交 message (必填):', body: '请输入详细描述(可选):', breaking: '是破坏性修改吗?(可选,默认N)', footer: '关联关闭的issue(可选):', confirmCommit: '确认使用以上信息提交吗?(yes/no)' }, allowCustomScopes: true, // allowBreakingChanges: ['feat', 'fix'], // 跳过哪些步骤 // skipQuestions: ['body', 'breaking'], subjectLimit: 100 } ``` 接下来在 `package.json` 中添加如下配置 ``` "scripts": { "commit": "git-cz", }, "config": { "commitizen": { "path": "node_modules/cz-customizable" } }, ``` #### 4.集成 `commitlint` 验证提交规范 以上配置完成之后,我们还是可以使用 `git commit` 命令提交不规范的代码格式,所以需要 `commitlint` 验证提交规范 在项目下新建 `commitlint.config.js` 来配置 `commitlint`和提交代码的规则,配置如下: ```javascript module.exports = { extends: ['@commitlint/config-conventional', 'cz'], rules: { 'type-enum': [ 2, 'always', [ 'feature', // 新功能(feature) 'bug', // 此项特别针对bug号,用于向测试反馈bug列表的bug修改情况 'fix', // 修补bug 'ui', // 更新 ui 'docs', // 文档(documentation) 'style', // 格式(不影响代码运行的变动) 'perf', // 性能优化 'release', // 发布 'deploy', // 部署 'refactor', // 重构(即不是新增功能,也不是修改bug的代码变动) 'test', // 增加测试 'chore', // 构建过程或辅助工具的变动 'revert', // feat(pencil): add ‘graphiteWidth’ option (撤销之前的commit) 'merge', // 合并分支, 例如: merge(前端页面): feature-xxxx修改线程地址 'build' // 打包 ] ], // 格式 小写 'type-case': [2, 'always', 'lower-case'], // 不能为空 'type-empty': [2, 'never'], // 范围不能为空 'scope-empty': [2, 'never'], // 范围格式 'scope-case': [0], // 主要 message 不能为空 'subject-empty': [2, 'never'], // 以什么为结束标志,禁用 'subject-full-stop': [0, 'never'], // 格式,禁用 'subject-case': [0, 'never'], // 以空行开头 'body-leading-blank': [1, 'always'], 'header-max-length': [0, 'always', 72] } } ``` 使用 `husky` 生成 `commit-msg` 文件,验证提交信息 ``` npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1" ``` 最后,在 `package.json` 中添加下列代码 ``` "husky":{ "hooks":{ "pre-commit": "lint-staged", "commint-msg": "commitlint -E HUSKY_GIT_PARAMS" } } ``` 至此,我们的代码提交规范以配置完毕,下面进行验证 #### 5.验证提交规范 先试用 `git add .` 把代码存放到暂存区, 在使用 `git cz` 命令提交 第一步,选择本次更新的类型 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696181571484.png) 第二步,选择本次修改的范围 (可选) ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696182727381.png) 第三步,针对本次提交改动写一个简短的描述 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696184049693.png) 第四步,针对本次提交改动写一个详细的描述 (可选),不填写可按回车跳过 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696226596454.png) 第五步,确认是否与某个未关闭的 issue 有关联,如果有输入 y ,按回车后填写具体的 issue, 没有的话回车跳过 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696227952191.png) 第六步,确认提交信息,确认无误,回车确认 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696228577275.png) 温馨提示: 提交代码之前,可以使用 `pnpm eslint` 命令检查一下代码格式 ### 四.element-plus #### 引入 element-plus 执行安装命令 ``` pnpm i element-plus pnpm i @element-plus/icons-vue pnpm i sass -D ``` 在 `main.ts` 中引入并挂载,全局注册 element-plus 的图标 ```javascript import { createApp } from 'vue' import ElementPlus from 'element-plus' import * as ElementPlusIconsVue from '@element-plus/icons-vue' const app = createApp(App) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } const app = createApp(App) app.use(ElementPlus).mount('#app') ``` 这里,我们使用插件,按需自动导入 element-plus 组件 首先,执行下列的命令安装插件 ``` pnpm i unplugin-vue-components unplugin-auto-import -D ``` 其次,在 `vite.config.ts` 文件夹先导入插件,然后在 `plugins` 中添加 ```javascript // 按需导入element-plus组件 import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }), ``` 使用 `button` 组件测试以下,就可以看到如图所示的结果 ![](C:\Users\260572.INTERNET\Desktop\文档\企业微信截图_16696840722829.png) #### 配置全局 scss 样式文件 在 路径`src/styles` 新建三个个文件夹 element.scss: 修改 elementPlus 的主题色 ```scss /* 只需要重写需要的即可 */ $--colors: ( 'primary': ( 'base': #0c3ca8 ), 'success': ( 'base': #67c23a ), 'warning': ( 'base': #e6a23c ), 'danger': ( 'base': #f56c6c ), 'error': ( 'base': #f56c6c ), 'info': ( 'base': #909399 ) ); @forward 'element-plus/theme-chalk/src/common/var.scss' with ( $colors: $--colors ); // 全量引入 @use 'element-plus/theme-chalk/src/index.scss' as *; ``` variables.module.scss: 定义自己的样式变量 ```scss $test-color: blue; ``` index.scss: 引入上面连个样式文件 ```scss @import './element.scss'; @import './variables.module.scss'; ``` 然后在 `vite` 中加入以下配置 ```javascript plugins: [ vue(), AutoImport({ resolvers: [ ElementPlusResolver({ importStyle: 'sass' }) ] }), Components({ dts: true, resolvers: [ ElementPlusResolver({ importStyle: 'sass', directives: true, version: '1.56.1' }) ] }), ElementPlus({ useSource: true }) ], css: { preprocessorOptions: { scss: { additionalData: `@use "@/styles/index.scss" as *;` } } }, ``` ### 五.路由 执行下列命令安装依赖 ``` pnpm i vue-router@4 ``` 在 `src` 新新建目录 `router` ,并新建 `index.ts` 文件, 内容如下: ```javascript import { RouteRecordRaw, createRouter, createWebHashHistory } from 'vue-router' const modules = import.meta.glob('../views/**/**.vue') const routes: RouteRecordRaw[] = [ { path: '/', name: 'Login', component: modules['../views/login/index.vue'] } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router // 原来的 import 路由懒加载在开发环境可行,在生产环境不可行,故改为上面 // import.meta.glob 形式 ``` 修改入口文件`main.ts` ```javascript import { createApp } from 'vue' import App from './App.vue' import ElementPlus from 'element-plus' import router from './router' import * as ElementPlusIconsVue from '@element-plus/icons-vue' const app = createApp(App) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.use(router).use(ElementPlus).mount('#app') ``` 注意: 在`App.vue` 中添加路由出口 至此,路由的基本配置已经完成,更多配置信息,详见官网:https://router.vuejs.org/zh/guide/ ### 六.统一封装请求 (axios) 执行下列命令安装依赖 ``` pnpm i axios pnpm i qs -D pnpm i @types/qs -D ``` 在 `src` 下新建目录 `utils`,并新建文件 `http.ts`,内容如下: ```javascript import axios, { AxiosResponse, AxiosRequestConfig } from 'axios' import qs from 'qs' /** * 业务自定义状态码 * 1000 请求成功 * 5000 重定向 * 5002 重定向+提示(token获取失败) * 5003 cookie中缺失appKey * 5004 用户被拉入黑名单 * 4003 未授权 */ // axios声明合并,在axios的配置项AxiosRequestConfig接口定义中自定义新值 declare module 'axios' { export interface AxiosRequestConfig { /** * @description 设置为false,表示请求错误是用户自定义处理(true)还是全局处理(false) */ customError?: boolean } } // 创建axios实例,此时的content-type已指定为json,如需使用form-data,请自行修改 const http = axios.create({ timeout: 10000, headers: { 'Content-Type': 'application/json;charset=UTF-8' }, // 表示跨域请求时是否需要使用凭证 withCredentials: true, validateStatus(status) { return status === 200 // 自定义状态码范围 }, paramsSerializer(params) { // 序列化请求参数,避免get请求参数出现[],&,空格等识别错误的问题 return qs.stringify(params, { arrayFormat: 'brackets' }) }, transformRequest: [ data => { // 转化为正常的json data = JSON.stringify(data) return data } ] }) // 请求拦截 http.interceptors.request.use( (config: AxiosRequestConfig) => { // do something return config }, (error: any) => { Promise.reject(error) } ) // 响应拦截 http.interceptors.response.use( async (response: AxiosResponse) => { return Promise.reject(response) }, (error: any) => { // do something return Promise.reject(error) } ) export default http ``` 在请求拦截和响应拦截根据自己的需求加以修,之后在发请求时,可以直接运用以上封装的工具函数. ### 七.状态管理 pinia 安装 ``` pnpm i pinia@next pnpm i pinia-plugin-persist 持久化插件 ``` 在 `src` 下新增 `store` 文件夹, 接着在 `store` 中新增 `index.ts` 文件,内容如下: ```javascript import type { App } from 'vue' import { createPinia } from 'pinia' import piniaPluginPersist from 'pinia-plugin-persist' const store = createPinia() store.use(piniaPluginPersist) //使用插件持久化 export function setupStore(app: App) { app.use(store) } export default store ``` 并在入口文件下 `main.ts` 中增加 ```javascript import store from './store' app.use(store) ``` `pinia` 基本已经配置完毕,如何使用可以参考官网: https://pinia.web3doc.top/introduction.html ### 八.vue3 中使用 echarts 图表 安装 ``` pnpm i echarts ``` 使用方式如下所示: ```vue ```