设计了一个纯HTML页面系统,能够生成Vue组件代码和模拟JSON数据,并具备预览功能。
设计思路
这个系统将包含三个主要部分:
-
表单界面 - 用于配置组件属性
-
代码生成器 - 根据配置生成Vue代码和JSON数据
-
预览面板 - 实时显示生成的组件效果
实现方案
下面是完整的HTML实现,包含所有所需功能:
html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue代码生成系统</title> <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script> <style> :root { --primary-color: #4CAF50; --secondary-color: #2196F3; --dark-color: #333; --light-color: #f4f4f4; --success-color: #28a745; --danger-color: #dc3545; } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; background-color: #f5f5f5; color: #333; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } header { text-align: center; margin-bottom: 30px; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: var(--primary-color); margin-bottom: 10px; } .main-content { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } @media (max-width: 768px) { .main-content { grid-template-columns: 1fr; } } .panel { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #eee; } h2 { color: var(--dark-color); } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 500; } input, select, textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } button { padding: 10px 15px; background-color: var(--primary-color); color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background-color 0.3s; } button:hover { background-color: #3d8b40; } .btn-secondary { background-color: var(--secondary-color); } .btn-secondary:hover { background-color: #0b7dda; } .btn-danger { background-color: var(--danger-color); } .btn-danger:hover { background-color: #bd2130; } .code-container { position: relative; } pre { background-color: #f8f8f8; padding: 15px; border-radius: 4px; overflow-x: auto; max-height: 300px; font-family: 'Courier New', monospace; } .copy-btn { position: absolute; top: 10px; right: 10px; padding: 5px 10px; font-size: 14px; } .preview-area { min-height: 200px; border: 1px dashed #ddd; padding: 15px; margin-top: 20px; } .tabs { display: flex; margin-bottom: 15px; border-bottom: 1px solid #ddd; } .tab { padding: 10px 15px; cursor: pointer; background: #f8f8f8; border: 1px solid transparent; border-bottom: none; border-radius: 4px 4px 0 0; margin-right: 5px; } .tab.active { background: white; border-color: #ddd; color: var(--primary-color); font-weight: bold; } .tab-content { display: none; } .tab-content.active { display: block; } .alert { padding: 10px; margin: 10px 0; border-radius: 4px; } .alert-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } </style> </head> <body> <div class="container"> <header> <h1>Vue代码生成系统</h1> <p>通过表单配置生成Vue组件代码和模拟JSON数据</p> </header> <div class="main-content"> <div class="panel"> <div class="panel-header"> <h2>组件配置</h2> </div> <div class="form-group"> <label for="componentName">组件名称</label> <input type="text" id="componentName" placeholder="例如: UserCard" value="UserCard"> </div> <div class="form-group"> <label for="componentType">组件类型</label> <select id="componentType"> <option value="card">卡片组件</option> <option value="form">表单组件</option> <option value="list">列表组件</option> <option value="navigation">导航组件</option> </select> </div> <div class="form-group"> <label for="componentProps">组件属性 (JSON格式)</label> <textarea id="componentProps" rows="4">{ "title": "用户卡片", "name": "张三", "age": 28, "occupation": "前端工程师" }</textarea> </div> <div class="form-group"> <label for="componentStyle">样式选项</label> <select id="componentStyle"> <option value="default">默认样式</option> <option value="bootstrap">Bootstrap风格</option> <option value="material">Material Design</option> </select> </div> <button id="generateBtn" class="btn-secondary">生成代码</button> <button id="resetBtn" class="btn-danger">重置表单</button> </div> <div class="panel"> <div class="panel-header"> <h2>生成结果</h2> </div> <div class="tabs"> <div class="tab active" data-tab="vue">Vue代码</div> <div class="tab" data-tab="json">JSON数据</div> <div class="tab" data-tab="preview">预览</div> </div> <div class="tab-content active" id="vue-tab"> <div class="code-container"> <pre id="vueCode"></pre> <button class="copy-btn" data-target="vueCode">复制</button> </div> </div> <div class="tab-content" id="json-tab"> <div class="code-container"> <pre id="jsonCode"></pre> <button class="copy-btn" data-target="jsonCode">复制</button> </div> </div> <div class="tab-content" id="preview-tab"> <div id="previewArea" class="preview-area"></div> </div> <div id="alertArea"></div> <div style="margin-top: 20px;"> <button id="downloadVue" class="btn-secondary">下载Vue文件</button> <button id="downloadJson" class="btn-secondary">下载JSON文件</button> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // 获取DOM元素 const generateBtn = document.getElementById('generateBtn'); const resetBtn = document.getElementById('resetBtn'); const tabs = document.querySelectorAll('.tab'); const tabContents = document.querySelectorAll('.tab-content'); const copyButtons = document.querySelectorAll('.copy-btn'); const downloadVueBtn = document.getElementById('downloadVue'); const downloadJsonBtn = document.getElementById('downloadJson'); // 初始化 generateCode(); // 生成代码按钮事件 generateBtn.addEventListener('click', generateCode); // 重置按钮事件 resetBtn.addEventListener('click', function() { document.getElementById('componentName').value = 'UserCard'; document.getElementById('componentType').value = 'card'; document.getElementById('componentProps').value = `{ "title": "用户卡片", "name": "张三", "age": 28, "occupation": "前端工程师" }`; document.getElementById('componentStyle').value = 'default'; generateCode(); showAlert('表单已重置!', 'success'); }); // 标签切换事件 tabs.forEach(tab => { tab.addEventListener('click', function() { const tabId = this.getAttribute('data-tab'); // 更新标签状态 tabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); // 更新内容显示 tabContents.forEach(content => { content.classList.remove('active'); if (content.id === `${tabId}-tab`) { content.classList.add('active'); } }); }); }); // 复制按钮事件 copyButtons.forEach(button => { button.addEventListener('click', function() { const targetId = this.getAttribute('data-target'); const codeElement = document.getElementById(targetId); const textArea = document.createElement('textarea'); textArea.value = codeElement.textContent; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); showAlert('代码已复制到剪贴板!', 'success'); }); }); // 下载Vue文件按钮事件 downloadVueBtn.addEventListener('click', function() { const vueCode = document.getElementById('vueCode').textContent; const componentName = document.getElementById('componentName').value; downloadFile(vueCode, `${componentName}.vue`, 'text/plain'); showAlert('Vue文件下载成功!', 'success'); }); // 下载JSON文件按钮事件 downloadJsonBtn.addEventListener('click', function() { const jsonCode = document.getElementById('jsonCode').textContent; const componentName = document.getElementById('componentName').value; downloadFile(jsonCode, `${componentName}Data.json`, 'application/json'); showAlert('JSON文件下载成功!', 'success'); }); // 生成代码函数 function generateCode() { const componentName = document.getElementById('componentName').value; const componentType = document.getElementById('componentType').value; const componentProps = document.getElementById('componentProps').value; const componentStyle = document.getElementById('componentStyle').value; // 生成Vue代码 const vueCode = generateVueCode(componentName, componentType, componentProps, componentStyle); document.getElementById('vueCode').textContent = vueCode; // 生成JSON代码 document.getElementById('jsonCode').textContent = componentProps; // 更新预览 updatePreview(componentName, componentType, componentProps, componentStyle); } // 生成Vue代码的函数 function generateVueCode(name, type, props, style) { let templateCode = ''; let scriptCode = ''; let styleCode = ''; // 解析props JSON let propsObj; try { propsObj = JSON.parse(props); } catch (e) { propsObj = { error: "Invalid JSON provided" }; } // 根据组件类型生成不同的模板 switch(type) { case 'card': templateCode = generateCardTemplate(propsObj); break; case 'form': templateCode = generateFormTemplate(propsObj); break; case 'list': templateCode = generateListTemplate(propsObj); break; case 'navigation': templateCode = generateNavigationTemplate(propsObj); break; default: templateCode = `<div>\n <h2>${name}组件</h2>\n <p>这里是组件内容</p>\n</div>`; } // 生成脚本部分 scriptCode = `<script> export default { name: '${name}', data() { return ${JSON.stringify(propsObj, null, 2)} } } <\/script>`; // 生成样式部分 switch(style) { case 'bootstrap': styleCode = `<style scoped> /* Bootstrap风格样式 */ .card { margin: 20px 0; box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } .card-header { padding: 0.75rem 1.25rem; background-color: #f8f9fa; border-bottom: 1px solid #e9ecef; } .card-body { padding: 1.25rem; } <\/style>`; break; case 'material': styleCode = `<style scoped> /* Material Design风格样式 */ .card { margin: 20px 0; box-shadow: 0 2px 1px -1px rgba(0,0,0,0.2), 0 1px 1px 0 rgba(0,0,0,0.14), 0 1px 3px 0 rgba(0,0,0,0.12); border-radius: 4px; background: #fff; } .card-header { padding: 16px; border-bottom: 1px solid #e0e0e0; } .card-body { padding: 16px; } <\/style>`; break; default: styleCode = `<style scoped> /* 默认样式 */ .card { margin: 20px 0; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; } .card-header { padding: 12px 16px; background-color: #f5f5f5; border-bottom: 1px solid #e0e0e0; } .card-body { padding: 16px; } <\/style>`; } return `<template>\n${templateCode}\n</template>\n\n${scriptCode}\n\n${styleCode}`; } // 生成卡片模板 function generateCardTemplate(props) { return ` <div class="card"> <div class="card-header"> <h3>{{ title }}</h3> </div> <div class="card-body"> <p><strong>姓名:</strong> {{ name }}</p> <p><strong>年龄:</strong> {{ age }}</p> <p><strong>职业:</strong> {{ occupation }}</p> </div> </div>`; } // 生成表单模板 function generateFormTemplate(props) { return ` <div class="form-container"> <h3>{{ title }}</h3> <form @submit.prevent="handleSubmit"> <div class="form-group"> <label>姓名:</label> <input type="text" v-model="name"> </div> <div class="form-group"> <label>年龄:</label> <input type="number" v-model="age"> </div> <div class="form-group"> <label>职业:</label> <input type="text" v-model="occupation"> </div> <button type="submit">提交</button> </form> </div>`; } // 生成列表模板 function generateListTemplate(props) { return ` <div class="list-container"> <h3>{{ title }}</h3> <ul> <li v-for="(item, index) in items" :key="index"> {{ item }} </li> </ul> </div>`; } // 生成导航模板 function generateNavigationTemplate(props) { return ` <nav class="navbar"> <div class="nav-brand">{{ brand }}</div> <ul class="nav-menu"> <li v-for="(item, index) in menuItems" :key="index"> <a :href="item.link">{{ item.text }}</a> </li> </ul> </nav>`; } // 更新预览 function updatePreview(name, type, props, style) { const previewArea = document.getElementById('previewArea'); // 清空预览区域 previewArea.innerHTML = ''; // 创建临时div来渲染Vue组件 const tempDiv = document.createElement('div'); tempDiv.id = 'temp-preview'; previewArea.appendChild(tempDiv); // 解析props let propsObj; try { propsObj = JSON.parse(props); } catch (e) { propsObj = { error: "Invalid JSON" }; } // 根据类型渲染不同的预览 switch(type) { case 'card': tempDiv.innerHTML = ` <div class="card"> <div class="card-header"> <h3>${propsObj.title || '卡片标题'}</h3> </div> <div class="card-body"> <p><strong>姓名:</strong> ${propsObj.name || '未提供'}</p> <p><strong>年龄:</strong> ${propsObj.age || '未提供'}</p> <p><strong>职业:</strong> ${propsObj.occupation || '未提供'}</p> </div> </div> `; break; case 'form': tempDiv.innerHTML = ` <div class="form-container"> <h3>${propsObj.title || '表单标题'}</h3> <form> <div class="form-group"> <label>姓名:</label> <input type="text" value="${propsObj.name || ''}"> </div> <div class="form-group"> <label>年龄:</label> <input type="number" value="${propsObj.age || ''}"> </div> <div class="form-group"> <label>职业:</label> <input type="text" value="${propsObj.occupation || ''}"> </div> <button type="submit">提交</button> </form> </div> `; break; case 'list': tempDiv.innerHTML = ` <div class="list-container"> <h3>${propsObj.title || '列表标题'}</h3> <ul> <li>列表项 1</li> <li>列表项 2</li> <li>列表项 3</li> </ul> </div> `; break; case 'navigation': tempDiv.innerHTML = ` <nav class="navbar" style="display: flex; justify-content: space-between; padding: 10px; background: #f5f5f5;"> <div class="nav-brand">${propsObj.brand || '品牌名称'}</div> <ul class="nav-menu" style="display: flex; list-style: none;"> <li style="margin: 0 10px;"><a href="#">首页</a></li> <li style="margin: 0 10px;"><a href="#">关于</a></li> <li style="margin: 0 10px;"><a href="#">服务</a></li> <li style="margin: 0 10px;"><a href="#">联系</a></li> </ul> </nav> `; break; } } // 显示提示信息 function showAlert(message, type) { const alertArea = document.getElementById('alertArea'); const alert = document.createElement('div'); alert.className = `alert alert-${type}`; alert.textContent = message; alertArea.appendChild(alert); // 3秒后消失 setTimeout(() => { alert.remove(); }, 3000); } // 下载文件函数 function downloadFile(content, fileName, contentType) { const blob = new Blob([content], { type: contentType }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url); } }); </script> </body> </html>
功能说明
这个系统提供以下功能:
-
组件配置:
-
设置组件名称
-
选择组件类型(卡片、表单、列表、导航)
-
输入组件属性(JSON格式)
-
选择样式主题
-
-
代码生成:
-
生成Vue单文件组件代码
-
生成模拟JSON数据
-
-
预览功能:
-
实时预览生成的组件效果
-
-
实用工具:
-
代码复制功能
-
文件下载功能(Vue文件和JSON文件)
-
表单重置功能
-
使用方法
-
在左侧表单中配置组件属性
-
点击"生成代码"按钮
-
查看右侧生成的Vue代码和JSON数据
-
使用标签切换查看不同内容
-
使用复制按钮复制代码或下载按钮保存文件
这个系统完全在浏览器端运行,无需服务器支持,所有代码生成和预览功能都通过JavaScript实现。