news 2026/9/2 18:41:24

Vue——vue3 之 代码生成器原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue——vue3 之 代码生成器原理

背景问题:
需要理解代码生成器的实现原理。

方案思考:
实现一个简单的代码生成器。

具体实现:
代码生成器:

// utils/code-generator.js// 代码生成器类exportclassCodeGenerator{constructor(options={}){this.options={templateDir:options.templateDir||'./templates',outputDir:options.outputDir||'./output',...options}}// 生成Vue组件staticgenerateVueComponent(config){const{name,props,template,script,style}=configreturn`<template> <div class="${toKebabCase(name)}">${template||''}</div> </template> <script setup>${script||'import { ref } from \'vue\''}${props?`defineProps({\n ${props.map(prop=>`${prop.name}:${prop.type}`).join(',\n ')}\n})`:''}</script><style scoped>${style||`.${toKebabCase(name)}{\n /* 样式 */\n}`}</style>`} // 生成API文件 static generateApiFile(config) { const { moduleName, baseUrl, methods } = config const apiMethods = methods.map(method => { const { name, url, method: httpMethod, params } = method return`exportfunction${name}(${params?'params':''}){returnrequest({url:'${url}',method:'${httpMethod.toLowerCase()}',${params?`${httpMethod.toLowerCase()==='get'?'params':'data'}: params`:''}})}`}).join('\n\n') return`importrequestfrom'@/utils/request'${apiMethods}`} // 生成Store static generateStore(config) { const { name, state, actions, getters } = config return`import{defineStore}from'pinia'import{ref,computed}from'vue'exportconstuse${capitalize(name)}Store=defineStore('${name}',()=>{// State${Object.entries(state).map(([key,value])=>`const${key}= ref(${JSON.stringify(value)})`).join('\n ')}// Getters${getters?Object.entries(getters).map(([key,fn])=>`const${key}= computed(() =>${fn})`).join('\n '):''}// Actions${actions?Object.entries(actions).map(([key,fn])=>`const${key}=${fn.toString()}`).join('\n '):''}return{${[...Object.keys(state),...Object.keys(getters||{}),...Object.keys(actions||{})].join(',\n ')}}})`} // 生成路由 static generateRoute(config) { const { path, name, component, meta } = config return`{path:'${path}',name:'${name}',component:()=>import('@/views/${component}.vue'),meta:${JSON.stringify(meta,null,2)}}`} } // 辅助函数 function toKebabCase(str) { return str.replace(/[A-Z]/g, match =>`-${match.toLowerCase()}`)}functioncapitalize(str){returnstr.charAt(0).toUpperCase()+str.slice(1)}

代码生成工具:

