vue渲染函數&JSX

Vue推薦在絕大多數狀況下使用template來建立你的HTML。然而在一些場景中,你真的須要JavaScript的徹底編程能力,這時你可使用render函數,它比template跟接近編譯器.

虛擬DOM

在深刻渲染函數以前,瞭解一些瀏覽器的工做原理很重要。如下面這段HTML爲例:html

<div>
    <h1>My title</h1>
    Some text content
    <!--TODO:添加標籤行-->
</div>

當瀏覽器讀到這些代碼時,它會創建一個‘DOM節點樹’來保持追蹤,如同你會畫一張家譜樹來追蹤家庭成員的發展同樣。
HTML的DOM節點樹以下圖所示:
圖片描述
每一個元素都是一個節點。每片文字也是一個節點。甚至註釋也都是節點。一個節點就是頁面的一個部分。就像家譜樹同樣,每一個節點均可以有孩子節點(也就是說每一個部分能夠包含其它一些部分)。
高效的更新全部這些節點會是比較困難的,不過所幸你沒必要再手動完成這個工做了。你只須要告訴Vue你但願頁面上的HTML是什麼,這能夠是在一個模板裏:node

<h1>{{blogTitle}}</h1>

或則一個渲染函數裏:express

render:function(createElement){
    return createElement('h1',this.blogTitle);
}

在這兩種狀況下,Vue都會自動保持頁面的更新,即使blogTitle發生了改變。編程

Vue經過創建一個虛擬DOM對真實的DOM發生的變化保持追蹤。請仔細看這行代碼:數組

return createElement('h1',this.blogTitle)

createElement到底返回什麼呢?其實不是一個實際的Dom元素。它更準確的名字多是createNodeDescription,由於它所包含的信息會告訴Vue頁面上須要渲染什麼樣的節點,及其子節點。咱們把這樣的節點描述爲虛擬節點,也常簡寫爲VNode。虛擬DOM是咱們對Vue組件樹創建起來的整個VNode樹的稱呼。瀏覽器

createElement參數app

createElement(
    //{String|Object|Function}
    //一個HTML標籤字符串,組件選項對象,或則解析上述任何一種的一個async異步函數。必須參數。
    'div',
    
    //{Object}一個包含模板相關屬性的數據對象,你能夠在template中使用這些特性。可選參數。
    {},
    
    //{String|Array}子虛擬節點,由createElement()構建而成,也可使用也可使用字符串來生成文本虛擬節點。可選參數。
    [
        '先寫一些文字',
        createElement('h1','一則頭條'),
        createElement(Mycomponent,{
            props:{
                someProp:'foobar'
            }
        })
    ]
    
)

深刻data對象

有一點要注意:正如在模板語法中,v-bind:class和v-bind:style,會被特別對待同樣,在VNode數據對象中,下列屬性名是級別最高的字段。該對象也容許你綁定普通的HTML特性,就像DOM屬性同樣,好比innnerHTML(這會取代v-html指令)。dom

{
    //和v-bind:class同樣的API,接收一個字符串、對象或字符串和對象組成的數組。
    'class':{
        foo:true,
        bar:false
    },
    //和v-bind:style同樣的API,接收一個字符串、對象或對象數組組成的數組
    style:{
        color:'red',
        fontSize:'14px'
    },
    //普通的HTML特性
    attrs:{
        id:'foo'
    },
    //組件props
    props:{
        myPro:'bar'
    },
    //DOM屬性
    domProps:{
        innerHTML:'baz'
    },
    //事件監聽器基於'on',因此再也不支持如v-on:keyup.enter修飾符,須要手動匹配keyCode.
    on:{
        click:this.clickHandler
    },
    //僅用於組件,用於監聽原生事件,而不是組件內部使用,vm.$emit觸發的事件。
    nativeOn:{
        click:this.nativeClickHandler
    },
    //自定義指令。注意,你沒法對binding中的oldValue賦值,由於Vue已經自動爲你進行了同步。
    directives:[
        {
            name:'my-custom-directive',
            value:'2',
            expression:'1+1',
            arg:'foo',
            modifiers:{
                bar:true
            }
        }
    ],
    //做用域插槽格式,{name:props=>createElement('span',props.text)}
    scopedSlots:{
        default:props=>createElement('span',props.text)
    },
    //若是組件是其它組件的子組件,須要爲插槽指定名稱。
    slot:'name-of-slot',
    //其它特殊頂層屬性
    key:'myKey',
    ref:'myRef',
    //若是你在渲染函數中向多個元素都應用了相同的ref名,那麼$refs.myRef會變成一個數組。
    refInFor:true
}

完整示例

有了這些知識,咱們如今能夠完成咱們最開始想實現的組件:異步

var getChildrenTextContent = function(children){
    return children.map(function(node){
        return node.children
        ?getChildrenTextContent(node.children)
        :node.text
    }).join('')
}
Vue.component('anchord-heading',{
    render:function(createElement){
        //建立kebab-case風格的ID
        var headingId = getChildrenTextContent(this.$slots.default)
            .toLowerCase()
            .replace(/\W+/g,'-')
            .replace(/(^\-|\-$)/g,'')
        return createElement(
            'h'+this.level,
            [
                createElement('a',{
                    attrs:{
                        name:headingId,
                        href:'#'+headingId
                    }
                },this.$slots.default)
            ]
        )
    },
    props:{
        level:{
            type:Number,
            required:true
        }
    }
})

約束

VNodes必須惟一
組件樹中的全部VNodes必須是惟一的。這意味着,下面的render function是無效的:
render:function(createElement){async

var myParagraphVNode = createElement('div',[
    //錯誤-重複的VNodes
    myParagraphVNode,myParagraphVNode
])

}
若是你真的須要重複不少次的元素/組件,你可使用工廠函數來實現。例如,下面這個例子render函數完美有效地渲染了20個相同的段落:

render:function(createElement){
    return createElement('div',
        Array.apply(null,{length:20}).map(function(){
            return createElement('p','hi')
        })
    )
}
相關文章
相關標籤/搜索