创建vue3项目

1
pnpm create vue@latest

img


安装pnpm依赖

1
2
pnpm install
pnpm install --save-dev @types/node

tsconfig.json配置别名路径

配置别名路径可以在写代码时联想提示路径

1
2
3
4
5
6
7
8

"compilerOptions" : {
"baseUrl" : "./",
"paths" : {
"@/*":["src/*"]
},
}


elementPlus引入

官方文档: https://element-plus.org/zh-CN/

1
2
pnpm add element-plus
pnpm add @element-plus/icons-vue

自动按需:

1
2
3
pnpm add -D unplugin-vue-components unplugin-auto-import
pnpm i unplugin-element-plus -D
pnpm install unplugin-icons -D

修改配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// vite.config.ts

// 引入插件
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import ElementPlus from 'unplugin-element-plus/vite'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'



export default defineConfig({
plugins: [
vue(),
AutoImport({
// Auto import functions from Vue, e.g. ref, reactive, toRef...
// 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
imports: ['vue'],

// Auto import functions from Element Plus, e.g. ElMessage, ElMessageBox... (with style)
// 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
resolvers: [
ElementPlusResolver(),

// Auto import icon components
// 自动导入图标组件
IconsResolver({
prefix: 'Icon',
}),
],
}),

Components({
resolvers: [
// Auto register icon components
// 自动注册图标组件
IconsResolver({
enabledCollections: ['ep'],
}),
// Auto register Element Plus components
// 自动导入 Element Plus 组件
ElementPlusResolver(),
],
directoryAsNamespace: true
}),

Icons({
autoInstall: true,
compiler: 'vue3'
}),

// 按需定制主题配置
ElementPlus({
useSource: true,
})
],
})
1
2
3
// src/main.ts

import 'element-plus/theme-chalk/src/index.scss' // [!code ++]

安装sass

基于vite的项目默认不支持css预处理器,需要开发者单独安装

1
pnpm i sass -D

定制化样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// vite.config.ts

export default defineConfig({
plugins: [
...
],
css: {
preprocessorOptions: {
scss: {
// 自动导入定制化样式文件进行样式覆盖
// additionalData:
}
}
}
})

配置pinia和持久化插件

安装持久化存储插件: pinia-plugin-persistedstate

1
pnpm i pinia-plugin-persistedstate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/stores/index.ts
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'

// 创建 pinia 实例
const pinia = createPinia()
// 使用持久化存储插件
pinia.use(persist)

// 默认导出,给 main.ts 使用
export default pinia

// 模块统一导出
export * from './modules/client'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// src/stores/modules/client.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'

// 定义 Store
export const useClientStore = defineStore(
'client',
() => {
const token = ref()
const setToken = (val:string)=>{
token.value = val
}
const clearToken = ()=>{
token.value = undefined
}
return {
token,
setToken,
clearToken
}
},
{
persist: true
},
)
1
2
3
4
5
6
7
// src/main.ts

import pinia from './stores' // [!code ++]
app.use(pinia) // [!code ++]

import { createPinia } from 'pinia' // [!code --]
app.use(createPinia()) // [!code --]

设置router为哈希模式

1
2
3
4
5
6
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
...
})

懒加载指令实现

安装vueuse插件

1
pnpm i @vueuse/core

1. 封装全局指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// src/directives/index.ts

// 定义懒加载插件
import { useIntersectionObserver } from '@vueuse/core'

export const lazyPlugin = {
install (app:any) {
// 懒加载指令逻辑
app.directive('img-lazy', {
mounted (el:any, binding:any) {
// el: 指令绑定的那个元素 img
// binding: binding.value 指令等于号后面绑定的表达式的值 图片url
console.log(el, binding.value)
const { stop } = useIntersectionObserver(
el,
([{ isIntersecting }]) => {
console.log(isIntersecting)
if (isIntersecting) {
// 进入视口区域
el.src = binding.value
stop()
}
},
)
}
})
}
}

2. 注册全局指令

