diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index aff5304..aed810d 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -28,6 +28,14 @@ export default defineConfig({ { text: 'Flutter', link: '/Flutter/' }, ], sidebar: { + '/Web-Front/': [ + { + text: 'Web前端', + items: [ + { text: 'Vue3-Common', link: '/Web-Front/Vue3-Common' }, + ] + }, + ], '/Web-Backend/': [ { text: 'Web后端', diff --git a/docs/Web-Front/Vue3-Common.md b/docs/Web-Front/Vue3-Common.md new file mode 100644 index 0000000..9f19941 --- /dev/null +++ b/docs/Web-Front/Vue3-Common.md @@ -0,0 +1,411 @@ +# 一、依赖管理 +  本项目会传递安装的依赖有: +| 包名称 | 版本 | 含义和用途说明 | +|-------|------|---------------| +| `@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 + + + +``` \ No newline at end of file diff --git a/docs/Web-Front/index.md b/docs/Web-Front/index.md index dad279f..de19f51 100644 --- a/docs/Web-Front/index.md +++ b/docs/Web-Front/index.md @@ -4,3 +4,5 @@ title: Web前端 --- # 内容导航 + +- [Vue3-Common](/Web-Front/Vue3-Common) \ No newline at end of file