[Vue3+TS project] Silicon Valley selection day02--background management system template construction/project configuration

1 Project initialization

A project must have a unified specification, we need to use eslint+stylelint+prettier to detect and repair our code quality , we need to use husky to do commit interception , we need to use commitlint to unify the submission specification, we need to use preinstall to unify the package management tools .

1.1 Environment preparation

  • node v16.14.2

  • pnpm 8.0.0

1.2 Initialize the project

This project uses vite to build, vite official Chinese document reference: cn.vitejs.dev/guide/

pnpm: performant npm, meaning " high-performance npm ". Derived from npm/yarn, pnpm solves potential bugs inside npm/yarn, greatly optimizes performance, and expands usage scenarios. Touted as "the most advanced package management tool"

pnpm installation instructions:

npm i -g pnpm

Project initialization command:

pnpm create vite

Enter the project root directory pnpm install to install all dependencies, and run the program after installing the dependencies: pnpm run dev

After running, the project runs at http://127.0.0.1:5173/ , you can visit your project

Problems that may arise

 Cannot find module './App.vue' or its corresponding type declarations

Reason for error: typescript can only understand .ts files, but not .vue files

Solution 1: Install the volar plugin , enter volar, there are multiple extensions, the one that works is Typescript Vue Plugin (Volar)

Before vscode detected vue3, it automatically recommended to install the Vue Language Feature (Volar), but it threw a type error. It is officially recommended to disable Vetur when using it to avoid conflicts.

Solution 2: After creating the vite project, there will be an "env.d.ts" file in the root directory of the project, find the file, and add some code in it

declare module "*.vue" {
  import { DefineComponent } from "vue"
  const component: DefineComponent<{}, {}, any>
  export default component
}

Small Tip: The browser automatically opens to improve efficiency:

Add to the package.json file--open

"scripts": {
  "dev": "vite --open",
  "build": "vue-tsc && vite build",
  "preview": "vite preview"
},

Found this doesn't work. . . . (You can refer to the automatic opening browser configuration of my Vue2 project)

2 project configuration

One, eslint configuration

eslint Chinese official website: ESLint - Pluggable JavaScript linter - ESLint Chinese

ESLint was originally an open source project created by  Nicholas C. Zakas in June 2013. Its goal is to provide a plug-in javascript code detection tool

First install eslint

pnpm i eslint -D

Generate configuration file: .eslint.cjs

npx eslint --init

.eslint.cjs configuration file

module.exports = {
   // 运行环境
    "env": { 
        "browser": true,// 浏览器端
        "es2021": true,// es2021
    },
    //规则继承
    "extends": [ 
       //全部规则默认是关闭的,这个配置项开启推荐规则,推荐规则参照文档
       //比如:函数不能重名、对象不能出现重复key
        "eslint:recommended",
        //vue3语法规则
        "plugin:vue/vue3-essential",
        //ts语法规则
        "plugin:@typescript-eslint/recommended"
    ],
    //要为特定类型的文件指定处理器
    "overrides": [
    ],
    //指定解析器:解析器
    //Esprima 默认解析器
    //Babel-ESLint babel解析器
    //@typescript-eslint/parser ts解析器
    "parser": "@typescript-eslint/parser",
    //指定解析器选项
    "parserOptions": {
        "ecmaVersion": "latest",//校验ECMA最新版本
        "sourceType": "module"//设置为"script"(默认),或者"module"代码在ECMAScript模块中
    },
    //ESLint支持使用第三方插件。在使用插件之前,您必须使用npm安装它
    //该eslint-plugin-前缀可以从插件名称被省略
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    //eslint规则--最重要,需要看官网配置
    "rules": {
    }
}

1.1 Vue3 environment code verification plug-in

# 让所有与prettier规则存在冲突的Eslint rules失效,并使用prettier进行代码检查
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
# 运行更漂亮的Eslint,使prettier规则优先级更高,Eslint优先级低
"eslint-plugin-prettier": "^4.2.1",
# vue.js的Eslint插件(查找vue语法错误,发现错误指令,查找违规风格指南
"eslint-plugin-vue": "^9.9.0",
# 该解析器允许使用Eslint校验所有babel code
"@babel/eslint-parser": "^7.19.1",

installation instructions

