使用脚手架创建项目
yarn create vite '项目名' --template vue-ts
npm init vite@latest '项目名'
初始化项目
yarn 或者 npm i
安装eslint代码规范
输入命令 npx eslint --init 会生成 .eslintrc.js 配置文件
解决vue文件报 Parsing error: '>' expected
在 .eslintrc.js 文件添加 'parser': 'vue-eslint-parser',
解决 ’defineProps’ is not defined
在 .eslintrc.js 文件添加 'vue/setup-compiler-macros':true,
配置eslint规范
// rules配置文档http://eslint.cn/docs/rules/
'rules': {
'vue/multi-word-component-names': 'off',
// --以下是Possible Errors JS代码中的逻辑错误相关
'no-extra-parens': 'error', // 禁止不必要的括号
// "no-console": "error" // 不允许打印console.log
'no-template-curly-in-string': 'error', // 禁止在常规字符串中出现模板字符串语法${xxx}
// --以下是Best Practices 最佳实践
'default-case': 'error', // 强制switch要有default分支
'dot-location': ['error', 'property'], // 要求对象的点要跟属性同一行
'eqeqeq': 'error', // 要求使用 === 和 !==
'no-else-return': 'error', // 禁止在else前有return,return和else不能同时存在
'no-empty-function': 'error', // 禁止出现空函数,有意而为之的可以在函数内部加条注释
'no-multi-spaces': 'error', // 禁止出现多个空格,如===前后可以有一个空格,但是不能有多个空格
'no-multi-str': 'error', // 禁止出现多行字符串,可以使用模板字符串换行
'no-self-compare': 'error', // 禁止自身比较
'no-unmodified-loop-condition': 'error', // 禁止一成不变的循环条件,如while条件,防止死循环
'no-useless-concat': 'error', // 禁止没有必要的字符串拼接,如'a'+'b'应该写成'ab'
'require-await': 'error', // 禁止使用不带await的async表达式
// --以下是Stylistic Issues 主观的代码风格
'array-element-newline': ['error', 'consistent'], // 数组元素要一致的换行或者不换行
'block-spacing': 'error', // 强制函数/循环等块级作用域中的花括号内前后有一个空格(对象除外)
'brace-style': ['error', '1tbs', { 'allowSingleLine': true }], // if/elseif/else左花括号要跟if..同行,右花括号要换行;或者全部同一行
'comma-dangle': ['error', 'only-multiline'], // 允许在对象或数组的最后一项(不与结束括号同行)加个逗号
'comma-spacing': 'error', // 要求在逗号后面加个空格,禁止在逗号前面加一个空格
'comma-style': 'error', // 要求逗号放在数组元素、对象属性或变量声明之后,且在同一行
'computed-property-spacing': 'error', // 禁止在计算属性中出现空格,如obj[ 'a' ]是错的,obj['a']是对的
'eol-last': 'error', // 强制文件的末尾有一个空行
'func-call-spacing': 'error', // 禁止函数名和括号之间有个空格
'function-paren-newline': 'error', // 强制函数括号内的参数一致换行或一致不换行
'implicit-arrow-linebreak': 'error', // 禁止箭头函数的隐式返回 在箭头函数体之前出现换行
'indent': ['error', 2], // 使用一致的缩进,2个空格
'jsx-quotes': 'error', // 强制在jsx中使用双引号
'key-spacing': 'error', // 强制对象键值冒号后面有一个空格
'lines-around-comment': 'error', // 要求在块级注释/**/之前有一个空行
// 'multiline-comment-style': 'error', // 多行注释同一个风格,每一行前面都要有*
'new-cap': 'error', // 要求构造函数首字母大写
'newline-per-chained-call': ['error', { 'ignoreChainWithDepth': 2 }], // 链式调用长度超过2时,强制要求换行
'no-lonely-if': 'error', // 禁止else中出现单独的if
'no-multiple-empty-lines': 'error', // 限制最多出现两个空行
'no-trailing-spaces': 'error', // 禁止在空行使用空白字符
'no-unneeded-ternary': 'error', // 禁止多余的三元表达式,如a === 1 ? true : false应缩写为a === 1
'no-whitespace-before-property': 'error', // 禁止属性前有空白,如console. log(obj['a']),log前面的空白有问题
'nonblock-statement-body-position': 'error', // 强制单行语句不换行
'object-curly-newline': ['error', { 'multiline': true }], // 对象数属性要有一致的换行,都换行或都不换行
'object-curly-spacing': ['error', 'always'], // 强制对象/解构赋值/import等花括号前后有空格
'object-property-newline': ['error', { 'allowAllPropertiesOnSameLine': true }], // 强制对象的属性在同一行或全换行
'one-var-declaration-per-line': 'error', // 强制变量初始化语句换行
'operator-assignment': 'error', // 尽可能的简化赋值操作,如x=x+1 应简化为x+=1
'quotes': ['error', 'single'], // 要求字符串尽可能的使用单引号
'semi': ['error', 'never'], // 不要分号
'semi-spacing': 'error', // 强制分号后面有空格,如for (let i=0; i<20; i++)
'semi-style': 'error', // 强制分号出现在句末
'space-before-blocks': 'error', // 强制块(for循环/if/函数等)前面有一个空格,如for(...){}是错的,花括号前面要空格:for(...) {}
'space-infix-ops': 'error', // 强制操作符(+-/*)前后有一个空格
'spaced-comment': 'error', // 强制注释(//或/*)后面要有一个空格
// --以下是ECMAScript 6 ES6相关的
'arrow-body-style': 'error', // 当前头函数体的花括号可以省略时,不允许出现花括号
'arrow-parens': ['error', 'as-needed'], // 箭头函数参数只有一个时,不允许写圆括号
'arrow-spacing': 'error', // 要求箭头函数的=>前后有空格
'no-confusing-arrow': 'error', // 禁止在可能与比较操作符混淆的地方使用箭头函数
'no-duplicate-imports': 'error', // 禁止重复导入
'no-useless-computed-key': 'error', // 禁止不必要的计算属性,如obj3={['a']: 1},其中['a']是不必要的,直接写'a'
'no-var': 'error', // 要求使用let或const,而不是var
'object-shorthand': 'error', // 要求对象字面量使用简写
'prefer-const': 'error', // 要求使用const声明不会被修改的变量
/*
* 'prefer-destructuring': ['error', {
* 'array': false,
* 'object': true
* }, { 'enforceForRenamedProperties': true }], // 要求优先使用结构赋值,enforceForRenamedProperties为true将规则应用于重命名的变量
*/
'prefer-template': 'error', // 使用模板字符串,而不是字符串拼接
'rest-spread-spacing': 'error', // 扩展运算符...和表达式之间不允许有空格,如... re1错误,应该是...re1
'template-curly-spacing': 'error', // 禁止模板字符串${}内前后有空格
}
配置环境(开发环境/生产环境)
根目录新建.env.development
.env.production
文件
在其他文件可以通过import.meta.env
拿到环境变量
# .env.development
VITE_APP_NAME='development'
# base api 配置数据请求 基础地址
#解决跨域问题 (接口地址改成本地) vite.config.js
VITE_BASE_URL='/api'
# 配置项目端口号
VITE_PORT=8000
# .env.production
# just a flag
VITE_APP_NAME = 'production'
# base api
VITE_BASE_URL = '/prod-api'
配置代理
vite.config.ts文件
/* eslint-disable object-curly-newline */
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'
// https://vitejs.dev/config/
// config
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default defineConfig(({ command, mode }): any => {
const proces = loadEnv(mode, process.cwd())
// eslint-disable-next-line prefer-destructuring
const port = proces.VITE_PORT
/**
* command - 命令模式
* mode - 生产、开发模式
*/
/*
* const BASE_URl = loadEnv(mode, process.cwd()).VITE_GLOB_BASE_URl;
* const PUBLIC_DIR = loadEnv(mode, process.cwd()).VITE_GLOB_STATIC_SPACE;
* console.log(command, mode, loadEnv(mode, process.cwd()))
*/
console.log('\x1B[34m', '当前命令:', command)
console.log('\x1B[34m', '当前环境:', mode)
console.log('\x1B[37m', '\n环境变量:', proces)
return {
// 项目根目录,index.html 所在的目录
// root:'/',
// 生产或开发环境下的基础路径
// base:'/hboot/',
// 需要用到的插件数组
plugins: [vue()],
// 静态资源服务目录地址
publicDir: '',
// 存储缓存文件的目录地址
cacheDir: '',
// 打包解释项目中的@路径
resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } },
css: {
// postcss-modules 行为配置
modules: {
// ...
},
// 传递给css预处理器的配置项
preprocessorOptions: {
// 指定less预处理的配置项
less: {
// ...
}
}
},
// esbuild 选项转换配置
esbuild: {
/*
* ...
* 在react组件中无需导入react
* jsxInject: `import React from 'react'`,
* vue 使用jsx
*/
jsxFactory: 'h',
jsxFragment: 'Fragment'
},
// 静态资源处理
assetsInclude: '',
// 开发服务器选项
server: {
// ...
host: 'localhost',
port,
open: true, // 帮我们打开浏览器
cors: true, // 允许开发时 ajax 跨域
// 配置跨域请求
proxy: {
//匹配开发环境
'/api': {
// 这里是配置要代理的后端接口
target: 'https://baidu.com',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
},
//匹配生产环境
'/prod-api': {
// 这里是配置要代理的后端接口
target: 'https://baidu.com',
changeOrigin: true,
rewrite: path => path.replace(/^\/prod-api/, '')
}
}
},
base: './', // 设置打包路径,部署需要
// 依赖优化配置项
optimizeDeps: {
// 依赖构建入口
entries: '',
// 排除不需要构建的依赖项
exclude: [],
}
}
})
配置@路径提示
tsconfig.json文件
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
// 配置@路径提示
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
//配置elementUI类型提示
"types": ["element-plus/global","vite/client"],
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }],
"type":["node"],
"exclude": ["node_modules", "dist"]
}
配置git代码提交规范
yarn add -D commitizen cz-customizable @commitlint/cli @commitlint/config-conventional
npm install commitizen cz-customizable @commitlint/cli @commitlint/config-conventional -D
在根目录新建
.commitlintrc.js
和.cz-config.js
文件
参考:
// .commitlintrc.js
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [2, "always", ["init", "feat", "fix", "ui", "bug", "del", "docs", "style", "revert", "test", "perf", "chore", "refactor"]],
"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],
},
};
// .cz-config.js
module.exports = {
types: [
{ value: "🎉init", name: "init: 初始化" },
{ value: "✨feat", name: "feat: 新功能" },
{ value: "🔨fix", name: "fix: 修复缺陷" },
{ value: "🐛bug", name: "bug: 修复问题" },
{ value: "🗑del", name: "del: 删除相关" },
{ value: "📝docs", name: "docs: 文档/注释相关" },
{ value: "💄style", name: "style: 代码格式/样式相关" },
{ value: "⏪revert", name: "revert: 代码回退" },
{ value: "✅test", name: "test: 测试相关" },
{ value: "⚡perf", name: "perf: 性能优化相关" },
{ value: "📦build", name: "build: 代码构建/编译相关" },
{ value: "🚀chore", name: "chore: 构建/工程依赖/工具" },
{ value: "♻refactor", name: "refactor: 代码重构" },
{ value: "👷ci", name: "ci: 持续集成" },
],
scopes: [{ name: "all" }, { name: "doc" }, { name: "pc" }],
messages: {
type: "选择一种你的提交类型(必填):",
scope: "选择一个影响区域 (可选):",
subject: "短说明(必填):\n",
body: '长说明,使用"|"换行(可选):\n',
footer: "关联关闭的issue,例如:#31, #34(可选):\n",
breaking: "非兼容性说明 (可选):\n",
confirmCommit: "确定提交说明?",
},
allowCustomScopes: true,
allowBreakingChanges: ["feat", "fix"],
subjectLimit: 100,
};
然后在package.json文件中配置
"scripts": {
"commit": "git-cz"
}
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
然后就可以通过命令
npm run commit
yarn commit
提交代码啦, 效果是这样的:
注意一点的是vite脚手架创建的项目使用这种规范可能会报这个错误:
配置路由
yarn add vue-router@4
npm i vue-router@4
在src目录下创建router/index.ts文件
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
// 指定 RouteRecordRaw[] 类型后,书写的时候就有 TS 的类型提示和检查了
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/layout/index.vue'),
children: [
{ path: '/', component: () => import('@/views/home/index.vue') },
{ path: '/my', component: () => import('@/views/my/index.vue') },
],
},
{
path: '/login',
component: () => import('@/views/login/index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes,
scrollBehavior: () => ({ top: 0 })
})
// 路由拦截
router.beforeEach((to, from, next) => {
/*
* if (to.hash === '/login') {
* return '/'
* }
*/
console.log(to, from, next())
// return true或者next()就是放行
return true
})
export default router
在main.ts文件引入注册一下
import router from '@/router'
createApp(App).use(router).mount('#app')
使用状态管理pinia
官网: pinia.vuejs.org/
yarn add pinia 安装数据存储插件 yarn add piniaPluginPersistedstate
npm i pinia
在main.ts文件引入注册
import { createPinia } from 'pinia'
// piniaPluginPersistedstate数据存储插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
createApp(App).use(router).use(pinia).mount('#app')
在src目录新建store/index.ts文件
import useTodoStore from './module/todo'
export default function () {
return { todos: useTodoStore() }
}
store/module/todo.ts文件
import { Todo } from '@/type/todo'
import { defineStore } from 'pinia'
const useTodoStore = defineStore({
id: 'todos',
// 数据持久化(当数据发生改变时,保存到本地)
persist: {
key: 'todoList',
paths: ['list'],
},
// 状态
state: () => ({
list: [
{
id: 1,
name: '吃饭',
done: true,
},
] as Todo[]
}),
// 计算属性
getters: {
lists(): Todo[] {
return this.list
}
},
// 异步方法
actions: {
setList(obj: Todo) {
console.log('触发了')
this.list.push({ ...obj })
}
}
})
export default useTodoStore
在页面中使用
import useStore from '@/store'
// storeToRefs响应式
import { storeToRefs } from 'pinia'
const { todos } = useStore()
const { list } = storeToRefs(todos)
console.log(list)
const handleAdd = () => {
// 直接修改
// list.value.push({ id: Date.now(), name: '玩', done: false })
// 调用pinia action函数修改
todos.setList({ id: Date.now(), name: '玩', done: false })
}
使用axios
官网: www.kancloud.cn/yunye/axios…
yarn add axios
npm i axios
在src目录下创建utils/request.ts文件
/* eslint-disable implicit-arrow-linebreak */
import axios from 'axios'
const service = axios.create({
// 请求的地址
baseURL: import.meta.env.VITE_BASE_URL,
// 请求超时时间
timeout: 3 * 60 * 1000,
// 设置请求头
headers: { 'Content-Type': 'application/json' }
})
// 请求拦截器
service.interceptors.request.use(config => config, error =>
// 对请求错误做些什么
Promise.reject(error))
// 响应拦截器
service.interceptors.response.use(response => response, error => Promise.reject(error))
export default service
封装api, 在src目录下创建api/user.ts文件
import request from '@/utils/request'
export function getUserApi(params: any = {}) {
return request({
url: '/home/new',
method: 'get',
params
})
}
在页面使用
import { getUserApi } from '@/api/user'
getUserApi({}).then(res => {
console.log(res)
})