Vue.js——Render函数

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>

猜你喜欢

转载自blog.csdn.net/qq_38311097/article/details/82765435
今日推荐