Skip to content

ZsTs119/vue3-multi-platform

Repository files navigation

vue3-multi-platform Vue3 多端统一开发框架

Vue Vite TypeScript Element Plus Vant Pinia License Multi-Platform Dark Mode Auto-Import Theme System

Vue3 多端统一开发框架 - 快速构建跨平台应用,省时省力"。

🚀 特性一览

  • 现代技术栈:Vite 5.2 + Vue 3.5 + TypeScript 5.3 + Pinia 2.1
  • 多端适配:一套代码,同时支持 H5 和 PC 端
  • UI 组件库:Element Plus 2.7 (PC 端) + Vant 4.9 (移动端)
  • 自动导入:组件和 API 自动导入,无需手动 import
  • 主题系统:支持多主题切换,内置暗黑模式
  • 权限控制:完整的登录认证和权限管理
  • 状态管理:基于 Pinia 的状态管理,支持持久化
  • 请求封装:Axios 请求封装,支持常规请求和流式请求
  • 安全防护:内置请求签名和设备指纹识别
  • 图标系统:SVG 图标和 Iconfront 图标组件封装
  • 自定义 Hooks:常用功能封装为 Hooks
  • 构建优化:自动代码分割、压缩和优化
  • Cursor 规则:提供详细的项目规范文档,支持 Cursor AI 开发助手智能理解项目架构和开发规范

📁 目录结构

src/ ├── apis/ # API 接口 │ ├── modules/ # 按模块组织的API │ │ ├── user.ts # 用户相关API │ │ └── script.ts # 脚本相关API │ ├── types/ # API类型定义 │ └── index.ts # 统一导出 ├── assets/ # 静态资源 │ └── icons/ # 图标资源 ├── components/ # 公共组件 │ ├── SvgIcon/ # SVG图标组件 │ ├── InconFent/ # Iconfront图标组件 │ └── ThemeSwitch/ # 主题切换组件 ├── hooks/ # 自定义Hooks │ ├── useNProgress.ts # 进度条Hook │ └── useThemeTransition.ts # 主题切换过渡动画Hook ├── router/ # 路由配置 │ ├── home/ # 首页路由模块 │ ├── login/ # 登录路由模块 │ └── index.ts # 路由主文件 ├── stores/ # 状态管理 │ ├── theme.ts # 主题状态 │ ├── token.ts # Token管理 │ ├── user.ts # 用户信息 │ └── login.ts # 登录状态 ├── styles/ # 全局样式 │ ├── themes/ # 主题相关 │ │ └── variables.scss # 主题变量定义 │ ├── transitions/ # 过渡动画 │ │ └── theme.scss # 主题切换动画 │ └── mixins/ # 样式混入 ├── utils/ # 工具函数 │ ├── http/ # HTTP请求封装 │ ├── device.ts # 设备信息 │ └── index.ts # 工具统一导出 └── views/ # 页面组件 ├── login/ # 登录页面 ├── home/ # 首页 ├── settings/ # 设置页面 └── error/ # 错误页面 

📚 项目规范指南

项目内置了七大核心规范,确保开发过程中的一致性和高质量代码输出:

1. 项目介绍规范

项目基于现代前端技术栈构建,核心技术包括:

  • Vue 3.5.x、TypeScript 5.3.x、Vite 5.2.x
  • 状态管理:Pinia 2.1.x (含持久化)
  • UI 组件库:Element Plus 2.7.x (PC 端)、Vant 4.9.x (移动端)
  • 工具库:Axios、Lodash-es、TypeScript-MD5 等

2. 项目结构规范

项目采用模块化、分层次的目录结构,主要包括:

  • apis: API 接口层,按业务模块组织
  • components: 全局公共组件
  • hooks: 自定义 Hooks
  • router: 路由配置,模块化管理
  • stores: Pinia 状态管理
  • styles: 全局样式和主题系统
  • utils: 工具函数
  • views: 页面组件

3. API 使用规范

API 请求采用统一封装,包含权限认证、请求签名、错误处理等机制:

  • 请求流程:参数准备 → 权限验证 → 请求签名 → 设备指纹 → 请求发送 → 响应处理
  • API 定义规范:按业务模块分组、类型严格定义、命名规范统一
  • 支持常规请求和流式请求两种方式

