【Vue H5项目实战】从0到1的自助点餐系统—— 搭建脚手架(Vue3.2 + Vite + TS + Vant + Pinia + Node.js)

news2024/10/6 10:27:40

前言

H5 项目基于 Web 技术,可以在智能手机、平板电脑等移动设备上的浏览器中运行,无需下载和安装任何应用程序,且H5 项目的代码和资源可以集中在服务器端进行管理,只需更新服务器上的代码,即可让所有顾客访问到最新的系统版本。

本系列将以肯德基自助点餐页面为模板,搭建一款自助点餐系统,第一次开发移动端h5项目,免不了有所差错和不足,欢迎各位大佬指正。

项目代码正在gitee同步更新中,项目地址:https://gitee.com/airheaven/kfg-vue,学习前请大家给个star哦🌟

技术栈

Vue3.2 + Vite + TS + Vant + Pinia + Node.js

一、起始准备

1.1、安装nvm

nvm 全英文也叫 node.js version management,是一个 nodejs 的版本管理工具,用于管理nodejs。
首先进入github链接:https://github.com/coreybutler/nvm-windows/releases 下载 nvm-setup.zip,随后安装。

安装完成后输入nvm version显示版本号就是安装成功了,我这里用的是1.1.10版本。

PS E:\MyVueWorkspace> nvm version
1.1.10

1.2、利用nvm安装node和npm

nvm install 版本号 安装指定的版本的 nodejs,我这里输入:nvm install 16.16.0 安装16.16.0版本
nvm会自动帮你安装好node和npm,显示如下信息就是成功了:

Downloading node.js version 16.16.0 (64-bit)...
Extracting node and npm...
Complete
npm v8.11.0 installed successfully.

Installation complete. If you want to use this version, type
nvm use 16.16.0

如果之前安装过,可以使用nvm ls查看已经安装过的node版本。

安装好node和npm后,需要使用nvm use 16.16.0启用该版本。

1.3、利用npm安装Vite

既然是新项目,且用的是Vue3.2,那么我们必须用上现在嘎嘎香 嘎嘎快的Vite,Vite是新一代的前端开发与构建工具,具有开箱即用、高度的可扩展性和完整的类型支持。

使用npm install -g vite安装最新版的Vite,然后使用vite -v查看版本(我的是4.1.4)

added 14 packages, and audited 16 packages in 13s

found 0 vulnerabilities
npm notice
npm notice New major version of npm available! 8.11.0 -> 9.5.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.5.1
npm notice Run npm install -g npm@9.5.1 to update!
npm notice
PS E:\MyVueWorkspace> vite -v
vite/4.1.4 win32-x64 node-v16.16.0

1.4、VsCode插件安装

在VsCode中找到扩展,需要安装的扩展插件有:

ESlint:开源的JavaScript验证工具,可以让代码更加规范:

在这里插入图片描述

Prettier:前端代码格式工具,可以让代码保持风格一致:

在这里插入图片描述
Vue Language Features(Volar):针对Vue3的vscode插件:

在这里插入图片描述

二、项目初始化

输入npm create vite@latest使用Vite初始化项目,填写项目名称(KFG-vue),选择Vue作为框架,语言选择TypeScript,如下所示:

Need to install the following packages:
  create-vite@latest
Ok to proceed? (y) y
√ Project name: ... KFG-vue
√ Package name: ... kfg-vue
√ Select a framework: » Vue
√ Select a variant: » TypeScript

然后cd进入KFG-vue项目目录,输入:npm install安装项目所需的基本依赖:

added 46 packages, and audited 47 packages in 37s
5 packages are looking for funding
  run `npm fund` for details
found 0 vulnerabilities

输入npm run dev运行项目,控制台会输出网址,如http://127.0.0.1:5173/即可以查看初始化好的项目:

> kfg-vue@0.0.0 dev
> vite
  VITE v4.1.4  ready in 261 ms
  ➜  Local:   http://127.0.0.1:5173/
  ➜  Network: use --host to expose

然后我们需要删除一些初始化项目中不需要的东西,删除public里的vite.svg,删除assets里面的vue.svg,删除components里面的HelloWorld.vue,清空style.css,清空App.vue里的内容(仅仅保留最基本的vue3模板):
在这里插入图片描述
由于vue中ts无法识别引入的vue文件,引入模块后会提示打不到module,但是编译可能成功,运行也不报错,为了我的强迫症我选择在src文件夹下新增一个env.d.ts文件解决这个问题:

// src/env.d.ts
declare module "*.vue" {
  import type { DefineComponent } from "vue";

  // eslint-disable-next-line @typescript-eslint/ban-types
  const vueComponent: DefineComponent<{}, {}, any>;

  export default vueComponent;
}

三、代码规范配置(可选)

插件拿来不一定能够完全适用,需要提供了一些额外的适用于 ts 和vue语法的规则,配置以下项:

ESlint配置:输入npx eslint --init,选择如下:

√ How would you like to use ESLint? · problems(第二个)
√ What type of modules does your project use? · esm(第一个)
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser, node(两个都勾选)
√ What format do you want your config file to be in? · JavaScript

Prettier配置:输入npm i prettier eslint-config-prettier eslint-plugin-prettier -D
创建prettier.cjs文件,文件中输入:

// prettier.cjs
module.exports = {
  printWidth: 100,
  tabWidth: 2,
  useTabs: false, // 是否使用tab进行缩进,默认为false
  singleQuote: true, // 是否使用单引号代替双引号,默认为false
  semi: true, // 行尾是否使用分号,默认为true
  arrowParens: 'always',
  endOfLine: 'auto',
  vueIndentScriptAndStyle: true,
  htmlWhitespaceSensitivity: 'strict',
};

配置eslintrc文件,将文件.eslintrc.cjs改为:

// eslintrc.cjs

module.exports = {
  root: true, // 停止向上查找父级目录中的配置文件
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'prettier', // eslint-config-prettier 的缩写
  ],
  parser: 'vue-eslint-parser', // 指定要使用的解析器
  // 给解析器传入一些其他的配置参数
  parserOptions: {
    ecmaVersion: 'latest', // 支持的es版本
    parser: '@typescript-eslint/parser',
    sourceType: 'module', // 模块类型,默认为script,我们设置为module
  },
  plugins: ['vue', '@typescript-eslint', 'prettier'], // eslint-plugin- 可以省略
  rules: {
    'vue/multi-word-component-names': 'off',
    '@typescript-eslint/no-var-requires': 'off',
  },
};

配置保存文件自动格式化:在项目的.vscode中新建一个setting.json文件,

在这里插入图片描述
文件中配置如下,使程序能够保存时自动使用eslint格式化(懒人福音),setting.json配置 如下所示:

// .vscode/setting.json
  {
  	"editor.codeActionsOnSave": {
  		"source.fixAll.eslint": true
    },
  // #每次保存的时候自动格式化
  	"editor.formatOnSave": true,
  	"editor.formatOnType": true,
  // #每次保存的时候将代码按eslint格式进行修复
  	"eslint.autoFixOnSave": true,
  	"eslint.format.enable": true,
  } 

添加lint命令(可选):package.json中进行配置,可以运行npm run lint检查代码:

// package.json

// 可以运行`npm run lint`检查代码
"lint": "eslint --ext .js,.vue,.ts src --fix"

四、项目搭建

4.1、清除默认样式

在网上找一个reset.css文件,放入到src/styles文件夹(可能需要新建)中,从而清除默认样式:

/* src/styles */
/* 清除内外边距 */
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote,
dl, dt, dd, ul, ol, li,
pre,
fieldset, lengend, button, input, textarea,
th, td {
    margin: 0;
    padding: 0;
}

/* 设置默认字体 */
body,
button, input, select, textarea { /* for ie */
    /*font: 12px/1 Tahoma, Helvetica, Arial, "宋体", sans-serif;*/
    font: 12px/1.3 "Microsoft YaHei",Tahoma, Helvetica, Arial, "\5b8b\4f53", sans-serif; /* 用 ascii 字符表示,使得在任何编码下都无问题 */
    color: #333;
}


h1 { font-size: 18px; /* 18px / 12px = 1.5 */ }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
h4, h5, h6 { font-size: 100%; }

address, cite, dfn, em, var, i{ font-style: normal; } /* 将斜体扶正 */
b, strong{ font-weight: normal; } /* 将粗体扶细 */
code, kbd, pre, samp, tt { font-family: "Courier New", Courier, monospace; } /* 统一等宽字体 */
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */

/* 重置列表元素 */
ul, ol { list-style: none; }