pnpm install -D eslint-plugin-import eslint-plugin-vue eslint-plugin-node eslint-plugin-prettier eslint-config-prettier eslint-plugin-node @babel/eslint-parser

1.2 Modify the .eslintrc.cjs configuration file

// @see https://eslint.bootcss.com/docs/rules/
​
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
    jest: true,
  },
  /* 指定如何解析语法 */
  parser: 'vue-eslint-parser',
  /** 优先级低于 parse 的语法解析配置 */
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    parser: '@typescript-eslint/parser',
    jsxPragma: 'React',
    ecmaFeatures: {
      jsx: true,
    },
  },
  /* 继承已有的规则 */
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  plugins: ['vue', '@typescript-eslint'],
  /*
   * "off" 或 0    ==>  关闭规则
   * "warn" 或 1   ==>  打开的规则作为警告(不影响代码执行)
   * "error" 或 2  ==>  规则作为一个错误(代码不能执行,界面报错)
   */
  rules: {
    // eslint(https://eslint.bootcss.com/docs/rules/)
    'no-var': 'error', // 要求使用 let 或 const 而不是 var
    'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-unexpected-multiline': 'error', // 禁止空余的多行
    'no-useless-escape': 'off', // 禁止不必要的转义字符
​
    // typeScript (https://typescript-eslint.io/rules)
    '@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
    '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
    '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
    '@typescript-eslint/semi': 'off',
​
    // eslint-plugin-vue (https://eslint.vuejs.org/rules/)
    'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
    'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
    'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
    'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
  },
}

1.3 .eslintignore ignore files

dist
node_modules

1.4 Running the script

package.json adds two running scripts

"scripts": {
    "lint": "eslint src", //校验
    "fix": "eslint src --fix", //修复
}

Two, configure prettier

With eslint, why do you need prettier? eslint is aimed at javascript, which is a detection tool, including js syntax and a small number of format issues. In eslint's view, correct syntax can ensure the normal operation of the code, and format issues are second;

And prettier is a formatting tool . It can't understand that the format is not uniform, so it continues to do what eslint didn't do well. In addition, prettier supports

Multiple languages ​​including js.

To sum up, the two brothers eslint and prettier guarantee the quality of the js code and the beauty of the code.

2.1 Install dependent packages

pnpm install -D eslint-plugin-prettier prettier eslint-config-prettier

2.2 Add rules to .prettierrc.json

{
  "singleQuote": true,
  "semi": false,
  "bracketSpacing": true,
  "htmlWhitespaceSensitivity": "ignore",
  "endOfLine": "auto",
  "trailingComma": "all",
  "tabWidth": 2
}

2.3 .prettierignore ignore files

/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*

Use  pnpm run lint to check the grammar, if there is an irregular format, modify it through pnpm run fix

Three, configure stylelint

stylelint is a lint tool for css. It can format css code, check css syntax errors and unreasonable writing, specify css writing order, etc.

We use scss as a preprocessor in our project and install the following dependencies:

pnpm add sass sass-loader stylelint postcss postcss-scss postcss-html stylelint-config-prettier stylelint-config-recess-order stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order stylelint-config-standard-scss -D

3.1  .stylelintrc.cjsConfiguration file

Official Website: Home | Stylelint Chinese Documentation | Stylelint Chinese Website

// @see https://stylelint.bootcss.com/
​
module.exports = {
  extends: [
    'stylelint-config-standard', // 配置stylelint拓展插件
    'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化
    'stylelint-config-standard-scss', // 配置stylelint scss插件
    'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
    'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件,
    'stylelint-config-prettier', // 配置stylelint和prettier兼容
  ],
  overrides: [
    {
      files: ['**/*.(scss|css|vue|html)'],
      customSyntax: 'postcss-scss',
    },
    {
      files: ['**/*.(html|vue)'],
      customSyntax: 'postcss-html',
    },
  ],
  ignoreFiles: [
    '**/*.js',
    '**/*.jsx',
    '**/*.tsx',
    '**/*.ts',
    '**/*.json',
    '**/*.md',
    '**/*.yaml',
  ],
  /**
   * null  => 关闭该规则
   * always => 必须
   */
  rules: {
    'value-keyword-case': null, // 在 css 中使用 v-bind,不报错
    'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
    'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
    'no-empty-source': null, // 关闭禁止空源码
    'selector-class-pattern': null, // 关闭强制选择器类名的格式
    'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
    'block-opening-brace-space-before': 'always', //大括号之前必须有一个空格或不能有空白符
    'value-no-vendor-prefix': null, // 关闭 属性值前缀 --webkit-box
    'property-no-vendor-prefix': null, // 关闭 属性前缀 -webkit-mask
    'selector-pseudo-class-no-unknown': [
      // 不允许未知的选择器
      true,
      {
        ignorePseudoClasses: ['global', 'v-deep', 'deep'], // 忽略属性,修改element默认样式的时候能使用到
      },
    ],
  },
}

