Files
blog-press/docs/Web-Front/Vue/Vue3-Common.md
2025-12-12 14:30:44 +08:00

414 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 一、依赖管理
  本项目会传递安装的依赖有:
| 包名称 | 版本 | 含义和用途说明 |
|-------|------|---------------|
| `@fortawesome/fontawesome-free` | ^6.7.2 | FontAwesome 图标库的免费版本 |
| `@popperjs/core` | ^2.11.8 | 工具提示和弹出框定位引擎 |
| `axios` | ^1.4.0 | 基于 Promise 的 HTTP 客户端 |
| `compressorjs` | ^1.2.1 | 纯 JavaScript 图片压缩库 |
| `crypto-js` | ^4.2.0 | JavaScript 加密算法库 |
| `dayjs` | ^1.11.13 | 轻量级的日期处理库 |
| `echarts` | ^5.5.1 | 百度开源的数据可视化图表库 |
| `element-plus` | ^2.6.0 | 基于 Vue 3 的桌面端 UI 组件库 |
| `js-cookie` | ^3.0.5 | JavaScript Cookie 操作库 |
| `lunar-calendar` | ^0.1.4 | 农历日历转换库 |
| `lunar-javascript` | ^1.6.13 | 农历日期处理的 JavaScript 库 |
| `path-browserify` | ^1.0.1 | Node.js path 模块的浏览器版本兼容实现 |
| `qs` | ^6.13.0 | URL 查询字符串解析和序列化库 |
| `v-calendar` | ^3.1.2 | Vue.js 的日历和日期选择器组件 |
::: tip
如果使用pnpm安装会传递peerDependencies部分。
:::
::: warning
建议将Vite、Typescript、@types等构建工具依赖放在devDependencies中
:::
# 二、vite.config.ts配置
## 2.1 生成Typescript类型文件
  安装vite-plugin-dts插件
```cmd
pnpm add vite-plugin-dts -D
```
```typescript
import dts from 'vite-plugin-dts'
// 打包输出文件夹
const outDirPath = 'dist'
// 需要打包的类型文件
const TARGET_TYPE_FOLDERS = ['src/components', 'src/utils', 'src/types', 'src/vue3-common.ts']
export default defineConfig({
plugins: [
// 生成类型文件
dts({
// 需要处理的文件
include: TARGET_TYPE_FOLDERS,
// 使用特定的 tsconfig 配置
tsconfigPath: path.resolve(__dirname, 'tsconfig.app.json'),
// 类型文件输出目录
outDir: path.resolve(__dirname, outDirPath)
})
],
})
```
  打包后会在dist目录生成.d.ts文件提供完整的Typescript类型支持。
