createElement构成了Vue Virtual Dom的模板,它有3个参数:
String:一个HTML标签,组件选项,或一个函数,必须return上述其中一个
Object:一个对应属性的数据对象,可选,可以在template中使用
第三个参数是子节点,也是可选参数。
以往在template里,都是在组件的标签上使用形容v-bind:class、v-bind:style这样的指令,在Render函数将其写在了数据对象中,比如下面的组件,使用传统的template写法:
<body>
<div id="app">
<ele></ele>
</div>
</body>
<script>
Vue.component('ele',{
render:function (createElement) {
return createElement(
'div',
{
//动态绑定class
class:{
'show':this.show
},
attrs:{
id:'element'
},
on:{
click:this.handleClick
}
}
,'文本内容'
)
},
data:function () {
return{
show: true
}
},
methods:{
handleClick:function () {
console.log('clicked!');
}
}
});
var app = new Vue({
el:'#app'
})
</script>
所有组件树中,如果VNode是组件或含有组件的slot,那么VNode必须唯一。下例通过一个循环和工厂函数就可以渲染5个重复的子组件Child.
<body>
<div id="app">
<ele></ele>
</div>
</body>
<script>
var Child = {
render:function (createElement) {
return createElement('p','text');
}
};
Vue.component('ele',{
render:function (createElement) {
return createElement('div',Array.apply(null,{
length:5
}).map(function () {
return createElement(Child);
}))
}
});
var app = new Vue({
el:'#app'
})
</script>
对于含有组件的slot,复用就要稍微复杂一点,需要将slot的每个子节点都要克隆一份。如下所示:
<body>
<div id="app">
<ele>
<div>
<child></child>
</div>
</ele>
</div>
<script>
//全局注册组件
Vue.component('child',{
render:function (createElement) {
return createElement('p','text');
}
});
Vue.component('ele',{
render:function (createElement) {
//克隆slot节点的方法
render:function cloneVNode(vnode) {
//递归遍历所有子节点,并克隆
const cloneChildren = vnode.children && vnode.children.map(function (vnode) {
return cloneVNode(vnode);
});
const cloned = createElement(
vnode.tag,
vnode.data,
cloneChildren
);
cloned.text = vnode.text;
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;
const clonedVNodes = vNodes.map(function (vnode) {
return cloneVNode(vnode);
});
return createElement('div',[
vNodes,
clonedVNodes
]);
}
});
var app = new Vue({
el:'#app'
})
</script>
</body>
对上述代码中部分进行修改,可以克隆多个slot
var vNodes = this.$slots.default;
var clonedVNodes = new Array(6);
for (var i = 0;i < 6;i++){
clonedVNodes[i] = vNodes.map(function (vnode) {
return cloneVNode(vnode);
});
}
使用Javascript代替模板功能:
在Render函数中,不需要Vue内置的指令,比如v-if,v-for,当然,也没办法使用他们。无论要实现什么功能,都可以用原生的Javascript。
<div id="app"><!--
<ele :show="show"></ele>
<button @click="show = !show">切换show</button>-->
<ele :list="list"></ele>
</div>
<script>
Vue.component('ele',{
render:function(createElement) {
var nodes = [];
for (var i = 0;i <this.list.length;i++){
nodes.push(createElement('p',this.list[i]));
}
return createElement('div',nodes);
},
props:{
list:{
type:Array
}
}
});
var app = new Vue({
el:'#app',
data:{
list:[
'《Vue实战》',
'《JavaScript实战》',
'《Javascript精粹》'
]
}
})
</script>