vue、react隱式例項化

limengke123發表於2018-07-18

這是一篇幾個月前寫的文章,那時候理解也不是特別透徹,但還是搬運到掘金髮一遍。

寫這篇的緣由是因為上一篇vue與react元件對比學習寫的有點囉嗦也沒有寫的很明白同時也存在一點錯誤,所以重新寫一篇簡介概要點的。

隱式例項化

隱式例項化,不希望寫在reactjsx裡或是vuetemplate,而是希望通過手動去例項化一個react或是vue元件。

說的有點繞,這種隱式例項化的應用場景在提示資訊(message)、模態框(modal)、載入條(loadingbar),例如一個ajax請求,在成功或失敗的時候需要給一個提示:

// 下面是虛擬碼...

import message from 'message'

fetch('/api/xxx')
    .then(resp => {
        if(resp.success === true){
            message({
                type:"success",
                text:"請求成功"
            })
        } else {
            message({
                type:"error",
                text:"請求出錯"
            })
        }
    })

複製程式碼

可以看的出來,我們的需求是想有一個元件能像html原生的alert一樣,在需要的地方能夠直接去呼叫,而不是需要把message元件寫進節點中。

難點

我們都知道不論是react、還是vue也好,寫的都是一個類或者叫構造器:


// react 引用程式碼省略

export default class Message extends React.Component{}

// vue
// export default {
    data(){},
    props:{},
    methods:{},
    render:function(){}
}


複製程式碼

react相當明顯地建立了一個classvue表面上好像只是暴露一個物件,實際上vue的元件被使用時,你需要把子元件傳入父元件的component的物件中,所以Vue會呼叫Vue.extend({...自組建的選項物件}),這個方法就返回了一個構造器。

既然知道了子元件是一個構造器,那我能不能直接去手動new一個子元件呢?在我測試下來,好像是不行。

vue例項化

那麼如何例項化呢?分成兩部分,先是例項化一個元件,然後再把例項化後的元件掛載到html中去。先拿vue說:

拿到構造器

import Vue from 'vue'
import message from './message.vue'

// 注意: 這裡的message僅僅就是一個物件,需要轉成構造器

const messageConstructor = Vue.extend(message)


複製程式碼

例項化

const customProps = {
    // 傳給元件的一些props
}


// 這樣就能拿到了一個vue元件的例項,就能做很多事情了,比如呼叫例項中寫好的methods中的方法,當然這還沒完,我們還得把例項掛載到Html中
const messageInstance = new messageConstuctor({propsData:customProps})
複製程式碼

掛載

vue的例項有一個很重要的方法:$mount,在選項物件中我們沒有傳入el屬性,所以你在這裡手動例項化的vue例項是沒有掛載出來的,需要手動呼叫一遍$mount,可以傳入一個DOM節點做為掛載節點,當然也可以不傳入引數,後面手動用dom方法把節點插入。


// 這裡返回的messageWithDom依然還是vue例項而不是dom節點,但是這個例項多了一個$el屬性,這個屬性裡面就藏著我們需要掛載的dom節點
const messageWithDom = messageInstance.$mount()

const dom = messageWithDom.$el

document.body.appendChild(dom)

複製程式碼

野路子

vue隱式化例項,基本是這個套路,當然我在看iview元件庫中用了一些其他的野路子,這裡也貼一下:


import Notification from './notification.vue';
import Vue from 'vue';

const _props = properties || {};

const Instance = new Vue({
    render (h) {
        return h(Notification, {
            props: _props
        });
    }
});

複製程式碼

道理基本上和我說的差不多,不過呼叫Vue.extend更加容易理解。

後續控制

拿到元件的例項後,基本上想怎麼玩就能怎麼玩了,比如說控制隱藏或顯示,可以在元件內部定義一個isShowdata屬性,在例項上可以這樣用:


if( xxxx ) {
    messageWithDom.isShow = true
} else {
    messageWithDom.isShow = false
}

複製程式碼

react例項化

react的例項化和vue稍稍不同,首先引進來的直接就是一個類所以不需要像Vue一樣多做一步轉換成構造器,其次react是沒有類似vue$mount方法,這也是我一開始很疑惑的地方,後來突然想起來react把元件的掛載方法放到了reactDom這個包裡面了。

建立一個虛擬dom

這裡需要呼叫React.createElement去建立一個虛擬dom,其實vue也能建立一個虛擬dom,參考上面iview的野路子。

import React from 'react'
import Message from './message.jsx'

const customProps = {
    // 傳給自元件的一些props
}

const Vnode = React.createElment(Message,{props:customProps})

複製程式碼

掛載並且拿到例項

react沒有$mount方法,而是直接呼叫reactDomrender方法,相當於vue的兩步直接一步完成:

import React from 'react'
import ReactDom from 'react-dom'

const containner = document.createElement('div')
document.body.appendChild(containner)

// 把虛擬dom傳入reactDom.render方法中,第二個引數是掛載的節點,並返回這個元件的例項
const messageInstance = ReactDom.render(Vnode,containner)
複製程式碼

後續的控制

拿到元件的例項後,基本想怎麼玩就能怎麼玩了,但是別忘記了!!!react修改state是呼叫setState,而不像vue直接修改。

總結

學會隱式化建立例項能夠很好的看清楚vuereact內部的細節,對提高vuereact大有好處。我的一個專案有個載入條的元件,同時用reactvue都實現了一遍,可以對比學習發現兩者的差異,喜歡的可以點個贊~~。

相關文章