合作联系微信: w6668263      合作联系电话:177-9238-7426     

vue2,vue3中在template中使用component组件is属性绑定jsx的vnode

vue2中在template中使用component组件is属性绑定jsx的vnode

方式一使用自定义指令

 

<template>
  <el-form-item
    v-for="(item, index) in attrsList"
    :key="`attrs_list_${index}`"
    :label="item.label"
  >
    <div :class="['normal-content', item?.className]">
      <div
        :class="['normal-content', item?.className]"
        v-insert-vnode="item.value"
      />
    </div>
  </el-form-item>
</template>

<script>
// 引入 Vue
import Vue from "vue";

// 全局注册 v-focus 指令
Vue.directive("insert-vnode", {
  // 当绑定元素插入到 DOM 中时
  inserted: (el, binding) => {
    const vnode = binding.value;
    // 创建一个临时的 Vue 实例来渲染 VNode
    const tempVm = new Vue({
      render: (h) => vnode,
    });
    // 挂载临时实例并将生成的 DOM 插入到目标元素中
    tempVm.$mount();
    el.appendChild(tempVm.$el);
  },
});
export default {
  name: "DemoTest",
  data() {
    return {
      formData: {
        name: "",
        mobile: "",
      },
    };
  },
  methods: {
    // 包装 JSX 为 Vue 组件
    wrapJsx(renderFn) {
      return {
        render: renderFn,
      };
    },
  },
  computed: {
    attrsList() {
      const { name, mobile } = this.formData;
      return [
        {
          label: "用户姓名:",
          value: () => <span>{name || "--"}</span>,
        },
        {
          label: "手机号:",
          value: () => <span>{mobile || "--"}</span>,
        },
      ];
    },
  },
};
</script>

 

方式二利用函数自定义函数wrapJsx

 

<template>
  <el-form-item
    v-for="(item, index) in attrsList"
    :key="`attrs_list_${index}`"
    :label="item.label"
  >
    <div :class="['normal-content', item?.className]">
      <component :is="wrapJsx(item.value)" />
    </div>
  </el-form-item>
</template>

<script>
export default {
  name: "InspectDialog",
  methods: {
    // 包装 JSX 为 Vue 组件
    wrapJsx(renderFn) {
      return {
        render: renderFn,
      };
    },
  },
  computed: {
    attrsList() {
      const { name, mobile, psName, isPsBlack, permitCode, creditCode } =
        this.formData;
      return [
        {
          label: "用户姓名:",
          value: (h) => h("span", {}, [name || "--"]),
        },
        {
          label: "手机号:",
          value: (h) => h("span", {}, [mobile || "--"]),
        },
        {
          label: "企业名称:",
          value: (h) => h("span", {}, [psName || "--"]),
        },
        {
          label: "是否黑名单企业:",
          value: (h) => h("span", {}, [isPsBlack ? "是" : "否"]),
        },
        {
          label: "排污许可编号:",
          value: (h) => h("span", {}, [permitCode || "--"]),
        },
        {
          label: "统一社会信用代码:",
          value: (h) => h("span", {}, [creditCode || "--"]),
        },
      ];
    },
  },
};
</script>

 

 

方式二使用自定义RenderNode组件(推荐实现方式)

 

<template>
  <el-form-item
    v-for="(item, index) in attrsList"
    :key="`attrs_list_${index}`"
    :label="item.label"
  >
    <div :class="['normal-content', item?.className]">
      <render-node :render="item.value" />
    </div>
  </el-form-item>
</template>

<script>
// 创建一个简单的渲染组件
const RenderNode = {
  functional: true,
  props: {
    render: {
      type: Function,
      required: true,
    },
  },
  render(h, { props }) {
    return props.render(h);
  },
};

export default {
  components: {
    RenderNode,
  },
  data() {
    return {
      formData: {
        name: "",
        mobile: "",
      },
    };
  },
  computed: {
    attrsList() {
      const { name, mobile } = this.formData;
      return [
        {
          label: "用户姓名:",
          value: () => <span>{name || "--"}</span>,
        },
        {
          label: "手机号:",
          value: () => <span>{mobile || "--"}</span>,
        },
        // ... 其他项目
      ];
    },
  },
};
</script>

 