## 2.2 build打包配置
```typescript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import dts from 'vite-plugin-dts'
import path from 'path'
import fs from 'fs'
import { ICommonObj } from './src/types'
// 打包输出文件夹
const outDirPath = 'dist'
// 需要单个打包的文件夹(组件和工具类)
const TARGET_LIB_FOLDERS = ['src/components', 'src/utils']
// 需要排除的第三方依赖
const EXTERNAL = ['vue', 'element-plus', 'echarts', 'axios', 'moment', 'crypto-js', 'spark-md5', 'path-browserify']
/**
* 递归读取文件夹下的所有文件
* @param folderPath 文件夹
*/
const getFilesFromFolder = (folderPath: string) => {
const files: string[] = []
// 读取文件夹中的内容
fs.readdirSync(folderPath).forEach((item: string) => {
const fullPath = path.join(folderPath, item)
// 读取文件状态 如果是文件夹,递归读取
if (fs.statSync(fullPath).isDirectory()) {
files.push(...getFilesFromFolder(fullPath))
} else {
// 否则添加至文件列表
files.push(fullPath)
}
})
return files
}
// 动态生成入口文件
const inputEntries = TARGET_LIB_FOLDERS.reduce((entries: ICommonObj, folder) => {
// 获取文件夹内的所有文件
const files = getFilesFromFolder(path.resolve(__dirname, folder))
files.forEach((filePath) => {
// 判断文件是否是 .vue 或 .ts 文件
if (filePath.endsWith('.vue') || filePath.endsWith('.ts')) {
// 获取相对路径并保持目录结构
const relativePath = path.relative('src', filePath)
const entryName = path.join('lib', relativePath.replace(/\.(vue|ts)$/, ''))
entries[entryName] = filePath // 为每个文件创建一个入口
}
})
return entries
}, {})
// https://vitejs.dev/config/
export default defineConfig({
build: {
// lib文件配置
lib: {
// 入口文件
entry: path.resolve(__dirname, 'src/vue3-common.ts'),
formats: ['es'],
name: 'vue3-common',
// 文件名
fileName: (format) => `vue3-common.${format}.js`
},
// 输出文件路径
outDir: outDirPath,
// 是否将css文件分割
cssCodeSplit: true,
// Rollup打包配置
rollupOptions: {
// 需要排除的依赖 通常为第三方库
external: EXTERNAL,
// 输入配置
input: {
// 入口文件
'vue3-common': path.resolve(__dirname, 'src/vue3-common.ts'),
// 其余需要单独打包的文件
...inputEntries
},
// 输出配置
output: {
dir: path.resolve(__dirname, outDirPath),
// 入口文件
entryFileNames: '[name].js',
// chunk文件
chunkFileNames: 'lib/[name].js',
// 资源文件
assetFileNames: 'styles/[name].[ext]'
}
},
// 是否压缩代码
minify: false
}
})
```
  打包后会在dist目录生成源码文件。
# 三、package.json配置
## 3.1 导出路径
```json
{
"exports": {
".": {
"import": "./dist/vue3-common.js",
"require": "./dist/vue3-common.js",
"types": "./dist/vue3-common.d.ts"
},
"./components/SvgIcon.vue": {
"import": "./dist/lib/components/SvgIcon.js",
"types": "./dist/components/SvgIcon.vue.d.ts"
},
"./styles/SvgIcon.css": "./dist/styles/SvgIcon.css",
"./components/LoginForm.vue": {
"import": "./dist/lib/components/LoginForm.js",
"types": "./dist/components/LoginForm.vue.d.ts"
},
"./styles/LoginForm.css": "./dist/styles/LoginForm.css",
"./components/MenuItem.vue": {
"import": "./dist/lib/components/MenuItem.js",
"types": "./dist/components/MenuItem.vue.d.ts"
},
"./components/MenuList.vue": {
"import": "./dist/lib/components/MenuList.js",
"types": "./dist/components/MenuList.vue.d.ts"
},
"./components/Hamburger.vue": {
"import": "./dist/lib/components/Hamburger.js",
"types": "./dist/components/Hamburger.vue.d.ts"
},
"./styles/Hamburger.css": "./dist/styles/Hamburger.css",
"./components/MultiInput.vue": {
"import": "./dist/lib/components/MultiInput.js",
"types": "./dist/components/MultiInput.vue.d.ts"
},
"./styles/MultiInput.css": "./dist/styles/MultiInput.css",
"./types": {
"types": "./dist/types/index.d.ts"
},
"./utils/axiosUtil": {
"import": "./dist/lib/utils/axiosUtil.js",
"types": "./dist/types/utils/axiosUtil.d.ts"
},
"./utils/cryptoUtil": {
"import": "./dist/lib/utils/cryptoUtil.js",
"types": "./dist/types/utils/cryptoUtil.d.ts"
},
"./utils/dataUtil": {
"import": "./dist/lib/utils/dataUtil.js",
"types": "./dist/types/utils/dataUtil.d.ts"
},
}
}
```
  在项目中引入common包后通过配置tsconfig.json即可实现按需引入功能`import { fun1 } from 'vue3-common/utils/index'`
