vue使用createElement异步渲染组件

    科技2026-10-06  4

    实验了两种方式。vue模板组件异步渲染组件和函数式组件异步渲染组件。模板组件借用了slot插槽。

    第一种方式,vue模板组件

    建立一个vue文件 ,假如名字叫mountElement.vue

    <template> <div id="mountedDiv"></div> </template> <script> import { isVNode } from "./VnodeUtil"; import TempSlot from "./TempSlot"; import Vue from "vue"; export default { methods: { //渲染 render(componentArr) { let self = this; let TempSoltConstructor = Vue.extend(TempSlot); let instance = new TempSoltConstructor(); let vnodes = self.createVnode(componentArr); if (isVNode(vnodes)) { instance.$slots.default = [vnodes]; } instance.$mount("#mountedDiv"); }, //生成虚拟dom createVnode(elementArr) { let self = this; const h = self.$createElement; return h( "div", { style: { height: "100vh", overflowY: "auto", width: "100vw", overflowX: "hidden" } }, elementArr.map((element, index) => { return h(element.name, element, element.slot); }) ); } } }; </script>

    其中VnodeUtil为

    const hasOwnProperty = Object.prototype.hasOwnProperty; export function noop() {}; export function hasOwn(obj, key) { return hasOwnProperty.call(obj, key); }; export function isVNode(node) { return node !== null && typeof node === 'object' && hasOwn(node, 'componentOptions'); };

    TempSlot为

    <template> <div> <slot> </slot> </div> </template>

    父组件引入mountElement.vue 并使用ref,渲染的时候,http请求(或其他异步方法)返回的dom结构(必须包含name,其他的内容参考createElement中参数),使用this.$ref.mountElement.render(需要渲染的dom结构)。

     

    第二种方式,采用函数式组件

    这里,全局注册了一个函数式组件

    Vue.component('element-list', { functional: true, props: { componentArr: { type: Function, required: true } }, render: function (createElement, context) { console.log("context=", context); //这里让传入的componentArr是函数,执行结果返回数组,避开不能直接传Observer观察对象问题 var componentArr = context.props.componentArr(); /** * 如果存在data.__ob__,说明data是被Observer观察的数据 * 不能用作虚拟节点的data * 需要抛出警告,并返回一个空节点 * * 被监控的data不能被用作vnode渲染的数据的原因是: * data在vnode渲染过程中可能会被改变,这样会触发监控,导致不符合预期的操作 * Avoid using observed data object as vnode data: * Always create fresh vnode data objects in each render! */ return createElement('div', { style: { height: "100vh", overflowY: "auto", width: "100vw", overflowX: "hidden" } }, getElements(createElement, componentArr) /** componentArr && componentArr.length > 0 ? componentArr.map((element, index) => { return createElement( element.name, element, element.slot ) }) : "" */ ) } }) function getElements(createElement, root) { return root ? (root instanceof Array && root.length > 0 ? root.map((element, index) => { return createElement( element.name, element, getElements(createElement, element.children) ) }) : root.slot) : root }

    在父组件中调用

    <element-list :componentArr="componentArr"></element-list>

    其中

    data() { return { componentArr: () => [] //这个参数一定要是个函数 }; },

    异步渲染的时候,只要改变componentArr的值,这里 componentArr要赋值给一个函数。比如 

    componentArr =()=>{ return [{ name:"div", slot:"测试div" },{ name:"a", slot:"测试a"} ] }

     

    Processed: 0.009, SQL: 9