方式三自定义JsxRender组件

<!--
 * @Author: yeminglong
 * @Date: 2024-11-25 14:55:21
 * @LastEditors: yeminglong
 * @LastEditTime: 2025-02-25 23:07:44
 * @Description:
 -->

<template>
  <div>
    <h1>Hello {{ userName }}</h1>
    <div>
      <div v-for="(item, index) in list" :key="`item${index}`">
        <JsxRender :node="item"> </JsxRender>
      </div>
    </div>
  </div>
</template>

<script>
const JsxRender = {
  render(h) {
    return <span>{this.node}</span>;
  },
  props: {
    node: {
      type: Object,
      default: null,
    },
  },
};
export default {
  name: "JsxTest",
  props: {},
  components: {
    JsxRender,
  },
  data() {
    return {
      userName: "jsx Test",
      list: [
        <el-button type="success">{123123}</el-button>,
        <el-button type="success">{123123}</el-button>,
      ],
    };
  },
  methods: {},
  mounted() {},
  created() {},
  beforeDestroy() {},
};
</script>

<style scoped></style>

 

 

 

 

 

vue3中在template中使用component组件is属性绑定jsx的vnode

<template>
  <h2>div list</h2>
  <my-list :list="list" />
  <div v-for="(item, index) in list" :key="index">
    <my-single :value="item.value" />
  </div>
</template>

<script setup lang="tsx">
  defineOptions({
    name: 'MyTest'
  })

  const MyButton = props => {
    return (
      <el-button
        type='primary'
        onClick={() => {
          alert(props.value)
        }}
      >
        MyButton 、{props.value}
      </el-button>
    )
  }

  const MySingle = defineComponent({
    props: {
      value: {
        type: Object,
        default: () => {}
      }
    },
    render() {
      return <div>{this.value}</div>
    }
  })

  const MyList = defineComponent({
    props: {
      list: {
        type: Array,
        default: () => []
      }
    },
    render() {
      return (
        <div>
          {this.list.map((item, index) => {
            return <div key={index}>{item.value}</div>
          })}
        </div>
      )
    }
  })

  const list = [
    {
      name: 1,
      value: <MyButton value={1}></MyButton>
    },
    {
      name: 2,
      value: (
        <el-button
          value={2}
          onClick={() => {
            alert('第二个按钮')
          }}
        >
          123123
        </el-button>
      )
    },
    {
      name: 2,
      value: (
        <div>
          {
            <el-card type='card'>
              {{
                header: () => {
                  return <div>header</div>
                },
                default: () => {
                  return (
                    <el-input type='textarea' value={2}>
                      123123
                    </el-input>
                  )
                }
              }}
            </el-card>
          }
        </div>
      )
    }
  ]
</script>

<style scoped></style>

 

 

总结封装组件RenderNode.js

 


function isVNode(node) {
	return (
		node !== null &&
		typeof node === 'object' &&
		Object.prototype.hasOwnProperty.call(node, 'tag') &&
		Object.prototype.hasOwnProperty.call(node, 'componentOptions')
	)
}
const RenderNode = {
	props: {
		value: {
			type: Object,
			default: () => null
		}
	},
	render(h) {
		if (isVNode(this.value)) {
			return this.value
		}
		return <div class="render-node-value">{this.value || ''}</div>
	}
}

export default RenderNode

调用示例

<template>
  <div>
    <div v-for="item in list">
      <div>{{ item.label }}</div>
      <div>
        <renderNode :value="item.value" />
      </div>
    </div>
  </div>
</template>

<script>
import RenderNode from './renderNode'
export default {
  name: "TestRenderNode",
  props: {},
  components: {
    RenderNode,
  }
  data() {
    const name = "张三";
    const mobile = "12345678901";
    return {
      list: [
        {
          label: "测试:",
          value: "123123",
        },
        {
          label: "用户姓名:",
          value: <span>{name}</span>,
        },
        {
          label: "手机号:",
          value: <span>{mobile}</span>,
        },
      ],
    };
  },
};
</script>
<style scoped></style>

 

 

 

参考资料:https://blog.csdn.net/qq_35459724/article/details/125235696

posted on 2025-02-24 19:38  草率的龙果果  阅读(162)  评论(0)    收藏  举报

导航