```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"vue3-common/*": ["node_modules/vue3-common/dist/*"]
}
}
}
```
# 四、发布框架
1. 发布到本地
执行`npm pack`命令,会在项目文件夹下生成`.tgz`文件,其他项目通过文件路径形式引入:
```json
"vue3-common": "file:../vue3-common/vue3-common-1.0.0.tgz"
```
2. 发布到git
将dist文件夹发布到git仓库其他项目通过git形式引入
```json
"vue3-common": "git+https://gitee.com/Cxx0822/vue3-common#master"
```
# 五、组件使用说明
## 5.1 菜单组件
1. 安装Vue Router
```cmd
pnpm install vue-router
```
2. 在src/views文件夹中新建vue文件例如
```cmd
views
viewA
index.vue
viewB
index.vue
```
3. 在src/views文件夹下新建meta.ts配置文件
```typescript
import type { IRouteMetaConfig } from 'vue3-common/types'
export const metaList: IRouteMetaConfig = {
'/viewA': {
title: 'viewA',
icon: 'viewA',
order: 1,
redirect: '/viewA/index'
},
'/viewA/index': {
title: 'viewA-Index',
icon: ''
},
'/viewB': {
title: 'viewB',
icon: 'viewB',
order: 2,
redirect: '/viewB/index'
},
'/viewB/index': {
title: 'viewB-index',
icon: ''
}
}
```
  order对应的显示顺序关系icon对应的为src/icons/svg中的svg图标文件参考下文图标组件
4. 在src目录新建router文件夹新建menu.ts文件
```typescript
import { getRoutersByModules, sortRoutesByOrder } from 'vue3-common/utils/routerUtil'
import Layout from '@/layout/index.vue'
import { metaList } from '@/views/meta'
const modules = {
...import.meta.glob('@/views/viewA/**/*.vue'),
...import.meta.glob('@/views/viewB/**/*.vue'),
}
const menuRoutes = getRoutersByModules(modules, Layout, metaList)
export default sortRoutesByOrder(menuRoutes)
```
  导入刚才的views文件夹并生成路由菜单。
5. 如果还有其他的常量路由可以在src/router中新建constant.ts文件
```typescript
import type { RouteRecordRaw } from 'vue-router'
const constantRoutes: RouteRecordRaw[] = [
{
path: '/',
redirect: '/login'
},
// 主页
{
path: '/login',
component: () => import('@/views/login/index.vue'),
meta: { hidden: true }
}
]
export default constantRoutes
```
  该部分即Vue Router中的路由定义。
6. 在src/router中新建index.ts
```typescript
import { createRouter, createWebHashHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { setupRouteGuard } from 'vue3-common/utils/permissionUtil'
// 使用 import.meta.glob 自动导入所有 src/router 目录下的 .ts 文件
const routeModules = import.meta.glob('./*.ts', { eager: true })
// 将所有模块的默认导出(即路由配置)合并成一个路由数组
const routes: RouteRecordRaw[] = Object.values(routeModules)
.map((module: any) => module.default) // 获取每个模块的默认导出
.flat() // 扁平化数组,确保所有路由项都在一个数组中
const router = createRouter({
history: createWebHashHistory(),
scrollBehavior: () => ({ top: 0 }),
routes
})
// 设置路由守卫
setupRouteGuard(router)
export default router
```
  遍历src/router文件夹下所有的路由文件并添加路由守卫。
7. 在main.ts中配置路由
```ts
// 引入路由
import router from './router'
// 创建Vue3实例
const app = createApp(App)
// 使用路由
app.use(router)
```
## 5.2 图标组件
1. 安装vite-plugin-svg-icons依赖
```cmd
pnpm install vite-plugin-svg-icons -D
```
2. 配置vite.config.ts
```typescript
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定 SVG图标 保存的文件夹路径
iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
// 指定 使用svg图标的格式
symbolId: 'icon-[dir]-[name]'
})
],
})
```
3. 在main.ts中注册
```typescript
// 注册svg-icon
import 'virtual:svg-icons-register'
```
4. 在src/icons/svg目录中添加svg图标
5. 在组件中使用
```vue
<template>
<svg-icon name="user"/>
</template>
<script setup>
import { SvgIcon } from 'vue3-common'
</script>
```