vue2,vue3渲染字符串内的组件

Vue 2024-02-01 549

vue2项目

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- 引入Vue和Element UI -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>

  <div id="app">
    <!-- 使用Vue组件替换class="input_box"的元素 -->
    <div ref="htmlContainer" style="width: 200px"></div>
    {{ form.g0uym1 }}
  </div>

  <script>
    // 创建一个Vue实例
    new Vue({
      el: '#app',
      data: {
        // 定义表单数据对象
        form: {
          g0uym1: "",
        },
        // 要渲染的HTML字符串
        html: '<p class="MsoNormal" style="line-height:26.0000pt;mso-char-indent-count:3.0000;mso-line-height-rule:exactly;text-indent:54.0000pt;"><font face="黑体"><span style="font-family:黑体;font-size:18.0000pt;mso-font-kerning:1.0000pt;mso-spacerun:yes;">甲方(用人单位):</span></font><span class="input_box" data-value="g0uym1" style="font-family: 宋体; font-size: 14pt; text-decoration: underline;"><span>请输入用人单位</span><span class="required">*</span></span></p>',
      },
      mounted() {
        // 使用Vue.compile和render函数动态渲染组件
        const container = this.$refs.htmlContainer;
        const componentOptions = Vue.compile(this.formatHTML(this.html));
        const vm = new Vue({
          ...componentOptions,
          data: this.$data,
        });
        vm.$mount();
        container.appendChild(vm.$el);
      },
      methods: {
        formatHTML(originalHTML) {
          return originalHTML.replace(/<span class="input_box".*?data-value="(.*?)".*?><span>.*?<\/span><span class="required">\*<\/span><\/span>/g, `<el-input v-model="form.$1"></el-input>`);
        },
      },
    });
  </script>

</body>
</html>

vue3

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="./vue.global.min.js"></script>
  <link href="https://cdn.bootcdn.net/ajax/libs/element-plus/2.3.12/index.css" rel="stylesheet">
  <script src="https://cdn.bootcdn.net/ajax/libs/element-plus/2.3.12/index.full.js"></script>
  <style>
    .el-input {
        width: 120px;
    }
  </style>
</head>
<body>
<div id="app">
  <div v-html="html"></div>
  <div ref="htmlRef" id="container"></div>
  <h3>结果: {{ form.g0uym1 }}</h3>
</div>
<script>
	const {ref, createApp, h} = Vue;

	Vue.createApp({
		data() {
			return {
				form: {
					g0uym1: ""
				},
				templateList: [
					{
						label: "甲方",
						type: "input",
						uid: "g0uym1"
					}
				],
				html: '<p class="MsoNormal" style="line-height:26.0000pt;mso-char-indent-count:3.0000;mso-line-height-rule:exactly;text-indent:54.0000pt;"><font face="黑体"><span style="font-family:黑体;font-size:18.0000pt;mso-font-kerning:1.0000pt;mso-spacerun:yes;">甲方(用人单位):</span></font><span class="input_box" data-value="g0uym1" style="font-family: 宋体; font-size: 14pt; text-decoration: underline;"><span>请输入用人单位</span><span class="required">*</span></span></p>',
			}
		},
		mounted() {
			// 创建Vue组件并挂载到容器中
			// 创建组件选项对象
			const form = this.form
			const componentOptions = {
				data() {
					return {
						form,
					}
				},
				template: `<p>甲方: <el-input v-model="form.g0uym1" placeholder="请输入"/></p>`,
			};
			const componentInstance = createApp(componentOptions);
			componentInstance.config.compilerOptions.isCustomElement = (tag) => tag === 'font';
			componentInstance.use(ElementPlus)
			componentInstance.mount("#container")
		},
		methods: {
			getNewHtml(html) {
				const parser = new DOMParser()
				const doc = parser.parseFromString(html, "text/html")
				const spanElements = doc.querySelectorAll("span[data-value]")
				for (let spanElement of spanElements) {
					const uid = spanElement.getAttribute("data-value")
					const item = this.templateList.find(a => a.uid === uid)
					// 创建新的 input 元素
					const inputElement = document.createElement("el-input");
					inputElement.setAttribute("v-model", `form.${uid}`);
					inputElement.setAttribute("placeholder", `请输入${item.label}`);
					spanElement.parentNode?.replaceChild(inputElement, spanElement)
				}
				return doc.body.innerHTML
			}
		}
	}).mount('#app')
</script>
</body>
</html>

vue3+vite

vite.config.ts添加运行时编译

resolve: {
      alias: {
        vue: "vue/dist/vue.esm-bundler.js",
      },
      extensions: [".ts", ".js", ".vue", ".json", ".mjs"],
    },

渲染函数

import ElementPlus from 'element-plus'

const newHtml = ref("<p><el-input v-model='form.a' placeholder="请输入内容"/></p>")
// 语法就是和写一个vue文件一样的
const renderVNode = () => {
  const componentOptions = {
    components: {
      ElConfigProvider,
    },
    setup() {
      const form = form2
      // 返回值会暴露给模板和其他的选项式 API 钩子
      return {
        form,
        locale: zhCn,
      }
    },
    template: `<el-config-provider :locale="locale">${newHtml.value}</el-config-provider>`,
  }
  const componentInstance = createApp(componentOptions)
  componentInstance.config.compilerOptions.isCustomElement = (tag) => tag === "font"
  componentInstance.use(ElementPlus)
  componentInstance.mount("#template-wrapper")
}

 

标签:Vue

文章评论

评论列表

已有0条评论