// utils/generator-tools.jsimport{CodeGenerator}from'./code-generator'// 项目生成器exportclassProjectGenerator{// 生成CRUD页面staticgenerateCRUD(config){const{moduleName,fields,hasPagination=true}=config// 生成列表页面constlistPage=this.generateListPage(config)// 生成表单页面constformPage=this.generateFormPage(config)// 生成APIconstapiFile=CodeGenerator.generateApiFile({moduleName,baseUrl:`/api/${moduleName}`,methods:[{name:`${moduleName}List`,url:`/${moduleName}/list`,method:'GET',params:true},{name:`get${capitalize(moduleName)}Info`,url:`/${moduleName}/info`,method:'GET',params:true},{name:`create${capitalize(moduleName)}`,url:`/${moduleName}`,method:'POST',params:true},{name:`update${capitalize(moduleName)}`,url:`/${moduleName}`,method:'PUT',params:true},{name:`delete${capitalize(moduleName)}`,url:`/${moduleName}`,method:'DELETE',params:true}]})// 生成Storeconststore=CodeGenerator.generateStore({name:moduleName,state:{list:[],total:0,loading:false},actions:{getList:`async function(params) { this.loading = true try { const response = await${moduleName}List(params) this.list = response.data.list this.total = response.data.total } finally { this.loading = false } }`}})return{listPage,formPage,apiFile,store}}// 生成列表页面staticgenerateListPage(config){const{moduleName,fields}=configconsttableColumns=fields.map(field=>`<el-table-column prop="${field.name}" label="${field.label}" />`).join('\n ')return`<template> <div class="${toKebabCase(moduleName)}-list"> <div class="search-form"> <el-form :model="queryParams" inline>${fields.filter(f=>f.searchable).map(field=>`<el-form-item label="${field.label}"> <el-input v-model="queryParams.${field.name}" placeholder="请输入${field.label}" /> </el-form-item>`).join('\n ')}<el-form-item> <el-button type="primary" @click="handleSearch">搜索</el-button> <el-button @click="handleReset">重置</el-button> </el-form-item> </el-form> </div> <div class="table-actions"> <el-button type="primary" @click="handleAdd">新增</el-button> <el-button @click="handleDeleteBatch">批量删除</el-button> </div> <el-table :data="list" v-loading="loading" @selection-change="handleSelectionChange" > <el-table-column type="selection" width="55" />${tableColumns}<el-table-column label="操作" width="200"> <template #default="{ row }"> <el-button size="small" @click="handleEdit(row)">编辑</el-button> <el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button> </template> </el-table-column> </el-table> <Pagination v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> </div> </template> <script setup> import { ref, onMounted } from 'vue' import {${moduleName}List, delete${capitalize(moduleName)}} from '@/api/${moduleName}' import Pagination from '@/components/Pagination.vue' const list = ref([]) const total = ref(0) const loading = ref(false) const queryParams = ref({ pageNum: 1, pageSize: 10,${fields.filter(f=>f.searchable).map(f=>`${f.name}: ''`).join(',\n ')}}) const selectedRows = ref([]) const getList = async () => { loading.value = true try { const response = await${moduleName}List(queryParams.value) list.value = response.data.list total.value = response.data.total } finally { loading.value = false } } const handleSearch = () => { queryParams.value.pageNum = 1 getList() } const handleReset = () => { queryParams.value = { pageNum: 1, pageSize: 10,${fields.filter(f=>f.searchable).map(f=>`${f.name}: ''`).join(',\n ')}} getList() } const handleAdd = () => { // 跳转到新增页面 } const handleEdit = (row) => { // 跳转到编辑页面 } const handleDelete = async (id) => { try { await delete${capitalize(moduleName)}(id) ElMessage.success('删除成功') getList() } catch (error) { ElMessage.error('删除失败') } } const handleSelectionChange = (selection) => { selectedRows.value = selection } onMounted(() => { getList() }) </script>`}// 生成表单页面staticgenerateFormPage(config){const{moduleName,fields}=configconstformItems=fields.filter(f=>f.formField).map(field=>`<el-form-item label="${field.label}" prop="${field.name}"> <el-input v-model="formData.${field.name}" placeholder="请输入${field.label}" /> </el-form-item>`).join('\n ')return`<template> <div class="${toKebabCase(moduleName)}-form"> <el-card> <template #header> <span>${config.title||capitalize(moduleName)}表单</span> </template> <el-form :model="formData" :rules="formRules" ref="formRef" label-width="100px" >${formItems}<el-form-item> <el-button type="primary" @click="handleSubmit">提交</el-button> <el-button @click="handleCancel">取消</el-button> </el-form-item> </el-form> </el-card> </div> </template> <script setup> import { ref, reactive } from 'vue' import { useRoute, useRouter } from 'vue-router' import { get${capitalize(moduleName)}Info, create${capitalize(moduleName)}, update${capitalize(moduleName)}} from '@/api/${moduleName}' const route = useRoute() const router = useRouter() const formRef = ref() const formData = reactive({${fields.filter(f=>f.formField).map(f=>`${f.name}:${f.type==='number'?0:f.type==='boolean'?false:"''"}`).join(',\n ')}}) const formRules = {${fields.filter(f=>f.required).map(f=>`${f.name}: [{ required: true, message: '请输入${f.label}', trigger: 'blur' }]`).join(',\n ')}} const handleSubmit = async () => { try { await formRef.value.validate() if (formData.id) { // 更新 await update${capitalize(moduleName)}(formData) ElMessage.success('更新成功') } else { // 创建 await create${capitalize(moduleName)}(formData) ElMessage.success('创建成功') } router.back() } catch (error) { ElMessage.error('提交失败') } } const handleCancel = () => { router.back() } // 如果是编辑模式,加载数据 if (route.query.id) { const loadDetail = async () => { const response = await get${capitalize(moduleName)}Info({ id: route.query.id }) Object.assign(formData, response.data) } loadDetail() } </script>`}}functiontoKebabCase(str){returnstr.replace(/[A-Z]/g,match=>`-${match.toLowerCase()}`)}functioncapitalize(str){returnstr.charAt(0).toUpperCase()+str.slice(1)}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 23:27:22