4. 代码注释规范

采用 JSDoc 风格的注释规范:

  • 函数和方法:包含描述、参数说明、返回值说明、示例
  • 类和接口:包含描述、属性说明
  • 复杂业务逻辑:分步骤说明
  • 特殊处理或边界条件:详细说明原因和处理方式

5. 核心 Hooks 与方法

项目封装了多个核心 Hooks 和工具方法:

  • 用户认证与权限:useUserStoreuseTokenStore
  • 主题管理:useThemeStoreuseThemeTransition
  • HTTP 请求:标准请求和流式请求封装
  • 进度条:useNProgress
  • 安全工具:设备指纹、请求签名

6. 新增模块规范

添加新功能模块的标准流程:

  • 创建 API 模块:定义接口、参数和响应类型
  • 创建视图组件:页面组件及私有组件
  • 创建路由配置:定义路由、权限和元信息
  • 创建状态管理:定义 State、Getters 和 Actions

7. 代码风格规范

基于 Airbnb JavaScript 风格指南,结合 Vue 官方风格指南:

  • 变量与引用:优先使用 const,需要重新赋值时使用 let
  • 函数:优先使用箭头函数,使用参数默认值
  • 组件:使用 PascalCase 命名,详细定义 Props
  • TypeScript:严格类型定义,提高代码可读性
  • 命名规范:描述性命名,遵循命名约定

🛠️ 快速开始

安装依赖

pnpm install

开发环境

# PC端开发 pnpm dev # H5端开发 pnpm dev:h5

生产环境

# PC端生产环境 pnpm pro # H5端生产环境 pnpm proH5

构建项目

# PC端构建(开发环境) pnpm build:dev # H5端构建(开发环境) pnpm build:dev:h5 # PC端构建(生产环境) pnpm build:prod # H5端构建(生产环境) pnpm build:prod:h5

📘 开发指南

主题系统

项目内置了强大的主题系统,支持多主题切换和平滑过渡动画。

1. 主题配置

主题变量定义在 src/styles/themes/variables.scss 中:

// 基础变量定义 $themes: ( light: ( // 亮色主题 --primary-color: #409eff, --bg-color: #ffffff, --text-primary: #303133, // 更多变量... ), dark: ( // 暗色主题 --primary-color: #409eff, --bg-color: #141414, --text-primary: #ffffff, // 更多变量... ), // 可以添加更多自定义主题... red: ( --primary-color: #f56c6c, // 红色主题的其他变量... ), );

2. 使用主题切换组件

在页面中引入 ThemeSwitch 组件:

<template> <div class="container"> <!-- 主题切换按钮 --> <ThemeSwitch /> <!-- 页面内容 --> </div> </template> <script setup lang="ts"> import ThemeSwitch from "@/components/ThemeSwitch/index.vue"; import { useThemeStore } from "@/stores/theme";  // 获取主题状态管理实例 const themeStore = useThemeStore();  // 在组件挂载时初始化主题 onMounted(() => {  themeStore.initTheme(); }); </script>

3. 在父容器中应用主题

在父容器中应用主题变量和过渡动画:

<template> <div class="app-container"> <!-- 页面内容 --> </div> </template> <style lang="scss"> // 导入主题过渡动画样式 @import "@/styles/transitions/theme.scss";  .app-container {  // 使用主题混入  @include useTheme;   // 使用主题变量  background: var(--bg-color);  color: var(--text-primary); } </style>

4. 主题状态管理

通过 useThemeStore 可以手动控制主题:

import { useThemeStore } from "@/stores/theme"; const themeStore = useThemeStore(); // 切换到暗色主题 themeStore.setTheme("dark"); // 切换到亮色主题 themeStore.setTheme("light"); // 切换到自定义主题 themeStore.setTheme("red"); // 切换暗黑/亮色模式 themeStore.toggleDarkMode(); // 获取当前主题 console.log(themeStore.currentTheme); // 检查是否为暗黑模式 console.log(themeStore.isDarkMode);

5. 主题过渡动画

项目使用 View Transitions API 实现平滑的主题切换动画,通过 useThemeTransition Hook 封装:

import { useThemeTransition } from "@/hooks/useThemeTransition"; const { handleThemeChange } = useThemeTransition(); // 切换主题并应用过渡动画 // 参数1: 目标主题 // 参数2: 触发元素 (可选,用于动画起点) // 参数3: 动画选项 (可选) handleThemeChange("dark", triggerElement, { duration: 500, easing: "cubic-bezier(0.4, 0, 0.2, 1)", });

6. 自定义主题

要添加新主题,只需在 src/styles/themes/variables.scss 中的 $themes 变量中添加新的主题配置:

$themes: ( light: ( /* 亮色主题变量 */ ), dark: ( /* 暗色主题变量 */ ), // 添加新主题 purple: ( --primary-color: #722ed1, --bg-color: #f9f0ff, --text-primary: #333333, // 其他变量... ), );

API 请求

1. 创建 API 模块

src/apis/modules 目录下创建模块文件:

// src/apis/modules/product.ts import axiosInstance from "@/utils/http"; import type { RequestData } from "../types/common"; interface ProductParams { id: string; name: string; } // 获取产品列表 export const getProducts = (params: ProductParams) => { const requestData: RequestData<ProductParams> = { parameter: params, }; return axiosInstance.post("/api/products", requestData); };

2. 导出 API 模块

src/apis/index.ts 中导出新模块:

// src/apis/index.ts export * as userApi from "./modules/user"; export * as scriptApi from "./modules/script"; export * as productApi from "./modules/product"; // 新增

3. 使用 API

在组件中使用 API:

// 方式1: 直接导入 import { getProducts } from "@/apis/modules/product"; // 方式2: 通过统一导出使用 import { productApi } from "@/apis"; const fetchData = async () => { try { // 方式1 const res1 = await getProducts({ id: "1", name: "test" }); // 方式2 const res2 = await productApi.getProducts({ id: "1", name: "test" }); console.log(res1, res2); } catch (error) { console.error(error); } };

状态管理

1. 创建 Store

src/stores 目录下创建新的 store:

// src/stores/product.ts import { defineStore } from "pinia"; interface Product { id: string; name: string; price: number; } interface ProductState { products: Product[]; loading: boolean; } export const useProductStore = defineStore("productStore", { state: (): ProductState => ({ products: [], loading: false, }), getters: { totalProducts: (state) => state.products.length, totalPrice: (state) => state.products.reduce((sum, product) => sum + product.price, 0), }, actions: { setProducts(products: Product[]) { this.products = products; }, addProduct(product: Product) { this.products.push(product); }, async fetchProducts() { this.loading = true; try { // 使用API获取数据 const { data } = await productApi.getProducts({}); this.setProducts(data); } catch (error) { console.error(error); } finally { this.loading = false; } }, }, // 持久化配置 persist: true, });

2. 使用 Store

在组件中使用 store:

import { useProductStore } from "@/stores/product"; // 在setup中使用 const productStore = useProductStore(); // 读取状态 console.log(productStore.products); console.log(productStore.totalProducts); // getter // 修改状态 productStore.setProducts([...]); productStore.addProduct({ id: "1", name: "Product 1", price: 99 }); // 调用异步action productStore.fetchProducts();

路由管理

1. 创建页面组件

src/views 目录下创建页面组件:

<!-- src/views/product/index.vue --> <template> <div class="product-container"> <h1>产品列表</h1> <div v-if="loading">加载中...</div> <ul v-else> <li v-for="item in products" :key="item.id"> {{ item.name }} - {{ item.price }} </li> </ul> </div> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; import { productApi } from "@/apis";  const products = ref([]); const loading = ref(false);  const fetchProducts = async () => {  loading.value = true;  try {  const { data } = await productApi.getProducts({});  products.value = data;  } catch (error) {  console.error(error);  } finally {  loading.value = false;  } };  onMounted(() => {  fetchProducts(); }); </script>

2. 创建路由模块

src/router 目录下创建路由模块:

// src/router/product/productRouter.ts const productRouter = [ { path: "/products", name: "Products", component: () => import("@/views/product/index.vue"), meta: { requiresAuth: true, title: "产品列表", }, }, { path: "/products/:id", name: "ProductDetail", component: () => import("@/views/product/detail.vue"), meta: { requiresAuth: true, title: "产品详情", }, }, ]; export default productRouter;

3. 注册路由模块

在主路由文件中引入并注册路由模块:

// src/router/index.ts import { createRouter, createWebHistory } from "vue-router"; import homeRouter from "./home/homeRouter"; import loginRouter from "./login/loginRouter"; import productRouter from "./product/productRouter"; // 新增 const routes = [ // 其他路由... ...homeRouter, ...loginRouter, ...productRouter, // 注册产品路由 ]; const router = createRouter({ history: createWebHistory(), routes, }); export default router;

环境变量配置

项目支持多环境配置,可以在根目录创建不同的环境变量文件:

  • .env - 所有环境通用的变量
  • .env.development - 开发环境变量
  • .env.production - 生产环境变量
  • .env.developmentH5 - H5 开发环境变量
  • .env.productionH5 - H5 生产环境变量

示例配置:

# .env.development VITE_NODE_ENV=development VITE_API_BASE_URL=/api VITE_TEST_URL=http://dev-api.example.com VITE_PRO_URL=http://api.example.com

在代码中使用环境变量:

// 使用环境变量 const apiUrl = import.meta.env.VITE_API_BASE_URL; console.log(`当前环境: ${import.meta.env.VITE_NODE_ENV}`);

Vite 配置解析

项目的 vite.config.ts 提供了丰富的功能配置:

1. 自动导入

无需手动导入 Vue API 和 UI 组件库:

// 自动导入Vue API、Element Plus和Vant组件 AutoImport({ imports: ["vue"], // 自动导入Vue API resolvers: [ElementPlusResolver(), VantResolver()], }); // 自动导入组件 Components({ resolvers: [ElementPlusResolver(), VantResolver()], });

2. 全局样式注入

自动为每个 SCSS 文件注入全局变量和混入:

css: { preprocessorOptions: { scss: { additionalData: `  @import "@/styles/themes/variables.scss";  @import "@/styles/mixins/theme.scss";  @import "@/styles/mixins/common.scss";  `; } } }

3. SVG 图标系统

自动加载和优化 SVG 图标:

createSvgIconsPlugin({ iconDirs: [path.join(__dirname, "src/assets/icons/svg")], symbolId: "icon-[name]", });

4. 构建优化

智能代码分割和压缩:

build: { minify: "terser", rollupOptions: { output: { manualChunks(id) { // 不同依赖库提取到独立的文件 if (id.includes('node_modules')) { return id.toString().split('node_modules/')[1].split('/')[0].toString(); } } } } }

5. 路径别名

简化导入路径:

resolve: { alias: { '@': path.resolve(__dirname, 'src'), '@c': path.resolve(__dirname, 'src/components'), '@u': path.resolve(__dirname, 'src/utils') } }

🧩 最佳实践

组件开发规范

  1. 组件命名: 使用 PascalCase 命名组件
  2. 目录结构: 复杂组件使用目录包含多个文件
  3. Props 类型: 始终为 props 定义类型
  4. 样式隔离: 使用 scoped 或 module 确保样式隔离
<!-- 推荐的组件结构 --> <template> <div class="product-card"> <!-- 组件内容 --> </div> </template> <script setup lang="ts"> // Props定义 interface Props {  product: {  id: string;  name: string;  price: number;  };  showDetails?: boolean; }  // 默认值 const props = withDefaults(defineProps<Props>(), {  showDetails: false, });  // 事件 const emit = defineEmits<{  (e: "select", id: string): void;  (e: "delete", id: string): void; }>(); </script> <style lang="scss" scoped> .product-card {  @include flex(column, flex-start, stretch);   // 使用主题变量  color: var(--text-primary);  background-color: var(--bg-color); } </style>

API 开发规范

  1. 模块化: 按业务领域组织 API
  2. 类型安全: 为请求和响应定义类型
  3. 注释: 使用 JSDoc 注释 API 功能和参数
  4. 错误处理: 统一处理 API 错误

状态管理规范

  1. Store 拆分: 按功能模块拆分 Store
  2. 类型定义: 为 State、Getters 和 Actions 定义类型
  3. 持久化: 根据需要配置持久化选项
  4. Action 复用: 在 Action 中复用其他 Action

📝 许可证

MIT

👨‍💻 作者

Releases

No releases published

Packages

No packages published