3.2 .stylelintignore ignore files

/node_modules/*
/dist/*
/html/*
/public/*

3.3 Running the script

"scripts": {
    "lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
}

Finally configure a unified prettier to format our js and css, html code

 "scripts": {
    "dev": "vite --open",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint src",
    "fix": "eslint src --fix",
    -"format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\"",
    -"lint:eslint": "eslint src/**/*.{ts,vue} --cache --fix",
    -"lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
  },

When we run pnpm run format , the code will be formatted directly

According to my understanding, if the company has a mature code style in future work projects, then we configure it according to the company's code style, which can ensure a unified style and improve efficiency. Configure it to be available for life.

Fourth, configure husky

We have integrated our code verification tool above, but we need to manually execute the command every time to format our code. If someone submits to the remote repository without formatting, then this specification is useless. So we need to force developers to submit according to code specifications.

To do this, we need to use husky to trigger the git hook (the hook of git on the client side) before the code is submitted , and then execute pnpm run format  to automatically format our code.

Install husky

pnpm install -D husky

implement

You need to initialize the warehouse with git first

npx husky-init

A .husky directory will be generated under the root directory, and there will be a pre-commit file under this directory . The commands in this file will be executed when we execute commit

.husky/pre-commitAdd the following command to the file:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm run format //关键

When we commit the code, the command will be executed, the code will be formatted, and then submitted.

Five, configure commitlint

For our commit information, there is also a unified specification, which cannot be written casually. To make everyone implement it according to the unified standard, we can use commitlint to achieve it.

Installation package

pnpm add @commitlint/config-conventional @commitlint/cli -D

Add a configuration file, create a new one commitlint.config.cjs(note that it is cjs), and then add the following code:

module.exports = {
  extends: ['@commitlint/config-conventional'],
  // 校验规则
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'docs',
        'style',
        'refactor',
        'perf',
        'test',
        'chore',
        'revert',
        'build',
      ],
    ],
    'type-case': [0],
    'type-empty': [0],
    'scope-empty': [0],
    'scope-case': [0],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [0, 'always', 72],
  },
}

package.jsonConfigure the scripts command in

# 在scrips中添加下面的代码
{
"scripts": {
    "commitlint": "commitlint --config commitlint.config.cjs -e -V"
  },
}

The configuration is over, now when we fill in committhe information, we need to bring the followingsubject

'feat',//新特性、新功能
'fix',//修改bug
'docs',//文档修改
'style',//代码格式修改, 注意不是 css 修改
'refactor',//代码重构
'perf',//优化相关,比如提升性能、体验
'test',//测试用例修改
'chore',//其他修改, 比如改变构建流程、或者增加依赖库、工具等
'revert',//回滚到上一个版本
'build',//编译相关的修改,例如发布版本、对项目构建或者依赖的改动

configure husky

npx husky add .husky/commit-msg 

Add the following command to the generated commit-msg file

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm commitlint

When we commit the submission information, we can no longer write it at will. It must be git commit -m 'fix: xxx' that meets the type. It should be noted that the type needs to be followed by English:, and the colon needs to be empty One grid, this cannot be omitted

6. Mandatory use of the pnpm package manager tool

When a team develops a project, it is necessary to unify the package manager tool, because different package manager tools download the same dependency, and the version may be different.

It leads to bug problems in the project, so the package manager tool needs to be managed uniformly! ! !

Create scritps/preinstall.jsa file in the root directory and add the following content

if (!/pnpm/.test(process.env.npm_execpath || '')) {
  console.warn(
    `\u001b[33mThis repository must using pnpm as the package manager ` +
    ` for scripts to work properly.\u001b[39m\n`,
  )
  process.exit(1)
}

configuration command

"scripts": {
    "preinstall": "node ./scripts/preinstall.js"
}

