代码生成:在 Vue 项目中,将 JSON 数据通过模板文件转换为 Vue 组件代码展示,并实时预览

核心:使用模板引擎渲染出 Vue 代码

🔧第一步:安装所需依赖

npm install handlebars

并在index.html文件中引入以下文件:
用于美化代码

  <script src="https://unpkg.com/prettier@2.8.8/standalone.js"></script>
  <script src="https://unpkg.com/prettier@2.8.8/parser-html.js"></script>
  <script src="https://unpkg.com/prettier@2.8.8/parser-babel.js"></script>

📁第二步:创建模板字符串(可在 JS 中定义)
定义结构化 Vue 模板

// templates/component-template.js
const componentTemplate = `
<template>
  <div class="{{kebabCase name}}-container">
    {{#each elements}}
      <{{this.tag}} 
        {{#if this.props}} 
          {{#each this.props}} 
            {{@key}}="{{this}}" 
          {{/each}} 
        {{/if}}>
        {{#if this.children}}
          {{#each this.children}}
            {{{this}}}
          {{/each}}
        {{else}}
          {{this.text}}
        {{/if}}
      </{{this.tag}}>
    {{/each}}
  </div>
</template>

<script setup>
// Auto-generated component: {{name}}
</script>

<style scoped>
.{{kebabCase name}}-container {
  padding: 20px;
}
</style>
`

export default componentTemplate

📄 第三步:编写 JSON 数据源

{
  "name": "UserCard",
  "elements": [
    {
      "tag": "h2",
      "text": "用户名:张三"
    },
    {
      "tag": "p",
      "text": "年龄:25岁"
    },
    {
      "tag": "button",
      "props": {
        "onClick": "alert('点击了按钮')",
        "title": "点我"
      },
      "text": "查看详情"
    }
  ]
}

⚙️ 第四步:编写转换逻辑(前端 Vue 组件内部)

<template>
  <div>
    <h2>JSON 转 Vue 代码演示</h2>

    <!-- JSON 输入区域 -->
    <textarea v-model="jsonInput" rows="10" cols="60" placeholder="请输入 JSON 数据"></textarea>
    <br />
    <button @click="generateCode">生成 Vue 代码</button>

    <!-- 显示生成的代码 -->
    <h3>生成的 Vue 代码:</h3>
    <pre v-if="generatedCode"><code>{{ generatedCode }}</code></pre>

    <!-- 实时预览生成的组件 -->
    <h3>实时预览:</h3>
    <Suspense>
      <component :is="dynamicComponent" v-if="dynamicComponent" />
    </Suspense>
  </div>
</template>

<script setup>
import { ref, shallowRef, h } from 'vue';
import Handlebars from 'handlebars';
import componentTemplate from '../../templates/component-template.js';

// 注册辅助函数
Handlebars.registerHelper('kebabCase', str =>
  str.replace(/([a-z])([A-Z])/g, '\$1-\$2').toLowerCase()
);

const jsonInput = ref(`{
  "name": "UserCard",
  "elements": [
    {
      "tag": "h2",
      "text": "用户名:张三"
    },
    {
      "tag": "p",
      "text": "年龄:25岁"
    },
    {
      "tag": "button",
      "props": {
        "onClick": "alert('点击了按钮')",
        "title": "点我"
      },
      "text": "查看详情"
    }
  ]
}`);

const generatedCode = ref('');
const dynamicComponent = shallowRef(null);


const generateCode = () => {
  try {
    const jsonData = JSON.parse(jsonInput.value);
    // 将数据填入模板
    const template = Handlebars.compile(componentTemplate);
    const fullCode = template(jsonData); // 包含 <template>...</template> 的完整代码
    const prettyCode = formatVueCode(fullCode)
    generatedCode.value = prettyCode

    // 提取 template 内容
    const templateContent = prettyCode.match(/<template>([\s\S]*)<\/template>/)?.[1]?.trim();
    console.log(templateContent)

    if (!templateContent) {
      throw new Error("无法提取有效模板内容");
    }

    dynamicComponent.value = {
      name: jsonData.name || "DynamicComponent",
      setup() {
        return () => h('div', { innerHTML: templateContent }); // 使用 render 函数
      }
    }

    // // 安全渲染方案:使用 VNodes 替代字符串模板
    // dynamicComponent.value = {
    //   name: jsonData.name || "DynamicComponent",
    //   setup() {
    //     // 这里可以添加更精细的 VNode 构造逻辑
    //     return () => h('div', [
    //       h('h1', jsonData.title),
    //       jsonData.items?.map(item => h('p', item))
    //     ]);
    //   }
    // };

  } catch (e) {
    console.error('JSON 解析或模板编译失败:', e)
    alert('JSON 格式错误或模板编译异常')
  }
}

const formatVueCode = (code) => {
  return window.prettier.format(code, {
    parser: 'vue',
    plugins: window.prettierPlugins,
    semi: false,
    singleQuote: true
  })
}

</script>

<style scoped>
pre {
  background-color: #f4f4f4;
  padding: 10px;
  border-radius: 4px;
  white-space: pre-wrap;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值