西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

碼農土哥發表於2018-04-25

最近我參加了一次來自西安的電話面試(第二輪,技術面),是大廠還是小作坊我在這裡按下不表,先來說說這次電面給我留下印象較深的幾道面試題,這次先來談談Vue的資料雙向繫結原理。

情景再現:

當我手機鈴聲響起,看著螢幕上面顯示的歸屬地是來自陝西西安的電話,我知道屬於我人生的第一次電話面試要來了。接起電話後,電腦那頭傳來了面試官的聲音(中間省略了一些客套,直接上面試題。)面試官發問,“談談你對Vue資料雙向繫結的認識”。

面試官的這個問題也可以理解成為“你是怎麼理解Vue資料繫結,知道它背後實現的原理麼”。一般剛畢業的前端新人可能會說,用v-model。(當然,這可能是句廢話)

如果簡單說下v-model指令,是Vue的語法糖之類的,可能不會讓面試官滿意,也看不出你對Vue的熟練程度。只能說明你看過Vue的官方文件,如下圖所示:

西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

如果你的回答點到此為止,基本上是不合格的。此時面試官可能會含蓄地追問:然後呢?

其實,如果面試官就這個問題追問,你應該要往兩方面想。往淺了說,如果不用v-model指令,你能用自己的思路實現雙向繫結嗎?往深了挖,他是想問v-model實現背後的原理。

如果你能get到這一點,說明你已經上道了,起碼是在公司中開發過業務程式碼的小碼農。

那如何在元件中自定義實現類似v-model的資料繫結呢?

我先擼為敬:

import Vue from 'vue'

const component = {
    template: `
        <div>
            <input type="text" @input="handleInput">
        </div>
    `,
    methods: {
        handleInput (e) {
            this.$emit('input', e.target.value)
        }
    }
}

new Vue({
    conponents: {
        CompA: component
    },
    el: '#root',
    template: `
        <div>
            <comp-a></comp-a>
        </div>
    `
})
複製程式碼

這是一個初始化的demo,定義了一個元件component,例項化了一個Vue物件。v-model繫結的值,是從外層的Vue例項中傳進去的。首先我們要在元件component裡面定義一個props:

props: ['value']
複製程式碼

然後就可以在Vue例項的template模板裡面去加上這個value,同時繫結input事件:

template: `
    <div>
        <comp-a :value="value" @input="value = arguments[0]"></comp-a>
    </div>
`,
data () {
    return {
        value: 'runtu'
    }
}
複製程式碼

解釋一下,上面程式碼中的arguments就是元件template裡面的$emit傳出來的值,所有的引數都會放到arguments裡面,類似於陣列。所以這邊我們把arguments[0]賦值給了value。

同樣,元件component裡面的input也得繫結value:

const component = {
    props: ['value'],
    template: `
        <div>
            <input type="text" @input="handleInput" :value="value">
        </div>
    `,
    methods: {
        handleInput (e) {
            this.$emit('input', e.target.value)
        }
    }
}
複製程式碼

等執行完以上步驟,江湖規矩,先在terminal裡面跑一下 npm run dev

西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

看到demo執行成功地跑在本地8080埠之後,再將視線轉移到瀏覽器裡看一下:

西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

你可以看到Root裡面的value是“runtu”,當我們在input框裡輸入什麼,它的data裡面的值就會變成什麼。相當於我們在Vue例項模板中使用v-model,就等價於我們去繫結了:value@input

到此,這個demo已經實現了v-model的功能。

當然,此時的template裡面可以直接將:value@input替換為v-model,效果是一樣的:

template: `
    <div>
        <comp-a v-model="value"></comp-a>
    </div>
`,
複製程式碼

西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

這應該是最簡單的實現v-model資料繫結的demo。只需要在一個元件裡面有個props,加上一個value,然後當元件要去修改資料的時候, $emit一個input事件,並且把新的值傳出去。這就實現了Vue裡面的資料雙向繫結。

其實,v-model指令就是在元件上加了一個props,以及增加了一個事件監聽(比如本demo中的input事件),說白了,在v-model裡面作者幫我們封裝了這個雙向繫結的邏輯,我們只管拿去用就好。

當然這個demo還可以更進一步,給變數的名稱定義一下,這樣看起來更加靈活:

const conmponent = {
    model: {
        prop: 'value',
        event: 'change'
    },
    props: ['value'],
    template: `
        <div>
            <input type="text" @input="handleInput" :value="value">
        </div>
    `,
    methods: {
        handleInput (e) {
            this.$emit('change', e.target.value)
        }
    }
}
複製程式碼

總結

一句話總結就是:在資料渲染時使用prop渲染資料 將prop繫結到子元件自身的資料上,修改資料時更新自身資料來替代prop, watch子元件自身資料的改變,觸發事件通知父元件更改繫結到prop的資料。

面試官可能還會不厭其煩地問你,Vue資料繫結這樣做的好處是什麼?

敲黑板劃重點:父元件資料改變時,不會修改儲存prop的子元件資料,只是以子元件資料為媒介,完成對prop的雙向修改。

如果還要繼續深挖,就得搬個小板凳泡上一壺茶準備好瓜子花生,坐下來跟面試官好好聊一聊Vue的響應式原理了,Object.defineProperty() 通過 getter 和 setter 劫持了物件賦值的過程,在這個過程中可以進行更新 dom 操作等等。

當你能聊到這部分的時候,說明你對Vue的研究達到了一定的程度,面試官也能通過這個問題了解到電話那頭的你對Vue.js知識掌握的深淺,不止停留在使用API做業務開發層面。

當然,這道面試題僅僅是我此次西安電話面試的開胃菜,接下來還有更多面試題等著我去回答,此電面系列文章會第一時間更新在我的公眾號<閏土大叔>裡面,歡迎大家關注。

西安電話面試:談談Vue資料雙向繫結原理,看看你的回答能打幾分

另外,跟大家透個底,目前為止,通過幾輪的面試,我已經成功地拿到了這家上市公司的offer。

未完待續......

相關文章