1
2
3
// 全局指令注册
import { lazyPlugin } from '@/directives'
app.use(lazyPlugin)

axios组件

1. 安装axios

1
pnpm i axios

2. 基础配置

官方文档地址:https://axios-http.com/zh/docs/intro
基础配置通常包括:

  1. 实例化 - baseURL + timeout
  2. 拦截器 - 携带token 401拦截等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { useClientStore } from '@/stores'
import axios from 'axios'
import router from '@/router'
import { ElMessage } from 'element-plus'

const baseURL = 'http://localhost:8080'

const instance = axios.create({
baseURL,
timeout: 100000
})

instance.interceptors.request.use(
(config) => {
const clientStore = useClientStore()
if (clientStore.token) {
config.headers.Authorization = clientStore.token
}
return config
},
(err) => Promise.reject(err)
)


instance.interceptors.response.use(
(res) => {
if (res.data.code === 200) {
return res
}
ElMessage({ message: res.data.message || '服务异常', type: 'error' })
return Promise.reject(res.data)
},
(err) => {
ElMessage({ message: err.response.data.message || '服务异常', type: 'error' })
console.log(err)
if (err.response?.status === 401) {
router.push('/login')
}
return Promise.reject(err)
}
)

export default instance
export { baseURL }
export interface Data<T> {
code: string
msg: string
result: T
}

3.API模板

1
2
3
4
5
6
7
8
9
10
11
import { LoginParams, LoginResult } from '@/types/login'
import request from '@/utils/axios.ts'
import { Data } from '@/utils/axios.ts'

export const loginAPI = (params: LoginParams): Promise<Data<LoginResult>> => {
return request({
url: '/login',
method: 'post',
data: params
}).then(res=>res.data as Data<LoginResult>)
}

使用tailwindcss

1.安装插件

1
2
pnpm install -D tailwindcss
npx tailwindcss init

2.配置tailwindcss.config.js

1
2
3
4
5
6
7
8
9
10
11
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

3.增入样式

1
2
3
4
5
// src/input.css 

@tailwind base;
@tailwind components;
@tailwind utilities;

4.构建编译

1
npx tailwindcss -i ./src/input.css -o ./src/output.css

5.添加至项目

1
2
3
4
5
6
7
8
9
10
11
12
// index.html

<!doctype html>
<html>
<head>
...,
<link href="./output.css" rel="stylesheet"> [! code++]
</head>
<body>
...
</body>
</html>

使用Echarts

1.安装插件

1
pnpm add echarts  vue-echarts

2.全局导出组件

1
2
3
// src/main.ts

import 'echarts' [! code++]

3.项目引入

1
import VChart from "vue-echarts";

ESLint & prettier 配置代码风格

环境同步:

  1. 安装了插件 ESlint,开启保存自动修复
  2. 禁用了插件 Prettier,并关闭保存自动格式化
1
2
3
4
5
// ESlint插件 + Vscode配置 实现自动格式化修复
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"editor.formatOnSave": false,

配置文件 .eslintrc.cjs

  1. prettier 风格配置 https://prettier.io

    1. 单引号

    2. 不使用分号

    3. 每行宽度至多80字符

    4. 不加对象|数组最后逗号

    5. 换行符号不限制(win mac 不一致)

  2. vue组件名称多单词组成(忽略index.vue)

  3. props解构(关闭)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rules: {
'prettier/prettier': [
'warn',
{
singleQuote: true, // 单引号
semi: false, // 无分号
printWidth: 80, // 每行宽度至多80字符
trailingComma: 'none', // 不加对象|数组最后逗号
endOfLine: 'auto' // 换行符号不限制(win mac 不一致)
}
],
'vue/multi-word-component-names': [
'warn',
{
ignores: ['index'] // vue组件名称多单词组成(忽略index.vue)
}
],
'vue/no-setup-props-destructure': ['off'], // 关闭 props 解构的校验
// 💡 添加未定义变量错误提示,create-vue@3.6.3 关闭,这里加上是为了支持下一个章节演示。
'no-undef': 'error'
}

完结撒花