vue3+ts+vite+pinia+element plus 从零打造一个前端后台管理项目

本文是对前一段时间自学vue最新语法的一个总结,因为过去的时间已经一个多月了,所以尽可能的还原当时的一步步过程和中间遇到的问题,作为一个总结日后查看。

通过这个文章,可以了解到

  • 如何使用使用 Vite 搭建项目
  • 如何在 Vite 中集成 typescript并使用
  • 如何在 Vite 中集成 vue-router4 和 pinia并使用
  • 如何使用 vue3 的伴侣 vueuse
  • 如何在项目中集成 eslint 和 prettier 保证代码质量
  • 如何规范化 git 提交信息
  • 如何为团队开发专属的项目模板
  • element-ui的使用
  • 如何封装一个axios网络类
  • 如何导入svg图库、使用全局变量等具体操作

下面我们就开始步入正题

一、初始化项目

按步骤进行初始化:

根据官网,直接输入命令

npm init vue@latest

这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:

image.png

然后我们根据提示,进行以下操作:

  cd vue-system
  npm install
  npm run lint
  npm run dev

这样我们的vue3就顺利的跑起来了,页面如下:


WX20230215-155122@2x.png

运行项目不会默认打开浏览器,需要在package.json里面 ,在vite 后面加上--open


w
集成配置

1、使用别名@/,安装types/node来加载path模块

npm i @types/node --save-dev

2、修改tsconfig.json

{
  "extends": "@vue/tsconfig/tsconfig.web.json",
  "include": ["env.d.ts", "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "compilerOptions": {
    "typeRoots": [
      "node_modules/@types", // 默认值
      "src/types"
   ],
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": "./",
    "paths":{
      "@": ["src"],
      "@/*": ["src/*"],
    }
  },
  "references": [
    {
      "path": "./tsconfig.config.json"
    }
  ]
}

3、修改 vite.config.ts

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import * as path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
    resolve: {
        //设置别名
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    plugins: [vue()],
    server: {
        port: 8080, //启动端口
        hmr: {
            host: '127.0.0.1',
            port: 8080
        },
        // 设置 https 代理
        proxy: {
            '/api': {
                target: 'your https address',
                changeOrigin: true,
                rewrite: (path: string) => path.replace(/^\/api/, '')
            }
        }
    }
});

二、代码质量风格的统一

ESLint

这个在项目初始化已经安装了,后面看看需要什么更详细的配置。

prettier

代码格式化的工具,具体配置步骤如下:
1、首先在VS Code中安装Prettier - Code formatter插件
![image.png](https://upload-images.jianshu.io/upload_images/246657-f2cbf3a9e10e1d5e.png?imageMogr2/auto-orient/strip%7CimageView2/2 /w/1240)
2、然后在设置中进行勾选

image.png

3、在代码文件中右键,选择 使用...格式化文件
image.png

4、配置默认格式化程序
image.png

5、在项目种的.prettierrc.json文件中

{
  // 一行最多 80 字符
  "printWidth": 80,
  // 使用 2 个空格缩进
  "tabWidth": 2,
  // 不使用 tab 缩进,而使用空格
  "useTabs": false,
  // 行尾需要有分号
  "semi": false,
  // 使用单引号代替双引号
  "singleQuote": true,
  // 对象的 key 仅在必要时用引号
  "quoteProps": "as-needed",
  // jsx 不使用单引号,而使用双引号
  "jsxSingleQuote": false,
  // 末尾使用逗号
  "trailingComma": "all",
  // 大括号内的首尾需要空格 { foo: bar }
  "bracketSpacing": true,
  // jsx 标签的反尖括号需要换行
  "jsxBracketSameLine": false,
  // 箭头函数,只有一个参数的时候,也需要括号
  "arrowParens": "always",
  // 每个文件格式化的范围是文件的全部内容
  "rangeStart": 0,
  "rangeEnd": Infinity,
  // 不需要写文件开头的 @prettier
  "requirePragma": false,
  // 不需要自动在文件开头插入 @prettier
  "insertPragma": false,
  // 使用默认的折行标准
  "proseWrap": "preserve",
  // 根据显示样式决定 html 要不要折行
  "htmlWhitespaceSensitivity": "css",
  // 换行符使用 lf
  "endOfLine": "auto"
}

json文件中不能注释,所以要把注释去掉

{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "all",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "always",
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve",
  "htmlWhitespaceSensitivity": "css",
  "endOfLine": "auto"
}

再修改代码保存的时候,就可以了

三、提交规范

为了使团队多人协作更加的规范,所以需要每次在 git 提交的时候,做一次硬性规范提交,规范 git 的提交信息,具体提交规范可参考:
//www.greatytc.com/p/635670ad2fca

一、使用 commitizen 规范git提交(交互式提交 + 自定义提示文案 + Commit规范)

这里是指用代码行命令的时候,设置可视化的提示,步骤如下:

1、安装

npm install -D commitizen cz-conventional-changelog @commitlint/config-conventional @commitlint/cli commitlint-config-cz cz-customizable

2、配置 package.json

{
  ...
  "scripts": {
    "commit:comment": "引导设置规范化的提交信息",
    "commit":"git-cz",
  },

  "config": {
      "commitizen": {
        "path": "node_modules/cz-customizable"
      }
  },
}

3、添加文件 commitlint.config.js

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> 格式 小写
        'type-case': [2, 'always', 'lower-case'],
        // <type> 不能为空
        'type-empty': [2, 'never'],
        // <scope> 范围不能为空
        'scope-empty': [2, 'never'],
        // <scope> 范围格式
        'scope-case': [0],
        // <subject> 主要 message 不能为空
        'subject-empty': [2, 'never'],
        // <subject> 以什么为结束标志,禁用
        'subject-full-stop': [0, 'never'],
        // <subject> 格式,禁用
        'subject-case': [0, 'never'],
        // <body> 以空行开头
        'body-leading-blank': [1, 'always'],
        'header-max-length': [0, 'always', 72],
    },
};

