若依框架作为国内企业级中后台系统的标杆开源项目,其Vue3版本在2022年发布后迅速成为主流选择。该版本基于以下技术栈构建:
语法糖本文将从技术选型、架构设计、组件开发、性能优化到工程化实践,系统解析若依Vue3前端开发体系,结合最新技术趋势与实际项目经验,为开发者提供可落地的解决方案。
在若依框架中,JavaScript适用于以下场景:
// src/views/demo/dynamicForm.vue
<script setup>
import { ref, onMounted } from 'vue'
const formConfig = ref([])
const formData = ref({})
onMounted(async () => {
// 模拟从后端获取表单配置
const { data } = await fetch('/api/form-config').then(res => res.json())
formConfig.value = data
// 初始化空数据对象
data.forEach(item => {
formData.value[item.prop] = item.defaultValue || ''
})
})
const handleSubmit = () => {
console.log('提交数据:', formData.value)
}
</script>
<template>
<el-form :model="formData">
<template v-for="item in formConfig" :key="item.prop">
<el-form-item :label="item.label" :prop="item.prop">
<component
:is="item.type === 'input' ? 'el-input' : 'el-select'"
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</el-form-item>
</template>
<el-button @click="handleSubmit">提交</el-button>
</el-form>
</template>
技术亮点:
)v-bind="item.attrs"
)若依框架核心代码库已全面迁移至TypeScript,其优势体现在:
// src/api/system/user.ts
import type { AxiosPromise } from 'axios'
// 用户状态枚举
export enum UserStatus {
NORMAL = '0',
DISABLED = '1'
}
// 用户列表查询参数
export interface UserQueryParams {
userName?: string
phonenumber?: string
status?: UserStatus
deptId?: number
pageNum?: number
pageSize?: number
}
// 用户列表响应数据
export interface UserListResponse {
list: UserItem[]
total: number
}
// 用户项
export interface UserItem {
userId: number
userName: string
nickName: string
email: string
phonenumber: string
sex: '0' | '1' | '2'
avatar: string
status: UserStatus
deptId: number
deptName: string
createTime: string
}
// API方法定义
export const getUserList = (params: UserQueryParams): AxiosPromise<UserListResponse> => {
return request({
url: '/system/user/list',
method: 'get',
params
})
}
工程化价值:
typedoc
工具生成API文档plop
根据类型定义生成表单验证规则若依Vue3采用经典的"三栏式"布局,核心实现如下:
src/
├── layout/ # 布局组件
│ ├── components/ # 布局子组件
│ │ ├── AppMain.vue # 主内容区
│ │ ├── Sidebar/ # 侧边栏
│ │ ├── TagsView/ # 多标签页
│ │ └── Navbar.vue # 顶部导航
│ ├── index.vue # 布局容器
│ └── routerView.vue # 路由视图
└── views/ # 业务页面
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/layout/index.vue'
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index.vue'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error/404.vue'),
hidden: true
}
]
export const asyncRoutes = [
{
path: '/system',
component: Layout,
meta: { title: '系统管理', icon: 'system' },
children: [
{
path: 'user',
component: () => import('@/views/system/user/index.vue'),
name: 'User',
meta: { title: '用户管理', icon: 'user' }
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes: constantRoutes
})
// 动态添加路由
export function addRoutes(routes) {
router.addRoute(Layout, ...routes)
}
// src/assets/styles/variables.scss
// 覆盖Element Plus默认断点
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;
// 自定义响应式工具类
@mixin responsive($breakpoint) {
@if $breakpoint == mobile {
@media (max-width: $--sm - 1) { @content; }
}
@else if $breakpoint == tablet {
@media (min-width: $--sm) and (max-width: $--md - 1) { @content; }
}
// 其他断点...
}
在src/components/ReForm
目录下实现增强型表单组件:
使用示例:
在src/components/ReTable
目录下实现增强型表格组件:
核心特性:
若依Vue3提供完整的主题定制方案:
src/
├── styles/
│ ├── element/ # Element Plus主题变量
│ │ ├── index.scss # 导入所有变量
│ │ ├── variables.scss # 核心变量定义
│ │ └── dark.scss # 暗黑模式
│ ├── common.scss # 通用样式
│ ├── transition.scss # 过渡动画
│ └── mixin.scss # 混合宏
// src/store/modules/settings.ts
import { defineStore } from 'pinia'
interface SettingsState {
theme: string
sidebarStatus: string
device: string
}
export const useSettingsStore = defineStore('settings', {
state: (): SettingsState => ({
theme: localStorage.getItem('theme') || '#409EFF',
sidebarStatus: localStorage.getItem('sidebarStatus') || '',
device: 'desktop'
}),
actions: {
changeTheme(theme: string) {
this.theme = theme
localStorage.setItem('theme', theme)
// 动态修改CSS变量
document.documentElement.style.setProperty('--el-color-primary', theme)
// 重新加载Element Plus主题
import(`element-plus/dist/index.css`).then(() => {
console.log('主题切换成功')
})
}
}
})
// src/styles/table.scss
.el-table {
--el-table-tr-bg-color: var(--el-color-primary-light-9);
tbody tr {
&.current-row > td {
background-color: var(--el-table-tr-bg-color) !important;
}
&:hover > td {
background-color: var(--el-table-tr-bg-color) !important;
}
}
}
// src/utils/validate.ts
export const validatePhone = (rule, value, callback) => {
const reg = /^1[3-9]\d{9}$/
if (!value) {
return callback(new Error('请输入手机号码'))
}
setTimeout(() => {
if (!reg.test(value)) {
callback(new Error('请输入正确的手机号码'))
} else {
callback()
}
}, 100)
}
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
Components({
resolvers: [ElementPlusResolver()],
dts: true // 生成类型声明
})
],
build: {
rollupOptions: {
output: {
manualChunks: {
'element-plus': ['element-plus'],
'echarts': ['echarts'],
'lodash': ['lodash-es'],
'vendor': ['vue', 'vue-router', 'pinia']
}
}
},
chunkSizeWarningLimit: 1500 // 调整警告阈值
}
})
<head>
<% if (process.env.NODE_ENV === 'production') { %>
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js">script>
<script src="https://unpkg.com/vue-router@4">script>
<script src="https://unpkg.com/pinia">script>
<script src="https://unpkg.com/element-plus">script>
<% } %>
head>
// src/utils/debounce.ts
export function debounce(fn: Function, delay: number) {
let timer: NodeJS.Timeout
return function(...args: any[]) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
// 使用示例
const handleSearch = debounce((query) => {
// 搜索逻辑
}, 300)
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true
},
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module'
},
rules: {
'vue/multi-word-component-names': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'@typescript-eslint/no-explicit-any': 'off'
}
}
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', // 新功能
'fix', // 修复bug
'docs', // 文档变更
'style', // 代码格式
'refactor', // 代码重构
'perf', // 性能优化
'test', // 测试相关
'build', // 构建相关
'ci', // CI配置
'chore', // 其他修改
'revert' // 回退
]
]
}
}
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: '16.x'
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
- name: Run tests
run: npm run test:unit
- name: Build project
run: npm run build
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: dist
path: dist
若依Vue3框架通过JavaScript与TypeScript的双轨制开发模式、模块化的组件设计、精细化的样式工程和系统化的性能优化,构建了完整的企业级前端开发解决方案。开发者应根据项目规模选择合适的技术栈:
未来技术趋势:
建议开发者持续关注若依官方仓库的更新动态,积极参与社区贡献,共同推动企业级前端开发技术的进步。