如何将某个成员设置为管理员?看这里!

&#x1f64b;能否将某个相册成员设置为管理员&#xff0c;协助我管理相册&#xff1f;&#x1f449;支持的⬇️下面将介绍如何将某个成员设置为管理员&#xff1a;1️⃣打开土著相册小&#x1f34a;序&#xff0c;点击目标相册&#xff0c;进入相册2️⃣点击底部按钮「管理」&…

作者头像 李华
网站建设 2026/9/3 1:23:05

Linux命令-lnstat(快速查找文件和目录)

&#x1f9ed;说明 locate 命令是 Linux 中一个用于快速查找文件和目录的工具&#xff0c;它通过搜索系统预先生成的文件名数据库来工作&#xff0c;速度非常快。下面我将详细介绍它的用法、与 find 命令的区别以及一些实用技巧。 &#x1f50d; locate 与 find 的区别 在深…

作者头像 李华
网站建设 2026/9/3 2:05:22

飞书助力clawdbot成为本土化的AI助手

飞书助力clawdbot成为本土化的AI助手 先看视频 废话少说&#xff0c;先看视频&#xff1a; clawdbot 简介 视频是用飞书pc端模拟手机端&#xff0c;来控制clawdbot的。 clawdbot已经火到了macmini涨价的地步&#xff0c;为什么我们用起来那么难&#xff1f; 看看主页说明中…

作者头像 李华
网站建设 2026/9/2 21:47:55

一个相当复杂的跨品牌电梯智能群控系统项目,涉及硬件改造、软件调试和系统集成。从多奥提供的详细清单和流程来看,用户很可能是电梯智能化改造项目的技术负责人或系统集成商,需要确保整个方案从准备到验收的顺利

现在需要我帮助梳理和优化这个技术方案&#xff0c;使其更具可操作性和系统性。我打算从项目全生命周期的角度&#xff0c;构建一个逻辑清晰、阶段分明的实施框架。 首先考虑的是项目前期准备阶段&#xff0c;这是整个项目的基础。根据我看到的搜索结果&#xff0c;现场勘察与…

作者头像 李华
网站建设 2026/9/2 21:48:03

Dropbear SSH Server - 工程级 Bug 修复方案

一、Critical 级别修复(立即修复) BUG #1: circbuffer.c 空指针解引用 问题位置: circbuffer.c:93-106 原始代码: void cbuf_readptrs(const circbuffer *cbuf,unsigned char **p1, unsigned int *len1, unsigned char **p2, unsigned int *len2) {*p1 = &cbuf->…

作者头像 李华
网站建设 2026/9/2 21:49:16

2026美国大学生数学建模竞赛时间安排

2026美赛数学建模A题B题C题D题E题F题思路模型代码论文持续更新&#xff0c;完整论文见文末名片2026年MCM/ICM美赛已进入冲刺倒计时&#xff0c;各位参赛小伙伴想必都已组队完毕&#xff0c;摩拳擦掌准备迎战这96小时的脑力攻坚战&#xff0c;向着好成绩全力奔赴&#xff01;美赛…

作者头像 李华