Vscode
: 前端人必备写码神器Chrome
:对开发者非常友好的浏览器 (反正我是很依赖它的)Nodejs
&npm
:配置本地开发环境,安装 Node 后你会发现 npm 也会一起安装下来Vue.js devtools
:浏览器调试插件Vue Language Features (Volar)
:Vscode 开发 vue3 必备插件,提供语法高亮提示,非常好用Vue 3 Snippets
:vue3 快捷输入
1. 使用 vite 快速创建脚手架
兼容性注意: Vite 需要
Node.js
版本>= 12.0.0
。
npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app — —template vue
yarn
yarn create vite my-vue-app —template vue
pnpm
pnpm create vite my-vue-app — —template vue
这里我采用 `yarn` 来安装
```bash
yarn create vite try-vite-vue-app -- --template vue-ts
第二步: cd
到项目文件夹, 安装依赖, 启动项目
# 进入项目文件夹
cd try-vite-vue-app
# 安装依赖
yarn
# 启动
yarn dev
2. Vite 常用基础配置
resolve.alias 配置文件引用路径别名
在我们项目开发过程中,会有很多嵌套层级的目录,所以要找到某个目录经常用相对路径../../..,层级一多就显得眼花缭乱,通过 alias 别名,我们可以快速地指定首层的目录,并且相比相对路径减少了路径索引的消耗,在性能上来说也是更优解。
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// 指定解析路径
import { resolve } from 'path'
const pathResolve = (dir: string) => resolve(__dirname, dir)
// 可以是一个对象
resolve: {
alias: {
'@': pathResolve('src'), // 设置 `@` 指向 `src` 目录
views: pathResolve('src/views'), // 设置 `views` 指向 `./src/views` 目录,下同
components: pathResolve('src/components'),
assets: pathResolve('src/assets')
}
},
// 也可以是一个 { find, replacement } 的数组
resolve: {
alias: [
// /@/xxxx => src/xxxx
{
find: /\/@\//,
replacement: pathResolve('src') + '/',
},
// /#/xxxx => types/xxxx
{
find: /\/#\//,
replacement: pathResolve('types') + '/',
},
],
},
指定解析路径使用的 path module 需要先安装nodejs的类型声明 @types/node
开发服务器选项 serve
当我们在没有任何配置的时候,在运行服务的时候,vite 是会自动跑在本地的3000端口,所以我们可以扩展下配置
server: {
port: 4000, // 设置服务启动端口号,如果端口已经被使用,Vite 会自动尝试下一个可用的端口
open: true, // boolean | string 设置服务启动时是否自动打开浏览器,当此值为字符串时,会被用作 URL 的路径名
cors: true, // 为开发服务器配置 CORS,配置为允许跨域
// 设置代理,根据我们项目实际情况配置
proxy: {
'/api': {
target: 'http://127.0.0.1:8000', // 后台服务地址
changeOrigin: true, // 是否允许不同源
secure: false, // 支持https
rewrite: path => path.replace(/^/api/, '')
}
}
}
构建选项 build
build: {
outDir: 'dist', // 指定打包路径,默认为项目根目录下的 dist 目录
terserOptions: {
compress: {
keep_infinity: true, // 防止 Infinity 被压缩成 1/0,这可能会导致 Chrome 上的性能问题
drop_console: true, // 生产环境去除 console
drop_debugger: true // 生产环境去除 debugger
},
},
chunkSizeWarningLimit: 1500 // chunk 大小警告的限制(以 kbs 为单位)
}
3. TypeScript 配置
3.1. tsconfig.json 配置项
在初始化 vite 项目的时候可以看到,项目根目录下生成了 tsconfig.json
和 tsconfig.node.json
两个文件。
tsconfig.json 指定了用来编译这个项目的根文件和编译选项
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
可以看到tsconfig.node.json
中的"include": ["vite.config.ts"]
表明这个单独拆分出来的配置文件只是负责编译 vite 的配置文件vite.config.ts
{
"compilerOptions": {
"composite": true,
"module": "esnext",
"moduleResolution": "node"
},
"include": ["vite.config.ts"]
}
include 指定需要编译的文件范围
默认是对 src 下的.ts、.d.ts、.tsx、.vue
结尾的文件都需要进行编译
exclude 配置不需要编译的文件范围
"exclude": ["node_modules","dist"]
references 将 TypeScript 程序拆分
属性是 TypeScript 3.0 的新特性,允许将 TypeScript 程序拆分结构化。这和我们写 vue 组件的思想有着异曲同工之妙,避免了在一个文件中处理过多的内容,而是通过拆分成多个文件,分别配置不同的部分,达到更加清晰,可维护性更高的目的。
compilerOptions 编译选项
skipLibCheck 忽略声明文件检查
忽略所有的声明文件( *.d.ts)的类型检查
"compilerOptions": {
"skipLibCheck": true
}
这个属性不但可以忽略 npm 不规范带来的报错,还能最大限度的支持类型系统。设置为 true 就不用怕使用的第三方库不规范了。
可能有人好奇,为什么要跳过这些第三方库的检查?
我们做类型检查(以及代码规范等)的目的是为了对团队内业务代码开发保持统一和规范,以保证开发成员之间的快速上手和后续维护。所以我们要做的是将各种规则集成到业务代码模块,而一些框架上的或者第三方库的内容就不用多此一举了。
baseUrl
作用:设置baseUrl
来告诉编译器到哪里去查找模块。所有非相对模块导入都会被当做相对于 baseUrl
。
注意相对模块的导入不会被设置的baseUrl
所影响,因为它们总是相对于导入它们的文件.
这个设置的作用和 vite 构建选项 build 中的 base 是类似的,我们配置为当前根目录即可
paths 路径映射列表
作用:模块名到基于baseUrl
的路径映射的列表。
请注意"paths"
是相对于"baseUrl"
进行解析。
在 vite 配置中设置了路径别名resolve.alias
,为了让编译 ts 时也能够解析对应的路径,我们还需要配置 paths 选项
"paths": {
"@/*": ["src/*"],
"views/*": ["src/views/*"],
"components/*": ["src/components/*"],
"assets/*": ["src/assets/*"],
"api/*": ["src/api/*"],
"utils/*": ["src/utils/*"],
}
isolatedModules 将每个文件作为单独模块
typescript 将没有导入/导出的文件视为旧脚本文件。因为这样的文件不是模块和它们在全局命名空间中合并的任何定义。该配置项会禁止此类文件。将任何导入或导出添加的文件都视为模块
这个设置在 vite 官方文档中是被要求应该设置为 true 的,但项目初始化的时候并没有默认加上这条
"isolatedModules": true,
https://vitejs.cn/guide/features.html#typescript-compiler-options
types 客户端类型
作用:添加要包含的类型声明文件名列表,只有在这里列出的模块的声明文件才会被加载进来
{
"compilerOptions": {
"types": ["vite/client"]
}
}
这将会提供以下类型定义补充:
- 资源导入 (例如:导入一个 .svg 文件)
- import.meta.env 上 Vite 注入的环境变量的类型定义
- import.meta.hot 上的 HMR API 类型定义
tsconfig.json
完整配置内容
{
"compilerOptions": {
"target": "esnext",
"isolatedModules": true,
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"skipLibCheck": false, // 忽略所有的声明文件( *.d.ts)的类型检查,跳过第三方库的类型检查
"lib": [
"esnext",
"dom"
],
"baseUrl": ".",
"types": [
"vite/client"
],
"paths": {
"@/": [
"src/"
]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules",
"dist"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
3.2. env.d.ts 全局类型声明
打开 src 文件夹下的 env.d.ts
文件,可以看到
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
请注意:三斜杠指令是包含单个XML标签的单行注释,注释的内容会做为编译器指令使用,只有在文件的最顶部才会生效,可以查看TypeScript: Documentation - Triple-Slash Directives学习相关内容。
所以这个文件的作用就呼之欲出了:帮助编译器识别类型。
TypeScript 相比 JavaScript 增加了类型声明。原则上,TypeScript 需要做到先声明后使用。这就导致开发者在调用很多原生接口(浏览器、Node.js)或者第三方模块的时候,因为某些全局变量或者对象的方法并没有声明过,导致编译器的类型检查失败。
当我们遇上Property xxx does not exist on type …报错的时候,就可以定位到是没有声明过这个方法/属性。我们就可以在这个文件作全局声明。
可以看到,该文件已经默认为所有的 vue 文件声明了 DefineComponent的组件类型,这就意味着只要我们的单文件组件使用
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
...
})
</script>
的写法,就能避免 vue 文件中大多数类型声明的报错,比如使用路由的this.$router、this.$route命令
eslint + prettier 约束代码风格
Eslint 支持
安装
# 1. eslint 安装
yarn add eslint --dev
# 2. typescript parser ESLint 默认使用的是 Espree 进行语法解析,所以无法对部分 typescript 语法进行解析,因此我么还需要安装 @typescript-eslint/parser 替换掉默认的解析器
yarn add @typescript-eslint/parser --dev
# 3. eslint 插件安装
# 借用这个 plugin 的能力才能让 eslint 识别 vue 文件
yarn add eslint-plugin-vue --dev
# eslint-plugin 作为 eslint 默认规则的补充,提供了一些额外的适用于 ts 语法的规则
yarn add @typescript-eslint/eslint-plugin --dev
注意: 如果 eslint
安装报错:
可以尝试运行以下命令:
yarn config set ignore-engines true
运行成功后再次执行 eslint
安装命令
1. 项目下新建 .eslintrc.js
配置
eslint
校验规则:
module.exports = {
root: true,
env: {
browser: true,
node: true,
es2021: true,
},
parser: 'vue-eslint-parser',
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
// eslint-config-prettier 的缩写
'prettier',
],
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
// eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'no-var': 'error',
'prettier/prettier': 'error',
// 禁止出现console
'no-console': 'warn',
// 禁用debugger
'no-debugger': 'warn',
// 禁止出现重复的 case 标签
'no-duplicate-case': 'warn',
// 禁止出现空语句块
'no-empty': 'warn',
// 禁止不必要的括号
'no-extra-parens': 'off',
// 禁止对 function 声明重新赋值
'no-func-assign': 'warn',
// 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
'no-unreachable': 'warn',
// 强制所有控制语句使用一致的括号风格
curly: 'warn',
// 要求 switch 语句中有 default 分支
'default-case': 'warn',
// 强制尽可能地使用点号
'dot-notation': 'warn',
// 要求使用 === 和 !==
eqeqeq: 'warn',
// 禁止 if 语句中 return 语句之后有 else 块
'no-else-return': 'warn',
// 禁止出现空函数
'no-empty-function': 'warn',
// 禁用不必要的嵌套块
'no-lone-blocks': 'warn',
// 禁止使用多个空格
'no-multi-spaces': 'warn',
// 禁止多次声明同一变量
'no-redeclare': 'warn',
// 禁止在 return 语句中使用赋值语句
'no-return-assign': 'warn',
// 禁用不必要的 return await
'no-return-await': 'warn',
// 禁止自我赋值
'no-self-assign': 'warn',
// 禁止自身比较
'no-self-compare': 'warn',
// 禁止不必要的 catch 子句
'no-useless-catch': 'warn',
// 禁止多余的 return 语句
'no-useless-return': 'warn',
// 禁止变量声明与外层作用域的变量同名
'no-shadow': 'off',
// 允许delete变量
'no-delete-var': 'off',
// 强制数组方括号中使用一致的空格
'array-bracket-spacing': 'warn',
// 强制在代码块中使用一致的大括号风格
'brace-style': 'warn',
// 强制使用骆驼拼写法命名约定
camelcase: 'warn',
// 强制使用一致的缩进
indent: 'off',
// 强制在 JSX 属性中一致地使用双引号或单引号
// 'jsx-quotes': 'warn',
// 强制可嵌套的块的最大深度4
'max-depth': 'warn',
// 强制最大行数 300
// "max-lines": ["warn", { "max": 1200 }],
// 强制函数最大代码行数 50
// 'max-lines-per-function': ['warn', { max: 70 }],
// 强制函数块最多允许的的语句数量20
'max-statements': ['warn', 100],
// 强制回调函数最大嵌套深度
'max-nested-callbacks': ['warn', 3],
// 强制函数定义中最多允许的参数数量
'max-params': ['warn', 3],
// 强制每一行中所允许的最大语句数量
'max-statements-per-line': ['warn', { max: 1 }],
// 要求方法链中每个调用都有一个换行符
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }],
// 禁止 if 作为唯一的语句出现在 else 语句中
'no-lonely-if': 'warn',
// 禁止空格和 tab 的混合缩进
'no-mixed-spaces-and-tabs': 'warn',
// 禁止出现多行空行
'no-multiple-empty-lines': 'warn',
// 禁止出现;
semi: ['warn', 'never'],
// 强制在块之前使用一致的空格
'space-before-blocks': 'warn',
// 强制在 function的左括号之前使用一致的空格
// 'space-before-function-paren': ['warn', 'never'],
// 强制在圆括号内使用一致的空格
'space-in-parens': 'warn',
// 要求操作符周围有空格
'space-infix-ops': 'warn',
// 强制在一元操作符前后使用一致的空格
'space-unary-ops': 'warn',
// 强制在注释中 // 或 /* 使用一致的空格
// "spaced-comment": "warn",
// 强制在 switch 的冒号左右有空格
'switch-colon-spacing': 'warn',
// 强制箭头函数的箭头前后使用一致的空格
'arrow-spacing': 'warn',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-useless-escape': 'warn',
'no-irregular-whitespace': 'warn',
'no-prototype-builtins': 'warn',
'no-fallthrough': 'warn',
'no-extra-boolean-cast': 'warn',
'no-case-declarations': 'warn',
'no-async-promise-executor': 'warn',
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
}
env 预定义的环境变量
作用:提供预定义的环境变量。
因为node 或者浏览器中的全局变量很多,如果我们一个个声明会显得繁琐,因此就需要用到env,这是对环境定义的一组全局变量的预设。
env: {
browser: true,
es2021: true, // 添加所有 ECMAScript 2021 全局变量并自动将 ecmaVersion 解析器选项设置为 12
node: true,
},
parser 指定要使用的解析器
作用:指定要使用的解析器。我们指定为vue-eslint-parser即可
parser: 'vue-eslint-parser',
parserOptions 解析器配置
作用:给解析器传入一些其他的配置参数
比如我们之前安装的@typescript-eslint/parser
就可以在这里进行配置
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: "latest", // 支持的es版本
sourceType: 'module', // 代模块类型,默认为script,我们设置为module
},
extends 使用预设配置
作用:使用预设的 lint 包
如果要我们自己去设置各个规则未免会显得繁琐,所以可以直接使用业界的最佳实践作为基础规则
extends: [
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended'
],
plugins 增强 ESlint 功能
作用:增强 ESlint 功能
还记得我们最开始安装的@typescript-eslint/eslint-plugin
吗?它就是用来给 eslint 提供一些额外的适用于 ts 语法的规则插件名中的 eslint-plugin-
可以省略:
// eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写
plugins: ["vue", "@typescript-eslint", "prettier"],
rules 自定义规则
作用:创建自定义规则。
规则定义值:
- off 或 0 - 关闭规则
- warn 或 1 - 开启规则, 使用警告 程序不会退出
- error 或 2 - 开启规则, 使用错误 程序退出
虽然我们通过 extends 引入了行业内最佳实践的一些规则,但是每个团队还是有每个团队自己的开发习惯,所以我们可以通过 rules 添加或者修改 extends 中的规则。
2. 项目下新建 .eslintignore
# eslint 忽略检查 (根据项目需要自行添加)
node_modules
dist
prettier 支持
# 安装 prettier
yarn add prettier --dev
解决 eslint 和 prettier 冲突
当 ESLint 的规则和 Prettier 的规则相冲突时,就会发现一个尴尬的问题,用其中一种来格式化代码,另一种就会报错。
prettier 官方提供了一款工具 eslint-config-prettier 来解决 ESLint
中的样式规范和 prettier
中样式规范的冲突
,以 prettier
的样式规范为准
,使 ESLint 中的样式规范自动失效
# 安装插件 eslint-config-prettier
yarn add eslint-config-prettier --dev
上面介绍的工具,仅仅只是将部分 ESLint 规则给禁用了,避免 Prettier 格式化之后的代码导致 ESLint 报错而已,如何将两者结合起来使用呢?
prettier 官方提供了一个 ESLint 插件 eslint-plugin-prettier ,这个插件的主要作用就是将 prettier 作为 ESLint 的规则来使用,相当于代码不符合 Prettier 的标准时,会报一个 ESLint 错误,同时也可以通过 eslint —fix 来进行格式化
yarn add eslint-plugin-prettier --dev
项目下新建 .prettierrc.js
配置
prettier
格式化规则:
module.exports = {
printWidth: 100, // 超过最大值换行
tabWidth: 2, // 缩进字节数
useTabs: false, // 缩进不使用tab,使用空格
semi: false, // 末尾不加尾号
singleQuote: true, // 默认单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在jsx中使用单引号代替双引号
trailingComma: 'none', // es5对象属性最后加逗号。none不加
bracketSpacing: true, // 在对象,数组括号与文字之间加空格
jsxBracketSameLine: false, // 在jsx中把'>' 是否单独放一行
arrowParens: 'always', // 箭头函数参数只有一个时是否要有小括号
htmlWhitespaceSensitivity: 'ignore', // HTML空白灵敏度,空格被认为是不敏感的
vueIndentScriptAndStyle: false, // script、style标签不缩进
endOfLine: 'auto',
// 覆写默认配置,为某些特定文件制定特定配置
overrides: [
{
files: '*.json',
options: {
printWidth: 200
}
}
]
}
package.json 配置命令
{
"script": {
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write ."
}
}
上面配置完成后, 可以运行以下命令
测试下代码检查个格式化
效果:
# eslint 检查
yarn lint
# prettier 自动格式化
yarn prettier
配置 husky + lint-staged
使用
husky
+lint-staged
助力团队编码规范, husky&lint-staged 安装推荐使用mrm
, 它将根据package.json
依赖项中的代码质量工具来安装和配置 husky 和 lint-staged,因此请确保在此之前安装并配置所有代码质量工具,如Prettier 和 ESlint
配置 css 预处理器 less
虽然
vite
原生支持less/sass/scss/stylus
,但是你必须手动安装他们的预处理器依赖
安装
yarn add -D less
yarn add --dev less-loader
配置全局 less 样式文件
在 src/
下新增 styles
文件夹,用于存放全局样式文件
新建 main.less
, 设置一个颜色变量
:
@primary-color: #1890ff;
如何将这个全局样式文件全局注入
到项目中呢?配置 Vite
即可:
css: {
preprocessorOptions: {
less: {
additionalData: '@import "@/styles/main.less";', // 没有 resolve.alias 别名的话 路径为./src/styles/main.less
},
},
},
组件中使用
<style scoped lang="less">
a {
color: @primary-color;
}
</style>
stylelint 规范 css 的书写风格
安装
- stylelint — 运行工具,
- stylelint-config-standard — stylelint的推荐配置
- stylelint-order — 排序插件(先写定位,再写盒模型,再写内容区样式,最后写 CSS3 相关属性)
- stylelint-config-prettier 关闭所有不必要的或可能与Prettier冲突的规则
yarn add stylelint --dev
yarn add stylelint-config-prettier stylelint-config-recommended stylelint-config-standard stylelint-config-html --dev
官方提供了stylelint-config-recommended和stylelint-config-standard两种css标准:
stylelint-config-recommended包含可能报错的rule,code format的css标准
stylelint-config-standard继承于recommend,一些常见的css书写标准
Stylelint 14+ 不再包含 Scss,Sass,Less 或者 SugarSS 等预编译器的解析了,所以我们可以通过 extends 引入公共规则
"extends": ["stylelint-config-standard", 'stylelint-config-prettier'],
为了让 stylelint 能够读 vue (.html, .xml, .svelte, .vue 等)文件,我们还需要安装postcss-html
yarn add postcss-html --dev
"customSyntax": "postcss-html"
stylelint-order 是CSS属性排序插件,并且每个规则都支持自动修复(stylelint —fix)
yarn add stylelint-order --dev
package.json 配置命令
"stylelint": "npx stylelint --aei .vue src",
"stylint:fix": "npx stylelint ./src/**/*.vue --fix"
项目下新建 stylelint.config.js
项目下新建 .stylelintignore
.stylelintignore 用来配置不需要通过 stylelint 约束的文件
# 其他类型文件
*.js
*.ts
*.jpg
*.woff
# 测试和打包目录
/dist/*
/public/*
public/*
/node_modules/
路由 vue-router@4
# 安装路由
yarn add vue-router@4
在 src
文件下新增 router
文件夹 => index.ts
文件, 内容如下:
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
const basicRouters: RouteRecordRaw[] = [
{
path: '/',
name: 'Root',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/login/Index.vue'),
}
]
const router = createRouter({
history: createWebHistory(),
routes: basicRouters,
})
export default router
修改入口文件 mian.ts
:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app = createApp(App)
app.use(router)
app.mount('#app')
vue-router4.x
支持 typescript
,配置路由的类型是 RouteRecordRaw
,这里 meta
可以让我们有更多的发挥空间,这里提供一些参考:
title
:string
; 页面标题,通常必选。icon?
:string
; 图标,一般配合菜单使用。auth?
:boolean
; 是否需要登录权限。ignoreAuth?
:boolean
; 是否忽略权限。roles?
:RoleEnum[]
; 可以访问的角色keepAlive?
:boolean
; 是否开启页面缓存hideMenu?
:boolean
; 有些路由我们并不想在菜单中显示,比如某些编辑页面。order?
:number
; 菜单排序。frameUrl?
:string
; 嵌套外链。
这里只提供一些思路,每个项目涉及到的业务都会存在些差异,这里就不作详细讲解了,根据自己业务需求做配置即可。
axios 统一请求封装
# 安装 axios
yarn add axios
# 安装 nprogress 用于请求 loading
# 也可以根据项目需求自定义其它 loading
yarn add nprogress
# 类型声明,或者添加一个包含 `declare module 'nprogress'
yarn add @types/nprogress --dev
实际使用中可以根据项目修改,比如RESTful
api
中可以自行添加put
和delete
请求,ResType
也可以根据后端的通用返回值动态的去修改
新增 service
文件夹,service
下新增 http.ts
文件以及 api
文件夹:
http.ts
: 用于axios
封装
import axios, { AxiosRequestConfig } from 'axios'
import NProgress from 'nprogress'
// 设置请求头和请求路径
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) => {
NProgress.start()
axios
.get(url, { params })
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
reject(err.data)
})
})
},
post(url, params) {
return new Promise((resolve, reject) => {
NProgress.start()
axios
.post(url, JSON.stringify(params))
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
reject(err.data)
})
})
},
upload(url, file) {
return new Promise((resolve, reject) => {
NProgress.start()
axios
.post(url, file, {
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
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
除了自己手动封装 axios , 这里还推荐一个 vue3 的请求库: VueRequest
, 非常好用, 下面来看看 VueRequest
有哪些比较好用的功能吧!!!
- 🚀 所有数据都具有响应式
- 🔄 轮询请求
- 🤖 自动处理错误重试
- 🗄 内置请求缓存
- 💧 节流请求与防抖请求
- 🎯 聚焦页面时自动重新请求
- ⚙️ 强大的分页扩展以及加载更多扩展
- 📠 完全使用 Typescript 编写,具有强大的类型提示
- ⚡️ 兼容 Vite
- 🍃 轻量化
- 📦 开箱即用
官网链接: https://www.attojs.com/
状态管理 pinia
由于 vuex 4 对 typescript 的支持让人感到难过,所以状态管理弃用了 vuex 而采取了 pinia. pinia 的作者是 Vue 核心团队成员
安装 pinia
Pinia 与 Vuex 的区别:
id
是必要的,它将所使用 store 连接到 devtools。- 创建方式:
new Vuex.Store(...)
(vuex3),createStore(...)
(vuex4)。 - 对比于 vuex3 ,state 现在是一个
函数返回对象
。 - 没有
mutations
,不用担心,state 的变化依然记录在 devtools 中。
# 安装 yarn add pinia@next
main.ts 中增加
# 引入 import {createPinia} from "pinia" # 创建根存储库并将其传递给应用程序 app.use(createPinia())
在 src
文件夹下新增 store
文件夹, 接在在 store 中新增 main.ts
创建 store
, mian.ts :
`import {defineStore} from ‘pinia’
export const useMainStore = defineStore({
id: ‘mian’,
state: () =>({
name: ‘超级管理员’
})
})
`
组建中获取 store :
<br /> <br />
getters 用法介绍
Pinia 中的 getter 与 Vuex 中的 getter 、组件中的计算属性具有相同的功能
store
=> mian.ts
`import {defineStore} from ‘pinia’
export const useMainStore = defineStore({
id: ‘mian’,
state: () => ({
name: ‘超级管理员’,
}),
// getters
getters: {
nameLength: (state) => state.name.length,
}
})
`
组件中使用:
`