When we use npm or yarn to install packages, an error will be reported. The principle is that the code in the file preinstall (the life cycle hook provided by npm) will be triggered during the install.

3 Project Integration

3.1 Integrating element-plus

Silicon Valley selects the operation platform, and the UI component library uses element-plus , so the element-plus plug-in needs to be integrated! ! !

Official website address: A Vue 3 UI framework | Element Plus

@element-plus/icons-vue: is an icon component library, often used

pnpm install element-plus @element-plus/icons-vue

The entry file main.ts installs element-plus globally, and the default language supported by element-plus is English and Chinese

import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
//@ts-ignore  忽略当前文件ts类型的检测否则有红色提示(打包会失败)
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {
    locale: zhCn
})

 

Element Plus global component type declaration---can be ignored

// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["element-plus/global"]
  }
}

After configuration, you can test the use of element-plus components and icons.

3.2 Configuration of src alias

When developing a project, the relationship between files and files may be complicated, so we need to configure an alias for the src folder! ! !

// vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
--import path from 'path'
export default defineConfig({
    plugins: [vue()],
    resolve: {
        alias: {
            "@": path.resolve("./src") // 相对路径别名配置,使用 @ 代替 src
        }
    }
})

TypeScript compilation configuration

// tsconfig.json
{
  "compilerOptions": {
    --"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
    --"paths": { //路径映射,相对于baseUrl
      "@/*": ["src/*"] 
    }
  }
}

If the subcomponents introduced in vue3 are not used, there may be a red line prompt, which does not affect the operation. To get rid of it you can disable the plugin Vetur.

3.3 Configuration of environment variables

During the project development process, it will go through at least three stages: development environment , test environment and production environment (that is, formal environment). The states of requests in different stages (such as interface addresses, etc.) are not the same, and it is quite cumbersome and error-prone to manually switch the interface address. Therefore, the need for environment variable configuration came into being. We only need to do simple configuration and leave the work of environment state switching to the code .

As the name implies, the development environment (development) is an environment for development and use. Each developer works on his own dev branch. When the development reaches a certain level, colleagues will merge the code and conduct joint debugging.

The testing environment (testing) is the environment in which colleagues work, usually deployed by the test colleagues themselves, and then tested in this environment

Production environment (production) The production environment refers to the formal provision of external services. Generally, the error report will be turned off and the error log will be turned on. (The environment officially provided to customers.)

Note: In general, an environment corresponds to a server, and some companies have a development and test environment that is a server! ! !

Add files for development, production, and test environments to the root directory of the project!

.env.development
.env.production
.env.test

document content

# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'development'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/api'


NODE_ENV = 'production'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/prod-api'


# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'test'
VITE_APP_TITLE = '硅谷甄选运营平台'
VITE_APP_BASE_API = '/test-api'

Configuration run command: package.json

 "scripts": {
    "dev": "vite --open",
    "build:test": "vue-tsc && vite build --mode test",
    "build:pro": "vue-tsc && vite build --mode production",
    "preview": "vite preview"
  },

Get environment variables through import.meta.env

//import.meta.env获取环境变量--任何组件都可以使用
console.log(import.meta.env)
// 比如后面的api接口会使用到这里的基础路径

3.4 SVG icon configuration

SVG vector graphics are often used when developing projects, and after we use SVG, image resources are no longer loaded on the page.

This is a great improvement in page performance, and our SVG file is much smaller than img, and it hardly takes up resources in the project.

Install the SVG dependency plugin

pnpm install vite-plugin-svg-icons -D

vite.config.tsConfigure the plugin in

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {
  return {
    plugins: [
      createSvgIconsPlugin({
        // Specify the icon folder to be cached
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        // Specify symbolId format
        symbolId: 'icon-[dir]-[name]',
      }),
    ],
  }
}

Entry file import

import 'virtual:svg-icons-register'

Easy to use in any component

Create a new icons folder in src/assets, which stores the required svg icons

<!-- svg:图标外层容器,内部需要use标签结合使用 -->
<svg>
  <!-- xlink:href执行用哪一个图标,属性值必须加上 #icon-图标名字 -->
  <use xlink:href="#icon-apple" fill="red"></use>
</svg>

3.4.1 svg is packaged as a global component

Because many modules of the project need to use icons, it is packaged as a global component! ! !

