查看: 3404|回復: 0

[JavaScript/JQuery] 西安電話面試:談談Vue數據雙向綁定原理,看看你的回答能打幾分

發表于 2018-5-12 08:00:02

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

情景再現:

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

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

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

圖片描述

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

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

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

那如何在組件中自定義實現類似v-model的數據綁定呢?

我先擼為敬:

  1. import Vue from 'vue'
  2. const component = {
  3. template: `
  4. <div>
  5. <input type="text" @input="handleInput">
  6. </div>
  7. `,
  8. methods: {
  9. handleInput (e) {
  10. this.$emit('input', e.target.value)
  11. }
  12. }
  13. }
  14. new Vue({
  15. conponents: {
  16. CompA: component
  17. },
  18. el: '#root',
  19. template: `
  20. <div>
  21. <comp-a></comp-a>
  22. </div>
  23. `
  24. })
復制代碼

這是一個初始化的demo,定義了一個組件component,實例化了一個Vue對象。v-model綁定的值,是從外層的Vue實例中傳進去的。首先我們要在組件component里面定義一個props:

  1. props: ['value']
復制代碼

然后就可以在Vue實例的template模板里面去加上這個value,同時綁定input事件:

  1. template: `
  2. <div>
  3. <comp-a :value="value" @input="value = arguments[0]"></comp-a>
  4. </div>
  5. `,
  6. data () {
  7. return {
  8. value: 'runtu'
  9. }
  10. }
復制代碼

解釋一下,上面代碼中的arguments就是組件template里面的$emit傳出來的值,所有的參數都會放到arguments里面,類似于數組。所以這邊我們把arguments[0]賦值給了value。

同樣,組件component里面的input也得綁定value:

  1. const component = {
  2. props: ['value'],
  3. template: `
  4. <div>
  5. <input type="text" @input="handleInput" :value="value">
  6. </div>
  7. `,
  8. methods: {
  9. handleInput (e) {
  10. this.$emit('input', e.target.value)
  11. }
  12. }
  13. }
復制代碼

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

圖片描述

看到demo運行成功地跑在本地8080端口之后,再將視線轉移到瀏覽器里看一下:

圖片描述

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

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

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

  1. template: `
  2. <div>
  3. <comp-a v-model="value"></comp-a>
  4. </div>
  5. `,
復制代碼

圖片描述

這應該是最簡單的實現v-model數據綁定的demo。只需要在一個組件里面有個props,加上一個value,然后當組件要去修改數據的時候, $emit一個input事件,并且把新的值傳出去。這就實現了Vue里面的數據雙向綁定。

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

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

  1. const conmponent = {
  2. model: {
  3. prop: 'value',
  4. event: 'change'
  5. },
  6. props: ['value'],
  7. template: `
  8. <div>
  9. <input type="text" @input="handleInput" :value="value">
  10. </div>
  11. `,
  12. methods: {
  13. handleInput (e) {
  14. this.$emit('change', e.target.value)
  15. }
  16. }
  17. }
復制代碼
總結

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

面試官可能還會不厭其煩地問你,Vue數據綁定這樣做的好處是什么?

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

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

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

當然,這道面試題僅僅是我此次西安電話面試的開胃菜,接下來還有更多面試題等著我去回答,此電面系列文章會第一時間更新在我的公眾號里面。

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

未完待續.....



回復

使用道具 舉報