<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="Vue.2.6.10.js"></script> </head> <body> <!-- 写在前面:虚拟dom,是一个轻量级的js对象,在状态发生变化时,进行Diff运算,对比,生成补丁对象,并更新DOM节点, 与传统dom操作相比,其是基于js计算的,所以开销会少上不少。 --> <div id="app1"> <ele></ele> </div> <div id="app2"> <ele2></ele2> </div> <div id="app3"> <ele3></ele3> </div> <div id="app4"> <ele4></ele4> </div> <div id="app5"> <ele5> <div> <child5></child5> </div> </ele5> </div> </body> <script> //Vnode对象通过一些特定的选项,描述了真实的dom结构 var vNode = { tag:‘div‘, attributes:{ id:‘container‘ }, children:{ //... } }; // 一个render函数的例子 Vue.component(‘ele‘,{ render(createElement) { return createElement( ‘div‘, {//可选的数据对象,包括style、props、dom属性、on、nativeOn(仅对于指令,用于监听原生而非$emit事件)、自定义指令、作用域slot、具名slot等 class:{ ‘show‘:this.show//动态绑定class }, attrs:{ id:‘element‘//html特型 }, on:{ click:this.handleClick//给div绑定click事件 } }, ‘文本内容‘ ) }, data() { return { show:true } }, methods: { handleClick:function(){ console.log(‘clicked!‘); } }, }); var app1 = new Vue({ el:"#app1" }); //在所有组件树中,如果vNode是组件或含有组件的slot,那么vnode必须唯一,以下给出两个错误示例 var childCom ={ render:function(createElement){ return createElement(‘p‘,‘text‘)//省略数据对象形式,渲染结果为<p>text</p> } }; Vue.component(‘ele2‘,{ render:function(createElement){ //创建一个子节点(使用子组件childCom) var childNode = createElement(childCom); return createElement(‘div‘,[ childNode, childNode ])//子节点的传入形式可以是字符串或者数组 } }); var app2 = new Vue({ el:"#app2" }); //错误示例2,重复使用含有组件的slot Vue.component(‘child‘,{ render:function(createElement){ return createElement(‘p‘,‘text‘); } }); Vue.component(‘ele3‘,{ render(createElement) { createElement(‘div‘,[ this.$slots.default, this.$slots.default ]) }, }); var app3 = new Vue({ el:"#app3" }); //这两个实例中都在组件里使用了重复的vnode, // 第一种情况vnode是局部注册的组件,第二种 //是含有组件的slot(复习:即<div></div>部分,使用$slots.default访问得到,其内部又含有组件) //正确的重复渲染多个组件的方法: var child4 = { render:function(createElement){ return createElement(‘p‘,"text"); } }; Vue.component(‘ele4‘,{ render:function(createElement){ return createElement(‘div‘, Array.apply(null,{//将global对象作为thisObj length:5 }).map(function(){ return createElement(child4); })) } }); var app4 = new Vue({ el:"#app4" }); //对于带有组件的slot,复用需要将slot的每个子节点都克隆一份 Vue.component(‘child5‘,{ render:function(createElement){ return createElement(‘p‘,‘text‘); } }); Vue.component(‘ele5‘,{ render:function(createElement){ //深度克隆slot节点 function cloneVNode(vnode){ const clonedChildren = vnode.children && vnode.children.map(function(vnode){ return cloneVNode(vnode); });//返回的是vnode数组对象 console.log(clonedChildren); const cloned = createElement( vnode.tag,//‘div’ vnode.data,//{object} clonedChildren//子节点(数组/字符串形式) ); cloned.text = vnode.text;//克隆节点的关键属性值等于传入的slot子节点的关键属性 cloned.isComment = vnode.isComment; cloned.componentOptions = vnode.componentOptions; cloned.elm = vnode.elm; cloned.context = vnode.context; cloned.ns = vnode.ns; cloned.isStatic = vnode.isStatic; cloned.key = vnode.key; return cloned; } const vNodes = this.$slots.default; console.log(vNodes);//<div>...</div> const clonedVNodes = vNodes.map(function(vnode){ console.log(vnode);//在这里slot只有一个子节点,因此遍历也只会遍历这一个 return cloneVNode(vnode); }); console.log(clonedVNodes); //获取slot插槽内的内容(子节点),使用map方法依次执行cloneVnode //函数,在该函数中进行关键属性的复制 return createElement(‘div‘,[ vNodes, clonedVNodes, clonedVNodes//可以重复 ]); } }); var app5 = new Vue({ el:"#app5" }); </script> </html>
原文地址:https://www.cnblogs.com/linbudu/p/11067845.html
时间: 2024-10-28 19:33:48