✨
搭建一个开箱即用的基于 Vue-Cli + Vue2 + Vuex + Vant + TailwindCSS + TypeScript 的工程
UI框架以 Vant 为例
编写此笔记时所使用的Vue-Cli
版本为5.0.0
,Vue
版本为2.6.14
相关文档
- Vue-Cli
- Vue2
- Vuex
- Vue-Router
- vuex-composition-helpers
- vuex-persistedstate
- Vant
- TailwindCSS
- TypeScript
- ESLint
- Prettier
初始化项目
npm i -g @vue/cli
vue create vue-cli-starter
按照提示操作即可,这样一个基础项目就创建好了
💡
通过上述交互式命令的选项,我们创建了一个带有vue-router
、vuex
、ESLint
和Prettier
的基于 Vue-Cli 脚手架的 Vue2 项目
编辑tsconfig.json
,关闭空检查
{
"compilerOptions": {
// ...
"strictNullChecks": false,
"noImplicitAny": false
}
}
配置EditorConfig
新建.editorconfig
,设置编辑器和 IDE 规范,内容根据自己的喜好或者团队规范
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
配置ESLint和Prettier
新建.prettierrc
和.prettierignore
文件,填入自己喜欢的配置
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"printWidth": 120,
"singleQuote": true,
"trailingComma": "es5"
}
node_modules
dist
编辑.eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
node: true,
},
extends: [
'plugin:vue/essential',
'eslint:recommended',
'@vue/typescript/recommended',
'prettier',
'plugin:prettier/recommended',
],
plugins: ['prettier'],
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
},
rules: {
'prettier/prettier': 'error',
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
},
}
安装TailwindCSS
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
编辑tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./public/index.html', './src/**/*.{vue,jsx,tsx}'],
corePlugins: {
preflight: true,
},
plugins: [],
}
新建src/assets/tailwind.css
,填写如下内容,然后在src/main.ts
引入它
@tailwind base;
@tailwind components;
@tailwind utilities;
// ...
import './assets/tailwind.css'
环境变量
关于 Vue-Cli 的环境变量,可以参考官方文档
新建.env
文件,填入项目所需的环境变量。注意,自定义环境变量名必须以VUE_APP_
开头,否则不会被识别,例如
VUE_APP_NAME=vue-cli-starter
VUE_APP_HOST=localhost
VUE_APP_PORT=8080
API_HOST=http://localhost
API_PORT=8080
VUE_APP_BASE_API=$API_HOST:$API_PORT
之后就可以在代码中以 process.env.VUE_APP_XXX
的形式使用自定义环境变量了
迁移至Vue2.7
pnpm update vue
pnpm update @vue/cli*
pnpm update eslint-plugin-vue@9
pnpm rm vue-template-compiler
rm pnpm-lock.yaml
rm -rf node_modules
pnpm install
编辑tsconfig.json
,添加vueCompilerOptions
字段
{
// ...
"vueCompilerOptions": {
"target": 2.7
}
}
由于vuex
和vue-router
均为不支持组合式API
的v3
版本,需要通过中间函数来代替访问this
下的一些实例方法。新建src/hooks/index.ts
,添加如下代码
import { getCurrentInstance } from 'vue'
export function useStore() {
const { proxy } = getCurrentInstance()
const store = proxy.$store
return store
}
export function useRouter() {
const { proxy } = getCurrentInstance()
const router = proxy.$router
return router
}
export function useRoute() {
const { proxy } = getCurrentInstance()
const route = proxy.$route
return route
}
但是vuex
的mapState
、mapGetters
、mapActions
和mapMutations
辅助函数依然是无法使用的,如果想使用这些辅助函数,可以尝试安装vuex-composition-helpers
这个库
pnpm add vuex-composition-helpers@1.2.0
助手函数
新建src/utils/utils.ts
,封装一些辅助函数,具体代码参考我的助手函数封装
请求模块
pnpm add axios
新建src/api/core/http.ts
和src/api/core/config.ts
,之后的封装逻辑参考我的Axios封装
Mock
pnpm add -D vue-cli-plugin-mock mockjs @types/mockjs
根目录新建mock/index.js
,示例如下,根据自己的情况添加添加接口
export default {
'POST /api/login': {
code: '200',
message: 'ok',
data: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MjMyODU2LCJzZXNzaW9uIjoiOTRlZTZjOThmMmY4NzgzMWUzNzRmZTBiMzJkYTIwMGMifQ.z5Llnhe4muNsanXQSV-p1DJ-89SADVE-zIkHpM0uoQs',
success: true,
},
}
- 使用
import { request } from './api'
request('/api/login', { method: 'POST' })
注意,vue-cli-plugin-mock
默认是以当前开发服务器的host
和post
作为baseURL
状态管理
示例
编辑src/store/index.ts
和src/views/AboutView.vue
export default new Vuex.Store({
state: {
count: 0,
},
getters: {},
mutations: {
increment(state) {
state.count++
},
decrement(state) {
state.count--
},
},
actions: {},
modules,
})
<template>
<div class="about">
<h1>This is an about page</h1>
<div>
<button @click="decrement()">-</button>
<span class="mx-3">{{ count }}</span>
<button @click="increment()">+</button>
</div>
</div>
</template>
<script lang="ts" setup>
import { useState, useMutations } from 'vuex-composition-helpers'
const { count } = useState(['count'])
const { increment, decrement } = useMutations(['increment', 'decrement'])
</script>
持久化
pnpm add vuex-persistedstate
- 新建
src/store/modules/user.ts
type State = typeof state
const state = {
token: '',
isLogged: false,
}
const mutations = {
setToken(state: State, token: string) {
state.token = token
state.isLogged = true
},
removeToken(state: State) {
state.token = ''
state.isLogged = false
},
}
const actions = {}
export default {
namespaced: true,
state,
mutations,
actions,
}
- 编辑
src/store/index.ts
// ...
import createPersistedState from 'vuex-persistedstate'
// 导入其他vuex模块
const modulesFiles = require.context('./modules', true, /\.ts$/)
const modules = modulesFiles.keys().reduce((modules: Record<string, unknown>, modulePath) => {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
export default new Vuex.Store({
plugins: [createPersistedState()],
modules,
// ...
})
- 使用
<template>
<div class="flex justify-center gap-3">
<button @click="login">Login</button>
<button @click="removeToken()">Logout</button>
</div>
</template>
<script lang="ts" setup>
import { useMutations } from 'vuex-composition-helpers'
import { request } from '@/api'
const { setToken, removeToken } = useMutations('user', ['setToken', 'removeToken'])
const login = async () => {
const res = await request('/api/login', { method: 'POST' })
setToken(res.data)
}
</script>
UI框架
使用Vant
pnpm add vant@latest-v2
按需引入
⚡ 注意
由于迁移至Vue2.7
后,Vant2
文档中的使用babel-plugin-import
进行按需加载的方式失效了。需要改成用Vue3
的方式进行按需加载
pnpm add -D @vant/auto-import-resolver unplugin-vue-components
编辑vue.config.js
const { VantResolver } = require('@vant/auto-import-resolver')
const ComponentsPlugin = require('unplugin-vue-components/webpack')
module.exports = defineConfig({
// ...
configureWebpack: {
plugins: [
ComponentsPlugin({
resolvers: [VantResolver()],
}),
],
},
})
这样就完成了 Vant 的按需引入,就可以直接在模板中使用 Vant 组件了,unplugin-vue-components
会解析模板并自动注册对应的组件,@vant/auto-import-resolver
会自动引入对应的组件样式
移动端适配
此插件的参数配置文档看这里
pnpm add -D postcss-px-to-viewport-8-plugin
⚡注意
由于Vant
使用的设计稿宽度是375
,而通常情况下,设计师使用的设计稿宽度更多是750
,那么Vant
组件在750
设计稿下会出现样式缩小的问题
解决方案: 当读取的node_modules
文件是vant
时,那么就将设计稿宽度变为375
,读取的文件不是vant
时,就将设计稿宽度变为750
编辑postcss.config.js
,增加如下postcss-px-to-viewport-8-plugin
配置项
const path = require('path')
module.exports = {
plugins: {
// ...
'postcss-px-to-viewport-8-plugin': {
viewportWidth: (file) => {
return path.resolve(file).includes(path.join('node_modules', 'vant')) ? 375 : 750
},
unitPrecision: 6,
landscapeWidth: 1024,
},
},
}