Vue.js入门 0xB Render函数(1)基础

    Vue.js 2.x 与 Vue.js 1.x 最大的区别就在于 2.x 使用了 Virtual Dom (虚拟 DOM )来更新 DOM节点,提升擅染性能。

Virtual Dom

    React 和 Vue 2 都使用了 Virtual Dom 技术, Virtual Dom 并不是真正意义上的 DOM ,而是一个轻量级的 JavaScript 对象,在状态发生变化时, Virtual Dom 会进行 Diff 运算,来更新只需要被替换的 DOM,而不是全部重绘。
    与 DOM 操作相比, Virtual Dom 是基于 JavaScript 计算的,所以开销会小很多 。

     用 Virtual Dom 创建的 JavaScript 对象一般会是这样的:

var vNode = {
    tag:'div',
    attributes:{
        id:'main'
    },
    children:[
        //p节点
    ]
}

   在 Vue.js 2 中, Virtual Dom 就是通过一种 VNode 类表达的,每个 DOM 元素或组件都对应一个 VNode 对象,在 Vu巳. 源码中是这样定义的:

export interface VNode {
    tag?:string;//当前节点的标签名
    data?:VNodeData;//当前节点的数据对象
    children?:VNode[];//子节点,数组,也是VNnode类型
    text?:string;//当前节点的文本,一般文本节点或注释会有该属性
    elm?:Node;//当前虚拟节点对应的真实的DOM节点
    ns?:string;//节点的namespace
    context?:Vue;
    key?:string|number;//节点的key属性,用于作为节点的标识,有利于patch的优化
    componentOptions?:VNodeComponentOptions;//创建组件实例时会用到的选项信息
    componentInstance?:Vue;
    parent?:VNode;//组件的占位节点
    raw?:boolean;//原始HTML
    isStatic?:boolean;//静态节点标识
    isRootInser:boolean;//是否作为根节点插入,被<transition>包裹的节点,该属性的值为false
    isComment:boolean;//当前节点是否是注释节点
}

    VNodeData 代码如下:

export interface VNodeData {
    key?:string|number;
    slot?:string;
    scopedSlots?:{[key:string]:ScopedSlot};
    ref?:string;
    tag?:string;
    staticStyle?:{[key:string]:any};
    style?:Object[] | Object;
    props?:{[key:string]:any};
    attrs?:{[key:sstring]:any};
    domProps?:{[key:string]:any};
    hook?:{[key:string]:Function};
    on?:{[key:string]:Function|Function[]};
    nativeOn?:{[key:string]:Function|Function[]};
    transition?:Object;
    show?:boolean;
    inlineTemplate?:{
        render:Function;
        staticRenderFns:Function[];
    };
    directives?:VNodeDirection[];
    keepAlive?:boolean;
}

    主要可分以下几列:

 

什么是Render函数

    Render 函数通过 createElement 参数来创建 Virtual Dom,结构精简了很多。

<div id="app">
    <anchor :level="2" title="特性">特性</anchor>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    Vue.component('anchor',{
        props:{
            level:{
                type:Number,
                required:true
            },title:{
                type:String,
                default:''
            }
        },
        render:function(createElement){
            return createElement(
                'h'+this.level,
                [
                    createElement(
                        'a',
                        {
                            domProps:{
                                href:'#'+this.title
                            }
                        },
                        this.$slots.default
                    )
                ]
            )
        }
    });
    var app = new Vue({
        el:'#app'
    })
</script>

createElement 用法

    基本参数

createElement(
    //{String | Object | Function}
    //一个HTML标签,组件选项,或一个函数
    //必须Return上述其中一个
    'div',
    //{Object}
    //一个对应属性的数据对象,可选
    //可以在template中使用
    {
        //和v-bind:class一样的API
        'class':{
            foo:true,
            bar:false
        },
        //和v-bind:style一样的API
        style:{
            color:'red',
            fontSize:'14px'
        },
        //正常的HTML特性
        attrs:{
            id:'foo'
        },
        //组件props
        props:{
            myProp:'bar'
        },
        //DOM属性
        domProps:{
            innerHTML:'baz'
        },
        //自定义事件监听器“on”
        //不支持如v-on:keyup.enter的修饰器
        //需要手动匹配keyCode
        on:{
            click:this.clickHandler
        },
        //仅对于组件,用于监听原生事件
        //而不是组件使用vm.$emit触发的自定义事件
        nativeOn:{
            click:this.nativeClickHandler
        },
        //自定义指令
        directives:[
            {
                name:'my-custom-directive',
                value:'2',
                expression:'1+1',
                arg:'foo',
                modifiers:{
                    bar:ture
                }
            }
        ],
        //作用域slot
        //{name:props=>VNode|Array<VNode>}
        scopedSlots:{
            default:props=>h('sspan',props.text)
        },
        //如果子组件有定义slot的名称
        slot:'name-of-slot'
        //其他特殊顶层属性
        key:'myKey',
        ref:'myRef'
    },
    //{String | Array}
    //子节点(VNodes),可选
    [
        createElement('h1','hello world'),
        createElement(MyComponent,{
            props:{
                someProp:'foo'
            }
        }),
        'bar'
    ]
)

    以往在 template 里 , 我们都是在组件的标签上使用形容 v-bind:class 、 v-bind:s刷e、 v-on:click这样的指令,在 Render 函数都将其写在了数据对象里

    传统的 template 写法:

<div id="app"> 
    <ele></ele>
</div>
<script>
    Vue.component('ele',{
        template:'\
            <div id="element"\
                :class="{show:show}"\
                @click="handleClick">文本内容</div>',
        data:function(){
            return {
                show:true
            }
        },
        methods:{
            handleClick:function(){
                console.log('clicked!');
            }
        }
    };
    var app = new Vue({
        el:'#app'
    })
</script>

    使用 Render 改写后:

<div id="app">
    <ele></ele>
</div>
<script>
    Vue.component('ele',{
        render:function(createElement){
            return createElement(
                'div',
                {
                    //动态绑定class,同:class
                    class:{
                        'show':this.show
                    },
                    //普通html属性
                    attrs:{
                        id:'element'
                    },
                    //给div绑定click事件
                    on:{
                        click:this.handleClick
                    }
                },
                '文本内容'
            )
        },
        data:function(){
            return {
                show:true
            }
        },
        methods:{
            handleClick:function(){
                console.log('clicked!');
            }
        }
    });
    var app = new Vue({
        el:'#app'
    })
</script>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值