Create a SvgIcon component in the src/components directory: the representation is as follows

<template>
  <div>
    <svg :style="{ width: width, height: height }">
      <use :xlink:href="prefix + name" :fill="color"></use>
    </svg>
  </div>
</template>
​
<script setup lang="ts">
defineProps({
  //xlink:href属性值的前缀
  prefix: {
    type: String,
    default: '#icon-'
  },
  //svg矢量图的名字
  name: String,
  //svg图标的颜色
  color: {
    type: String,
    default: ""
  },
  //svg宽度
  width: {
    type: String,
    default: '16px'
  },
  //svg高度
  height: {
    type: String,
    default: '16px'
  }
​
})
</script>
<style scoped></style>

Create an index.ts file in the src folder directory: used to register all global components inside the components folder! ! !

If you register global components directly in the entry file, 100 will have to be written a hundred times, which is too much. through custom plugins

// 引入项目中全部的全局组件
import SvgIcon from '@/components/SvgIcon/index.vue';
​
// 全局组件的对象
const allGlobalComponents = { SvgIcon: SvgIcon };
// 对外暴露一个插件对象
export default {
    install(app) {
        Object.keys(allGlobalComponents).forEach((key) => {
            app.component(key, allGlobalComponents[key]);
        })
    }
}
Introduce the src/index.ts file in the entry file, and install the custom plug-in through the app.use method
// 引入自定义插件对象:注册全局组件
import globalComponent from '@/components/index.ts'
// 安装自定义插件
app.use(globalComponent)

3.5 Integrated sass

We can already use the scss style inside the component, because the sass sass-loader has been installed in the project when configuring the styleLint tool, so we can use the scss syntax in the component! ! ! Need to add lang="scss"

<style scoped lang="scss"></style>

Next we add some global styles to the project

Create an index.scss file in the src/style directory . Of course, the project needs to clear the default style, so introduce reset.scss in index.scss. The styles in reset.scss are available in npm.

@import './reset.scss'

Introduced in the entry file

// 引入全局样式
import '@/style/index.scss'

But you will find that there is no way to use variables in the src/styles/index.scss global style file . Therefore, global variables need to be introduced into the project.

Create a variable.scss file at style/variable.scss!

The configuration in the vite.config.ts file is as follows:

export default defineConfig((config) => {
    css: {
      preprocessorOptions: {
        scss: {
          javascriptEnabled: true,
          additionalData: '@import "./src/styles/variable.scss";',
        },
      },
    },
}

@import "./src/styles/variable.less";;Don't forget the latter , or you will report an error !

After configuration, you will find that these global variables provided by scss can be used in component styles! ! !

3.6 mock data

Installation dependency: vite-plugin-mock - npm

Pay attention to the version of vite-plugin-mock, the latest version 3.0.0 will report an error, it is recommended to install 2.9.6

Argument of type '{ localEnabled: boolean; }' is not assignable to parameter of type 'ViteMockOptions'. Object literal may only specify known properties, and 'localEnabled' does not exist in type 'ViteMockOptions'.

 

pnpm install -D [email protected] mockjs

Enable the plugin in the vite.config.js configuration file.

import { UserConfigExport, ConfigEnv } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'
export default ({ command })=> {
  return {
    plugins: [
      vue(),
      viteMockServe({
        localEnabled: command === 'serve',
      }),
    ],
  }
}

Create a mock folder in the root directory: to create the mock data and interface we need! ! !

Create a user.ts file inside the mock folder

//用户信息数据
function createUserList() {
    return [
        {
            userId: 1,
            avatar:
                'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
            username: 'admin',
            password: '111111',
            desc: '平台管理员',
            roles: ['平台管理员'],
            buttons: ['cuser.detail'],
            routes: ['home'],
            token: 'Admin Token',
        },
        {
            userId: 2,
            avatar:
                'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
            username: 'system',
            password: '111111',
            desc: '系统管理员',
            roles: ['系统管理员'],
            buttons: ['cuser.detail', 'cuser.user'],
            routes: ['home'],
            token: 'System Token',
        },
    ]
}
​
export default [
    // 用户登录接口
    {
        url: '/api/user/login',//请求地址
        method: 'post',//请求方式
        response: ({ body }) => {
            //获取请求体携带过来的用户名与密码
            const { username, password } = body;
            //调用获取用户信息函数,用于判断是否有此用户
            const checkUser = createUserList().find(
                (item) => item.username === username && item.password === password,
            )
            //没有用户返回失败信息
            if (!checkUser) {
                return { code: 201, data: { message: '账号或者密码不正确' } }
            }
            //如果有返回成功信息
            const { token } = checkUser
            return { code: 200, data: { token } }
        },
    },
    // 获取用户信息
    {
        url: '/api/user/info',
        method: 'get',
        response: (request) => {
            //获取请求头携带token
            const token = request.headers.token;
            //查看用户信息是否包含有次token用户
            const checkUser = createUserList().find((item) => item.token === token)
            //没有返回失败的信息
            if (!checkUser) {
                return { code: 201, data: { message: '获取用户信息失败' } }
            }
            //如果有返回成功信息
            return { code: 200, data: {checkUser} }
        },
    },
]

install axios

pnpm install axios

Finally, test the interface through axios! ! !

3.7 Axios secondary packaging

It is inevitable to interact with the backend when developing a project, so we need to use the axios plug-in to send network requests. When developing projects, we often repackage axios.

Purpose:

  • Using the request interceptor, some business can be processed in the request interceptor (starting progress bar, request header carrying public parameters)
  • Using the response interceptor, you can process some business in the response interceptor (end of the progress bar, simplify the data returned by the server, handle http network errors)

Create utils/request.ts in the root directory

import axios from "axios";
import { ElMessage } from "element-plus";
//创建axios实例
let request = axios.create({
    baseURL: import.meta.env.VITE_APP_BASE_API,
    timeout: 5000
})
//请求拦截器
request.interceptors.request.use(config => {
    return config;
});
//响应拦截器
request.interceptors.response.use((response) => {
    return response.data;
}, (error) => {
    //处理网络错误
    let msg = '';
    let status = error.response.status;
    switch (status) {
        case 401:
            msg = "token过期";
            break;
        case 403:
            msg = '无权访问';
            break;
        case 404:
            msg = "请求地址错误";
            break;
        case 500:
            msg = "服务器出现问题";
            break;
        default:
            msg = "无网络";
​
    }
    ElMessage({
        type: 'error',
        message: msg
    })
    return Promise.reject(error);
});
export default request;

important point:

What is exposed is the encapsulated request instead of axios

No need to carry /api when sending the request, because the basic path is configured

Any request will go through the request interceptor, so the configuration config in the request interceptor can carry something to the server, usually token

The config object must be returned in the request interceptor, otherwise the request cannot be sent out

3.8 Unified management of API interface

When developing a project, there may be many interfaces that need to be managed uniformly. Create an api folder in the src directory to manage the interface of the project in a unified manner.

For example: the following way

//统一管理咱们项目用户相关的接口
​
import request from '@/utils/request'
​
import type {
​
 loginFormData,
​
 loginResponseData,
​
 userInfoReponseData,
​
} from './type'
​
//项目用户相关的请求地址
​
enum API {
​
 LOGIN_URL = '/admin/acl/index/login',
​
 USERINFO_URL = '/admin/acl/index/info',
​
 LOGOUT_URL = '/admin/acl/index/logout',
​
}
//登录接口
export const reqLogin = (data: loginFormData) =>
 request.post<any, loginResponseData>(API.LOGIN_URL, data)
//获取用户信息
​
export const reqUserInfo = () =>
​
 request.get<any, userInfoReponseData>(API.USERINFO_URL)
​
//退出登录
​
export const reqLogout = () => request.post<any, any>(API.LOGOUT_URL)

Type.ts can limit the request parameters and the type of received data src/api/user/type.ts

// 登入接口需要携带参数ts类型
export interface loginForm {
    username: string,
    password: string
}
​
interface dataType {
    token: string
}
//定义登录接口返回数据类型
export interface loginResponseData {
    code: number,
    data: dataType
}
​
​
interface userInfo {
    userId: number,
    avatar: string,
    username: string,
    password: string,
    desc: string,
    roles: string[],
    buttons: string[],
    routes: string[],
    token: string
}
​
interface user {
    checkUser: userInfo
}
​
//定义服务器返回用户信息相关的数据类型
export interface userResponseData {
    code: number,
    data: user
}

Guess you like

Origin blog.csdn.net/m0_55644132/article/details/130733371