kurotanshi / vue-ubike-information

YouBike 臺北市公共自行車即時資訊
2 stars 41 forks source link

組件作業上傳 #26

Closed Frenkieli closed 4 years ago

Frenkieli commented 4 years ago

問題一、觸發順序問題

這邊去測試了 nextTick 、 computed 的set 和 beforeUpdate 的觸發順序

預想中 computed的set應該會先觸發更改資料,而後觸發刷新DOM前的beforeUpdate,最後在觸發DOM刷新結束的 nextTick

但實際測試確是 nextTick => computed : set => beforeUpdate ,nextTick沒有像文件所講的在DOM更新結束updated後才觸發

測試結果沒有在DOM觸發結束後才拿到 e.target.value 請問是 nextTick 的使用方式在哪邊出錯了嗎?

測試過程殘骸在檔案 vue-bike\src\components\searchBar.vue 下面

觸發刷新結果

kurotanshi commented 4 years ago

問題一、觸發順序問題

這邊去測試了 nextTick 、 computed 的set 和 beforeUpdate 的觸發順序

預想中 computed的set應該會先觸發更改資料,而後觸發刷新DOM前的beforeUpdate,最後在觸發DOM刷新結束的 nextTick

但實際測試確是 nextTick => computed : set => beforeUpdate ,nextTick沒有像文件所講的在DOM更新結束updated後才觸發

測試結果沒有在DOM觸發結束後才拿到 e.target.value 請問是 nextTick 的使用方式在哪邊出錯了嗎?

測試過程殘骸在檔案 vue-bike\src\components\searchBar.vue 下面

觸發刷新結果

Hi, 這個問題很有趣。

按照你的設定,我猜測你預想 nextTick 應該會在最後才執行對吧? 但結果卻在一開始就出現了。

這裏我講一下我的看法。

你在 input 裡面同時用 v-model 綁定 conditionName,並且加入了 keydown 事件來執行 searchStart method:

<input 
  ref="searchName"
  id="searchName"
  class="form-control" 
  type="text" 
  v-model="conditionName"
  @keydown="searchStart"
>

這是 computed:

conditionName: {
  get: function({conditionNameProp}){
    return conditionNameProp;
  },
  set: function(val){
    let vm = this;
    vm.$emit('update:conditionNameProp', val);
    vm.$emit('page-change-event', 0);
    console.log(Date.now(), '設定');
  }
}

這是 method:

searchStart(){
  let vm = this;
  console.log('searchStart 觸發');

  vm.$nextTick(function(){
    console.log(Date.now(), 'searchStart nextTick 刷新', vm.$refs.searchName.value);
  })
}

結果當 input 被修改時, keydown 事件的 searchStart 先被執行, 並且印出 "searchStart 觸發"、連同 nextTick 的刷新也印出。

然後才進到 computed 的設定,最後才到 beforeUpdate hook 的 callback function。

這是因為 $nextTick 被調用的時候,會先去檢查「 DOM 操作相關的 queue」 是否還有未完成的任務, 如果有,則去等待 DOM 更新完成後執行,如果沒有就馬上執行。

setTimeout 0 秒的情況不同的是,setTimeout 會等待所有非主線程的任務完成後才執行。

而真正寫入 data / DOM 其實是在 computed 的 set 而不是 methods。

最好的檢驗方式,就是我們將 computedmethods 分別加入 setTimeout 0 秒 與 nextTick 的操作:

// computed
conditionName: {
  get: function({conditionNameProp}){
    return conditionNameProp;
  },
  set: function(val){
    let vm = this;
    vm.$emit('update:conditionNameProp', val);
    vm.$emit('page-change-event', 0);
    console.log(Date.now(), '設定');

    // setTimeout 0 秒
    window.setTimeout(() => { console.log(Date.now(), 'computed - setTimeout'); }, 0);

    // nextTick
    vm.$nextTick(function(){
      console.log(Date.now(), 'computed-set nextTick 刷新', vm.$refs.searchName.value);
    });
  }
// methods
searchStart () {
  let vm = this;
  console.log('searchStart 觸發');

  // setTimeout 0 秒
  window.setTimeout(() => { console.log(Date.now(), 'searchStart - setTimeout'); }, 0);

  // nextTick
  vm.$nextTick(function(){
    console.log(Date.now(), 'searchStart nextTick 刷新', vm.$refs.searchName.value);
  });
}
},

在 input 被更新之後,會依序出現這樣的結果:

截圖 2020-08-20 下午3 50 44

在 method 裡的 nextTick 會先被執行,然後進到 computed 、 beforeUpdate , 等待 DOM 同步完成後執行 computed 的 nextTick,最後才是兩者的 setTimeout。

希望有幫助到你對 nextTick 順序的觀念理解 :)