/* 重置文本格式元素 */
a { text-decoration: none; color: #666;}


/* 重置表单元素 */
legend { color: #000; } /* for ie6 */
fieldset, img { border: none; }
button, input, select, textarea {
    font-size: 100%; /* 使得表单元素在 ie 下能继承字体大小 */
}

/* 重置表格元素 */
table {
    border-collapse: collapse;
    border-spacing: 0;
}

/* 重置 hr */
hr {
    border: none;
    height: 1px;
}
.clearFix::after{
	content:"";
	display: block;
	clear:both;
}
/* 让非ie浏览器默认也显示垂直滚动条,防止因滚动条引起的闪烁 */
html { overflow-y: scroll; }

a:link:hover{
    color : rgb(79, 76, 212) !important;
    text-decoration: underline;
}

/* 清除浮动 */
.clearfix::after {
    display: block;
    height: 0;
    content: "";
    clear: both;
    visibility: hidden;
}

在index.html中引入:

<link rel="stylesheet" href="./styles/reset.css">

4.2、路径别名配置

路径别名配置:在vite.config.ts, 加入以下内容(resolve的alias),设置别名@:

// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 设置路径
import { resolve } from "path";

// Vant声明和按需引入
import Component from "unplugin-vue-components/vite";
import { VantResolver } from "unplugin-vue-components/resolvers";

// vw方案,将px转为vw
import postcsspxtoviewport from "postcss-px-to-viewport";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Component({
      resolvers: [VantResolver()],
    }),
  ],
  css: {
    postcss: {
      plugins: [
        postcsspxtoviewport({
          unitToConvert: "px", // 要转化的单位
          viewportWidth: 750, // UI设计稿的宽度,一般写 320

          // 下面的不常用,上面的常用
          unitPrecision: 6, // 转换后的精度,即小数点位数
          propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
          viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
          fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
          selectorBlackList: ["ignore-"], // 指定不转换为视窗单位的类名,
          minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
          mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
          replace: true, // 是否转换后直接更换属性值
          landscape: false, // 是否处理横屏情况
        }),
      ],
    },
  },
  resolve: {
    alias: {
      "@": resolve(__dirname, "./src"),
      "*": resolve(""),
    },
  },
});

然后在tsconfig.json,加入以下内容(baseUrl和paths):

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "noEmit": true,
    "baseUrl": ".",
    // 用于设置解析非相对模块名称的基本目录,相对模块不会受到baseUrl的影响
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

4.3、项目搭建

1️⃣ Less: CSS预处理器

我选用了less作为CSS预处理器,需要安装相应的预处理器依赖:npm i less -D
如果需要规定全局样式的话,可以配置一下在src/asserts/less文件夹下新建一个global.less,然后在vite.config.ts的css中写入:

// vite.config.ts
css: {
preprocessorOptions: {
      less: {
        modifyVars: {
          hack: `true; @import (reference) "${resolve(
            "src/assets/less/global.less"
          )}";`,
        },
        javascriptEnabled: true,
      },
    },
    //....
  }

2️⃣ Vant: 轻量可定制的移动端组件库

选用移动端最常用的Vant作为组件库,输入npm i vant 安装Vant。

然后安装按需引入插件,输入npm i unplugin-vue-components -D安装插件,它可以自动引入组件,并按需引入组件的样式。相比于常规用法,这种方式可以按需引入组件的 CSS 样式,从而减少一部分代码体积,但使用起来会变得繁琐一些。

配置Vant的按需引入,在 vite.config.js 文件中配置插件:

// vite.config.ts
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from 'unplugin-vue-components/resolvers';

export default {
  plugins: [
    vue(),
    Components({
      resolvers: [VantResolver()],
    }),
  ],
};

完成以上两步,就可以直接在模板中使用 Vant 组件了,unplugin-vue-components 会解析模板并自动注册对应的组件。
可以试试在App.vue中写入:

<script setup lang="ts"></script>

<template>
  <van-button type="primary">Hello World</van-button>
</template>

<style scoped></style>

显示如下则成功引入Vant并自动注册了组件:
在这里插入图片描述

3️⃣ vw/vh方案:移动端适配

移动端适配通常使用的有rem方案和vw/vh方案,我选用的是vw方案,首先输入npm install postcss-px-to-viewport -D安装插件,将 px 转化成 vw,安装完成后,修改 vite.config.ts声明插件(由于 vite 中已经内联了 postcss,所以无需创建 postcss.config.js文件来声明插件):

// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// 设置路径
import { resolve } from "path";
// Vant声明和按需引入
import Component from "unplugin-vue-components/vite";
import { VantResolver } from "unplugin-vue-components/resolvers";
// vw方案,将px转为vw
import postcsspxtoviewport from "postcss-px-to-viewport";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Component({
      resolvers: [VantResolver()],
    }),
  ],
  css: {
    postcss: {
      plugins: [
        postcsspxtoviewport({
          unitToConvert: "px", // 要转化的单位
          viewportWidth: 750, // UI设计稿的宽度,一般写 320

          // 下面的不常用,上面的常用
          unitPrecision: 6, // 转换后的精度,即小数点位数
          propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
          viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
          fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
          selectorBlackList: ["ignore-"], // 指定不转换为视窗单位的类名,
          minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
          mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
          replace: true, // 是否转换后直接更换属性值
          landscape: false, // 是否处理横屏情况
        }),
      ],
    },
  },
  resolve: {
    alias: {
      "@": resolve(__dirname, "./src"),
      "*": resolve(""),
    },
  },
});


然后运行项目,即可发现支持了移动端适配,且自适应的调整高度,成功配置
在这里插入图片描述

4️⃣ Vue Router:路由配置

部分参考自:https://blog.csdn.net/jason_renyu/article/details/123261823

Vue Router是Vue.js 的官方路由,非常方便好用,在控制台输入:npm i vue-router@4安装Vue Router,新建router文件夹,新建router/index.ts,配置如下:

/**
 * createRouter 这个为创建路由的方法
 * createWebHashHistory 这个就是vue2中路由的模式,
 *                      这里的是hash模式,这个还可以是createWebHistory等
 * RouteRecordRaw 这个为要添加的路由记录,也可以说是routes的ts类型
 */
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
// 路由记录,这个跟vue2中用法一致,就不做过多解释了
const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    name: "todolist",
    component: () => import("@/components/TodoList.vue"),
    alias: "/todolist",
    meta: {
      title: "todolist页面",
    },
  },
  {
    path: "/father",
    name: "father",
    component: () => import("@/components/Father.vue"),
    meta: {
      title: "father页面",
    },
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});
export default router;

测试一下,在compnents文件下下新建Father.vue和TodoList.vue,内容如下:
Father.vue:

<!-- compnents/Father.vue -->
<template>
  <div>
    <h2>这是Father组件</h2>
    <h3>路由传入的参数为:{{ route.query.msg }}</h3>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
// 路由接收参数
import { useRoute } from "vue-router";
const route = useRoute();
// 接收路由传入的参数
let routeMsg = ref("");
if (route.query.msg) {
  routeMsg.value = route.query.msg as string;
}
</script>

<style scoped></style>

TodoList.vue:

<!-- compnents/TodoList.vue -->
<template>
  <div>
    <h2>这是TodoList组件</h2>
  </div>
</template>

<script setup lang="ts"></script>

<style scoped></style>

在App.vue中测试调用:

<!-- App.vue -->
<script setup lang="ts">
// useRouter的使用
import { useRouter } from "vue-router";
const router = useRouter();

const jumpFather = () => {
  // 编程式跳转和传参
  router.push({
    path: "/father",
    query: {
      msg: "hello Vue-Router",
    },
  });
};
</script>

<template>
  <div>
    <router-link to="/">todolist</router-link>
    |
    <router-link to="/father">father</router-link>
  </div>
  <div>
    <van-button type="primary" @click="jumpFather">跳转到father</van-button>
  </div>
  <router-view></router-view>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

然后输入npm run dev测试看看,显示如下,todolist和father点击后有所变化,配置成功啦!
在这里插入图片描述

5️⃣ Pinia:状态管理器

部分参考自:https://blog.csdn.net/qq1195566313/category_11672479.html

Pinia 是 Vue 的存储库,允许跨组件/页面共享状态。同样我们输入npm i pinia安装Pinia,在项目src下创建store文件夹,以后项目中所有的状态管理部分文件都将放到store文件夹下。然后新建index.ts创建store

// src/store/index.ts
import { createPinia } from 'pinia';

const pinia = createPinia();

export default pinia;

挂载store,打开main.ts,以跟router差不多的方式,挂载进去:

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
// 挂载router
import router from "./router/index";
// 挂载store
import store from "@/store";

const app = createApp(App);
app.use(router);
app.use(store);
app.mount("#app");

同样测试一下,在store文件夹下新建types文件夹,types文件夹为状态模块类型管理文件夹,创建模块类型文件home.ts,写入代码如下:

export type storeHome = {
    count: number,
    status: boolean
}

在store文件夹下新建modules文件夹,modules文件夹为状态模块管理文件夹,创建模块文件home.ts,写入代码如下:

import { defineStore } from "pinia";
import { storeHome } from "../types/home";

export const useHomeStore = defineStore("index", {
  state: (): storeHome => {
    return {
      count: 0,
      status: false,
    };
  },
  getters: {
    curCount(): number {
      return this.count;
    },
    curStatus(): boolean {
      return this.status;
    },
  },
  actions: {
    updatecount(val: number) {
      this.count = val;
    },
    changeStatus(val: boolean) {
      this.status = val;
    },
  },
});

然后在TodoList.vue文件中测试store是否成功:

<template>
  <div>
    <h2>这是TodoList组件</h2>
  </div>
  <div class="main-box">
    <h1>状态管理测试界面</h1>
    <h1>状态count:{{ homeStore.count }}</h1>
    <!-- <h1>状态curCount:{{ calculateCount }}</h1>
    <van-button @click="initCount">归零</van-button> -->
    <van-button type="success" @click="changeCount">计数</van-button>
    <van-button type="danger" @click="randomCount">随机</van-button>
  </div>
</template>

<script setup lang="ts">
import { useHomeStore } from "@/store/modules/home";
const homeStore = useHomeStore();

const changeCount = () => {
  homeStore.count++;
};

const randomCount = () => {
  const num: number = Math.random() * 100;
  homeStore.updatecount(Math.floor(num));
};
</script>

<style scoped></style>

输入npm run dev 进入测试,点击todolist,然后点击随机或者计数,可以看到状态count值的变化。
在这里插入图片描述
状态的持久化配置等内容暂时不展开,后续需要用到会说明。

至此项目的整体结构为:

在这里插入图片描述

6️⃣ Axios:网络请求封装

Axios 是一个基于 promise 的网络请求库,其使用简单,包尺寸小且提供了易于扩展的接口,首先输入npm i axios安装Axios。
新建 src/utils/http 文件夹,新建 axios.tstypes.ts
axios.ts封装axios请求方法:

// src/utils/http/axios.ts
import axios, {
  AxiosInstance,
  AxiosError,
  AxiosRequestConfig,
  AxiosResponse,
} from "axios";
import { showToast } from "vant";
import "vant/es/toast/style";
// response interface { code, msg, success }
// 不含 data
interface Result {
  code: number;
  success: boolean;
  msg: string;
}

// request interface,包含 data
interface ResultData<T = any> extends Result {
  data?: T;
}

enum RequestEnums {
  TIMEOUT = 10000, // 请求超时 request timeout
  FAIL = 500, // 服务器异常 server error
  LOGINTIMEOUT = 401, // 登录超时 login timeout
  SUCCESS = 200, // 请求成功 request successfully
}

// axios 基础配置
const config = {
  // 默认地址,可以使用 process Node内置的,
  // 这里后续要配置到env.development里
  baseURL: "/api",
  timeout: RequestEnums.TIMEOUT as number, // 请求超时时间
  withCredentials: true, // 跨越的时候允许携带凭证
};

class Request {
  request(config: AxiosRequestConfig<any>) {
    throw new Error("Method not implemented.");
  }
  service: AxiosInstance;