4、新增自定义提示文件 .cz-config.js

module.exports = {
    types: [
        {value: 'feature',  name: 'feature:  增加新功能'},
        {value: 'bug',      name: 'bug:      测试反馈bug列表中的bug号'},
        {value: 'fix',      name: 'fix:      修复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: '请输入详细描述(可选,待优化去除,跳过即可):',
        footer: '请输入要关闭的issue(待优化去除,跳过即可):',
        confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
    },
    allowCustomScopes: true,
    skipQuestions: ['body', 'footer'],
    subjectLimit: 72
};

6、终端输入git add .
7、接着输入npm run commit


image.png

image.png
二、VS Code插件

使用git-commint-plugin插件
具体使用可以查看这篇文章:
https://blog.csdn.net/weixin_41056807/article/details/127202536

三、sourcetree使用

使用脚本来做sourcetree的提交规范
具体使用可以查看这篇文章:
//www.greatytc.com/p/dc65bd37972a
生效后souretree的样子如下图

image.png

四、集成ElementPlus

1、集成
npm install element-plus --save

在main.ts中配置

import { createApp } from 'vue'
import { createPinia } from 'pinia'

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

import './assets/main.css'

const app = createApp(App)
//Pinia
app.use(createPinia())
app.use(router)
app.use(ElementPlus)

app.mount('#app')

如果您使用 Volar,请在 tsconfig.json 中通过 compilerOptions.type 指定全局组件类型。

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

五、项目编写以及过程中的内容知识整理

1、删除App.vue中多余的内容

<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>

<template>
  <RouterView />
</template>

<style scoped></style>

2、删除多余文件,添加login页面文件
删除views文件夹下自带的文件,添加login页面,并在router.ts中配置一下路由


image.png

image.png

3、引入全局样式文件


image.png

main.ts中引入
import '@/assets/styles/index.scss' // global css

4、login静态页面编写

  • 首先代码如下:
<template>
  <div class="login-container">
    <el-form
      ref="ruleFormRef"
      :model="loginForm"
      class="login-form"
      :rules="rules"
    >
      <div class="title-container">
        <h3 class="title">用户登录</h3>
      </div>
      <!-- 账号 -->
      <el-form-item prop="username">
        <!-- <svg-icon
          class="svg-container"
          iconName="user"
          iconSize="20"
        ></svg-icon> -->
        <el-input v-model="loginForm.username"></el-input>
      </el-form-item>
      <!-- 密码 -->
      <el-form-item prop="password">
        <!-- <svg-icon
          class="svg-container"
          iconName="password"
          iconSize="20"
        ></svg-icon> -->
        <el-input
          v-model="loginForm.password"
          type="password"
          showPassword
        ></el-input>
      </el-form-item>
      <!-- 登录按钮 -->
      <el-button
        type="primary"
        class="login-button"
        @click="handleLogin(ruleFormRef)"
      >
        登录
      </el-button>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'

const loginForm = ref({
  username: 'admin',
  password: '123456',
})

const ruleFormRef = ref<FormInstance>()

const rules = reactive<FormRules>({
  username: [
    { required: true, message: 'Please input Activity name', trigger: 'blur' },
  ],
  password: [
    { required: true, message: 'Please input password', trigger: 'blur' },
  ],
})
// 登录点击
const handleLogin = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  console.log('click login button')
}
</script>

<style lang="scss" scoped>
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
$cursor: #fff;

.login-container {
  width: 100vw;
  height: 100vh;
  background-color: $bg;
  display: flex;
  align-items: center;
  justify-content: center;

  .login-form {
    width: 520px;
    overflow: hidden;
    display: flex;
    flex-direction: column;

    :deep(.el-form-item) {
      border: 1px solid rgba(255, 255, 255, 0.1);
      background: white;
      border-radius: 5px;
    }

    :deep(.el-input) {
      height: 47px;
      width: 92%;
      padding: 12px 5px;
      color: #000;
      height: 47px;

      .el-input__wrapper {
        background: transparent;
        box-shadow: none;
      }
    }
    .login-button {
      width: 50%;
      height: 40px;
      margin: 0 auto;
    }
  }
  .title-container {
    .title {
      color: $light_gray;
      font-size: 26px;
      font-weight: bold;
      text-align: center;
      margin-bottom: 20px;
    }
  }

  .svg-container {
    padding: 6px 5px 6px 15px;
    color: $dark_gray;
    vertical-align: middle;
    display: inline-block;
  }
}
</style>
  • 在css的编写中我们引入了scss,此时运行项目报错vite] Internal server error: Preprocessor dependency "sass" not found. Did you install it? Plugin: vite:css
    我们需要来安装他,这样就不报错了
    npm install sass --save-dev

  • 这里来看一下scss和sass的介绍
    https://blog.csdn.net/qq_45947664/article/details/127857374

  • 这里还用:deep(.el-input)来修改input的默认样式,而不用::v-deep了

这样我们就完成了静态页面的编写,效果如下


image.png

5、ref和reactive的异同
这里我们用到了import { ref, reactive } from 'vue',来讲一下二者的异同,直接贴结论:

相同点:创建响应式对象

不同点:

  • ref可接受对象类型也可以接受基本类型即所有类型,而reactive只能接收Array、Object、Map、Set这种引用类型
  • ref创建的数据返回类型为RefImpl ,而RefImpl._value是一个 reactive 代理的原始对象,reactive创建的数据返回类型为Proxy
  • ref使用.value来取值和赋值

参考:https://www.bilibili.com/read/cv18429108

6、svg图标的使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容