Vue代码生成系统设计与实现

#「AI 原生编程挑战赛」用你的代码,让小型系统 “一键生长”#

设计了一个纯HTML页面系统,能够生成Vue组件代码和模拟JSON数据,并具备预览功能。

设计思路

这个系统将包含三个主要部分:

  1. 表单界面 - 用于配置组件属性

  2. 代码生成器 - 根据配置生成Vue代码和JSON数据

  3. 预览面板 - 实时显示生成的组件效果

实现方案

下面是完整的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>

功能说明

这个系统提供以下功能:

  1. 组件配置

    • 设置组件名称

    • 选择组件类型(卡片、表单、列表、导航)

    • 输入组件属性(JSON格式)

    • 选择样式主题

  2. 代码生成

    • 生成Vue单文件组件代码

    • 生成模拟JSON数据

  3. 预览功能

    • 实时预览生成的组件效果

  4. 实用工具

    • 代码复制功能

    • 文件下载功能(Vue文件和JSON文件)

    • 表单重置功能

使用方法

  1. 在左侧表单中配置组件属性

  2. 点击"生成代码"按钮

  3. 查看右侧生成的Vue代码和JSON数据

  4. 使用标签切换查看不同内容

  5. 使用复制按钮复制代码或下载按钮保存文件

这个系统完全在浏览器端运行,无需服务器支持,所有代码生成和预览功能都通过JavaScript实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zzywxc787

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值