  constructor(config: AxiosRequestConfig) {
    // 实例化 serice
    this.service = axios.create(config);

    /**
     * 请求拦截器
     * request -> { 请求拦截器 } -> server
     */
    this.service.interceptors.request.use(
      (config: AxiosRequestConfig): any => {
        const token = localStorage.getItem("token") ?? "";
        return {
          ...config,
          headers: {
            customToken: "customBearer " + token,
          },
        };
      },
      (error: AxiosError) => {
        // 请求报错
        Promise.reject(error);
      }
    );

    /**
     * 响应拦截器
     * response -> { 响应拦截器 } -> client
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        const { data, config } = response;
        if (data.code === RequestEnums.LOGINTIMEOUT) {
          // 登录过期,需要重定向至登录页面
          localStorage.setItem("token", "");
          location.href = "/";
        }
        if (data.code && data.code !== RequestEnums.SUCCESS) {
          showToast({ message: data });
          return Promise.reject(data);
        }
        return data;
      },
      (error: AxiosError) => {
        const { response } = error;
        if (response) {
          this.handleCode(response.status);
        }
        if (!window.navigator.onLine) {
          showToast({
            message: "网络连接失败,请检查网络",
          });
          // 可以重定向至404页面
        }
      }
    );
  }

  public handleCode = (code: number): void => {
    switch (code) {
      case 401:
        showToast({
          message: "登陆失败,请重新登录",
        });
        break;
      case 500:
        showToast({
          message: "请求异常,请联系管理员",
        });
        break;
      case 404:
        showToast({
          message: "404错误,请联系管理员",
        });
        break;
      default:
        showToast({
          message: "请求失败,请联系管理员",
        });
        break;
    }
  };

  // 通用方法封装
  get<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.get(url, { params });
  }

  post<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.post(url, params);
  }
  put<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.put(url, params);
  }
  delete<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.delete(url, { params });
  }
}

export default new Request(config);

types.ts和后端约定好接口返回的数据结构,如:

// src/utils/http/types.ts		

// 和后端约定好接口返回的数据结构
export interface Response<T = any> {
  code: number | string;
  message: string;
  result: T;
}

封装axios的方式多种多样,网上有很多种选择,本项目Axios封装主要参考自:https://blog.csdn.net/weixin_56650035/article/details/127467646
在这里插入图片描述
测试使用,src目录下新增 api/user/index.ts,内容如下:

// src/api/user/index.ts
import request from "@/utils/http/axios";
import { Response } from "@/utils/http/types";

export interface LoginParams {
  username: string;
  password: string;
}

export interface UserInfo {
  id: number;
  username: string;
  mobile: number;
  email: string;
}

export default {
  async login(params: LoginParams) {
    return await request.post<Response<UserInfo>>("/user/login", params);
  },
};

最后,在某一个vue文件中调用api试试:

// 测试axios的封装
import Api, { LoginParams } from "@/api/user";
const loginInfo: LoginParams = {
  username: "name",
  password: "string",
};
const login = async () => {
  const result = await Api.login(loginInfo);
  // do something
  console.log(result);
};

五、git commit规范辅助和git版本管理

5.1、设置commit规范辅助

这里暂不使用git Husky和eslint,需要的同学可以配置

使用到Commitizen帮助编写规范的commit message ,首先需要输入npm install commitizen -D安装Commitizen,然后输入npm i -D cz-customizable安装cz-customizable自定义的 Commitizen 插件,
配置 根目录创建 .cz-config.js,内容如下:

module.exports = {
    types: [
      {
        value: ':sparkles: feat',
        name: '✨ feat:     新功能'
      },
      {
        value: ':bug: fix',
        name: '🐛 fix:      修复bug'
      },
      {
        value: ':tada: init',
        name: '🎉 init:     初始化'
      },
      {
        value: ':pencil2: docs',
        name: '✏️  docs:     文档变更'
      },
      {
        value: ':lipstick: style',
        name: '💄 style:    代码的样式美化'
      },
      {
        value: ':recycle: refactor',
        name: '♻️  refactor: 重构'
      },
      {
        value: ':zap: perf',
        name: '⚡️ perf:     性能优化'
      },
      {
        value: ':white_check_mark: test',
        name: '✅ test:     测试'
      },
      {
        value: ':rewind: revert',
        name: '⏪️ revert:   回退'
      },
      {
        value: ':package: build',
        name: '📦️ build:    打包'
      },
      {
        value: ':rocket: chore',
        name: '🚀 chore:    构建/工程依赖/工具'
      },
      {
        value: ':construction_worker: ci',
        name: '👷 ci:       CI related changes'
      }
    ],
    messages: {
      type: '请选择提交类型(必填)',
      customScope: '请输入文件修改范围(可选)',
      subject: '请简要描述提交(必填)',
      body: '请输入详细描述(可选)',
      breaking: '列出任何BREAKING CHANGES(可选)',
      footer: '请输入要关闭的issue(可选)',
      confirmCommit: '确定提交此说明吗?'
    },
    allowCustomScopes: true,
    allowBreakingChanges: [':sparkles: feat', ':bug: fix'],
    subjectLimit: 72
  }

最后要把package.json的脚本中的"type": "module"改为"type": "commonjs"
在scrpits中添加一行:"commit": "git add . && cz-customizable",如下

"scripts" : {
  ...
  "commit": "git add . && cz-customizable"
}

以后就使用 npm run commit 代替 git commit

5.2、git版本管理

首先在自己的github或者gitee上新建一个空白项目,我命名为KFG-vue,然后复制刚刚创建好的项目地址如:https://gitee.com/airheaven/kfg-vue.git,然后:

git init   # 把项目初始化,相当于在项目的跟目录生成一个 .git 目录
git add .    # 把项目的所有文件加入暂存区

随后使用npm run commit 进行commit,可以看到规范配置成功,选择辅助信息:
在这里插入图片描述

链接远程仓库:git remote add origin https://gitee.com/airheaven/kfg-vue.git(这里输入你刚刚创建好的仓库),然后git push origin master将项目推送到master分支

5.3、git日常使用

npm run commit:对代码进行commit
git push origin master:将项目推送到master分支

💡 资源下载与学习

本部分的代码已上传至CSDN:https://download.csdn.net/download/air__Heaven/87530349

项目代码正在gitee同步更新中,请大家给个star🌟,项目地址:https://gitee.com/airheaven/kfg-vue

🎉 支持我:点赞👍+收藏⭐️+留言📝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/742974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6.2Java EE——Spring的入门程序

下面通过一个简单的入门程序演示Spring框架的使用&#xff0c;要求在控制台打印“张三&#xff0c;欢迎来到Spring”&#xff0c;实现步骤具体如下。 1、在IDEA中创建名称为chapter06的Maven项目&#xff0c;然后在pom.xml文件中加载需使用到的Spring四个基础包以及Spring依赖…

【域渗透篇】渗透域环境下的windows7与2008-r2

目录 前言 域环境搭建测试 主机发现&&端口服务扫描&&漏洞脚本扫描 主机发现 全端口扫描 漏洞脚本扫描 永恒之蓝获取shell 主机信息收集 查看当前所在域及当前域用户 找到域控制器 收集域成员的IP msf后渗透阶段 Hashdump获取本地密码信息 破解ha…

cesium学习文档

文章目录 1. 简易的cesium安装依赖修改 vite.config.js申请token创建简单的cesium 2. 修改查看器3. 修改摄像头4. 设置纽约城市模型5. 划分城市区域并且着色6. 地图标记显示7. 实现无人机巡城 1. 简易的cesium 安装依赖 yarn add -D cesium vite vite-plugin-cesium修改 vite…

Openlayers实战:小物块运动轨迹动画

Openlayers地图在做轨迹的时候,除了标注各个位置点,连线,还经常会用到轨迹动画。 本实战就是这样示例,一个物块在轨迹上移动。其实质是用setInterval,每个一小段时间,重新计算定位一下小物块位置,整体串起来就是在移动。 效果图 源代码 /* * @Author: 大剑师兰特(xia…

TextMining Day3 基于信息抽取的文本挖掘

TextMining Day3 基于信息抽取的文本挖掘 1. 简介2. 背景:文本挖掘与信息提取3. 数据挖掘与信息提取相结合3.1 DISCOTEX系统3.2 评价 4. 使用挖掘规则改进IE4.1 算法4.2 评价 7. 结论 1. 简介 图1:基于IE&#xff08;信息抽取&#xff09;的文本挖掘框架概述 本文报告了计算机…

stm32 使用CubeIDE 移植RTX5

STM32 使用st的官方开发环境 cubeide &#xff08;eclipse gcc&#xff09;移植 cmsis rtos2 RTX5 实时操作系统 这套环境的主要优势是免费。cubeide免费使用。RTX5 免商业版税&#xff08;已从原keil中剥离出来&#xff0c;现在完全开源免费&#xff09;。 一&#xff0c;环…

微软开源社区上线,能够给微软Win95等“上古系统”打补丁

日前一个基于社区的项目“Windows Update Restored”上线&#xff0c;据了解该项目的目的是为老系统重新提供对Windows Update的支持&#xff0c;可为 Windows 95 / NT 4.0/98(包括 SE)/ME/ 2000 SP2 等“上古时期”的微软操作系统提供升级补丁、修复 bug 或安全漏洞。 据悉&a…

Python+Requests+Excel接口测试实战

1、EXCEL文件接口保存方式&#xff0c;如图。 2、然后就是读取EXCEL文件中的数据方法&#xff0c;如下&#xff1a; 1 import xlrd2 3 4 class readExcel(object):5 def __init__(self, path):6 self.path path7 8 property9 def getSheet(self): 10 …

设计模式【创建型】-- 原型模式

原型模式&#xff08;Prototype&#xff09; 原型模式是指原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。调用者不需要知道任何创建细节&#xff0c;不调用构造函数 主要应用&#xff1a; 浅拷贝深拷贝 原型模式&#xff1a; 抽象原型类&#xf…

【Redis】—— Redis的AOF持久化机制

&#x1f4a7; 【 R e d i s 】—— R e d i s 的 A O F 持久化机制 \color{#FF1493}{【Redis】 —— Redis的AOF持久化机制} 【Redis】——Redis的AOF持久化机制&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞…

如何搭建一个优秀的移动商城?

移动商城是一种新兴的购物方式。随着移动设备的普及和人们对线上购物的需求不断增加&#xff0c;移动商城已经成为了现代电子商务的重要组成部分。 对于想要在这个领域中获得成功的人来说&#xff0c;建立一个优秀的移动商城非常重要。但在搭建移动商城的过程中&#xff0c;有很…

【监控系统】Prometheus架构相关概念及源码部署实战

上篇我们介绍了业界主流监控框架的对比&#xff0c;我们监控系统这块主要是采用Prometheus。 那么&#xff0c;什么是Prometheus 官网&#xff1a;https://prometheus.io/docs/introduction/overview/ Prometheus是一个开源的系统监控和报警系统&#xff0c;现在已经加入到CN…

Android Java代码与JNI交互 JNI方法Java类字段 (六)

🔥 Android Studio 版本 🔥 🔥 Java 基础类型数据对应 jni 中的字母 🔥 通过 jni 查找java某个类中相应字段对应的数据类型 , 需要使用到 jni 中的 GetFieldID() 函数 jfieldID GetFieldID(jclass clazz, const char* name, const char* sig){ return functions-&g…

MySQL 如何处理 慢查询

如何定位慢查询? 方式一&#xff1a; 可以使用开源工具&#xff0c;比如&#xff1a; 调试工具&#xff1a;Arthas运维工具&#xff1a;Prometheus 、Skywalking 方式二&#xff1a; 使用MySQL自带慢日志 慢查询日志记录了所有执行时间超过指定参数&#xff08;long_qu…

bsub 的用法和意义

bsub -R “rusage [mem40960]” -Is -XF 执行脚本的方法 bsub <run 几条有用的命令 bqueues 查询所有queue的状态 4. 常用命令之bhosts 显示各节点作业相关情况 bhosts hostname 常用命令之bjobs 查看提交作业运行情况; bjobs –r 显示正在运行的作业 bjobs –a 显示正在…

微信小程序,左上脚返回点击直接到首页

我们做小程序时就有很多这种情况&#xff0c;根据不同情况处理方式不同 第一种情况&#xff1a;小程序有多个tab onUnload(event){ //多层级跳转之后&#xff0c;监听左上角返回事件&#xff0c;直接退回到indexuni.switchTab({url:"/pages/index/index"})}, 第二种…

pandas 笔记:高亮内容

1 高亮缺失值 1.0 数据 import pandas as pd import numpy as npdata[{a:1,b:2},{a:3,c:4},{a:10,b:-2,c:5}]df1pd.DataFrame(data) df1 1.1 highlight_null df.style.highlight_null(color: str red,subset: Subset | None None,props: str | None None, ) 1.1.1 默认情…

【Elasticsearch】RestClient操作文档

目录 5.RestClient操作文档 5.1.新增文档 5.1.1.索引库实体类 5.1.2.语法说明 5.1.3.完整代码 5.2.查询文档 5.2.1.语法说明 5.2.2.完整代码 5.3.删除文档 5.4.修改文档 5.4.1.语法说明 5.4.2.完整代码 5.5.批量导入文档 5.5.1.语法说明 5.5.2.完整代码 5.6.小…

java 整合 Elastic 8.

1. 准备工作 使用docker 快速搭建的环境,官网docker-compose 方式搭建的集群 设置了密码登录 elastic elastic 需要给jdk 导入证书 找到 证书对应目录&#xff0c;复制到桌面。主要导入下面2个证书,执行如下命令 keytool -importcert -alias "修改成你的证书名"…

[数字图像处理]第八章 图像压缩

文章目录 第八章 图像压缩引言8.1 基础知识8.1.1 编码冗余8.1.2 空间冗余和时间冗余8.1.3 不相关的信息8.1.4 图像信息的度量山农第一定理 8.1.5 保真度准则8.1.6 图像压缩模型编码或压缩过程解码或解压缩过程 8.2 一些基本的压缩方法8.2.1 霍夫曼编码8.2.2 Golomb编码8.2.3 算…