最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue nextTick延遲回調(diào)獲取更新后DOM機制詳解

 更新時間:2022年08月02日 11:12:02   作者:楊柒柒  
這篇文章主要為大家介紹了Vue nextTick延遲回調(diào)獲取更新后DOM機制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

簡述

相信大家在寫vue項目的時候,一定會發(fā)現(xiàn)一個神奇的api,Vue.nextTick。為什么說它神奇呢,那是因為在你做某些操作不生效時,將操作寫在Vue.nextTick內(nèi),就神奇的生效了。那這是什么原因呢?

讓我們一起來研究一下。

  • vue 實現(xiàn)響應(yīng)式并不是數(shù)據(jù)發(fā)生變化后 DOM 立即變化,而是按照一定策略異步執(zhí)行 DOM 更新的
  • vue 在修改數(shù)據(jù)后,視圖不會立刻進行更新,而是要等同一事件循環(huán)機制內(nèi)所有數(shù)據(jù)變化完成后,再統(tǒng)一進行DOM更新
  • nextTick 可以讓我們在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào),用于獲得更新后的 DOM。

事件循環(huán)機制

在討論Vue.nextTick之前,需要先搞清楚事件循環(huán)機制,算是實現(xiàn)的基石了,那我們來看一下。

在瀏覽器環(huán)境中,我們可以將我們的執(zhí)行任務(wù)分為宏任務(wù)和微任務(wù),

  • 宏任務(wù): 包括整體代碼script,setTimeout,setIntervalsetImmediate、 I/O 操作、UI 渲染
  • 微任務(wù): Promise.then、MuationObserver

事件循環(huán)的順序,決定js代碼的執(zhí)行順序。事件循環(huán)如下:

用代碼解釋,瀏覽器中事件循環(huán)的順序同如下代碼:

for (macroTask of macroTaskQueue) { 
    // 1. 執(zhí)行一個宏任務(wù)
    handleMacroTask();
    // 2. 執(zhí)行所有的微任務(wù)
    for (microTask of microTaskQueue) { 
        handleMicroTask(microTask);
    }
 }

vue數(shù)據(jù)驅(qū)動視圖的處理(異步變化DOM)

<template>
  <div>
    <div>{{count}}</div>
    <div @click="handleClick">click</div>
  </div>
</template>
export default {
    data () {
        return {
            number: 0
        };
    },
    methods: {
        handleClick () {
            for(let i = 0; i < 10000; i++) {
                this.count++;
            }
        }
    }
}

分析上述代碼:

  • 當點擊按鈕時,count會被循環(huán)改變10000次。那么每次count+1,都會觸發(fā)count的setter方法,然后修改真實DOM。按此邏輯,這整個過程,DOM會被更新10000次,我們都知道DOM的操作是非常昂貴的,而且這樣的操作完全沒有必要。所以vue內(nèi)部在派發(fā)更新時做了優(yōu)化
  • 也就是,并不會每次數(shù)據(jù)改變都觸發(fā) watcher 的回調(diào),而是把這些 watcher 先添加到一個隊列queueWatcher里,然后在 nextTick 后執(zhí)行 flushSchedulerQueue處理
  • 當 count 增加 10000 次時,vue內(nèi)部會先將對應(yīng)的 Watcher 對象給 push 進一個隊列 queue 中去,等下一個 tick 的時候再去執(zhí)行。并不需要在下一個 tick 的時候執(zhí)行 10000 個同樣的 Watcher 對象去修改界面,而是只需要執(zhí)行一個 Watcher 對象,使其將界面上的 0 變成 10000 即可

Vue.nextTick原理

由上一節(jié)我們知道,Vue中 數(shù)據(jù)變化 => DOM變化 是異步過程,一旦觀察到數(shù)據(jù)變化,Vue就會開啟一個任務(wù)隊列,然后把在同一個事件循環(huán) (Event loop) 中觀察到數(shù)據(jù)變化的 Watcher(Vue源碼中的Wacher類是用來更新Dep類收集到的依賴的)推送進這個隊列。

如果這個watcher被觸發(fā)多次,只會被推送到隊列一次。這種緩沖行為可以有效的去掉重復(fù)數(shù)據(jù)造成的不必要的計算和DOM操作。而在下一個事件循環(huán)時,Vue會清空隊列,并進行必要的DOM更新。

nextTick的作用是為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用 Vue.nextTick(callback),JS是單線程的,擁有事件循環(huán)機制,nextTick的實現(xiàn)就是利用了事件循環(huán)的宏任務(wù)和微任務(wù)。

vue中next-tick.js的源碼如下

import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
export let isUsingMicroTask = false
// 首先定義一個 callbacks 數(shù)組用來存儲 nextTick,在下一個 tick 處理這些回調(diào)函數(shù)之前,
// 所有的 cb 都會被存在這個 callbacks 數(shù)組中
const callbacks = []
// pending 是一個標記位,代表一個等待的狀態(tài)
let pending = false
// 最后執(zhí)行 flushCallbacks() 方法,遍歷callbacks數(shù)組,依次執(zhí)行里邊的每個函數(shù)
function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}
let timerFunc
/*
判斷采用哪種異步回調(diào)方式
由于微任務(wù)優(yōu)先級高,首先嘗試微任務(wù)模擬
1.首先嘗試使用Promise.then(微任務(wù))
2.嘗試使用MuationObserver(微任務(wù))回調(diào)
3.嘗試使用 setImmediate(宏任務(wù))回調(diào)
4.最后嘗試使用setTimeout(宏任務(wù))回調(diào)
*/
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}
export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    timerFunc()
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

目前瀏覽器平臺并沒有實現(xiàn) nextTick 方法,所以 Vue.js 源碼中分別用 Promise、setTimeout、setImmediate 等方式在 microtask(或是task)中創(chuàng)建一個事件,目的是在當前調(diào)用棧執(zhí)行完畢以后(不一定立即)才會去執(zhí)行這個事件。

nextTick的調(diào)用方式

回調(diào)函數(shù)方式:Vue.nextTick(callback)

Promise方式:Vue.nextTick().then(callback)

實例方式:vm.$nextTick(callback)

Vue.nextTick的應(yīng)用

created生命周期中操作DOM

created鉤子函數(shù)執(zhí)行的時候DOM 其實并未進行掛載和渲染,此時就是無法操作DOM的,我們將操作DOM的代碼中放到nextTick中,等待下一輪事件循環(huán)開始,DOM就已經(jīng)進行掛載好了,而與這個操作對應(yīng)的就是mounted鉤子函數(shù),因為在mounted執(zhí)行的時候所有的DOM掛載已完成。

created(){
  vm.$nextTick(() => {  
      //不使用this.$nextTick()方法操作DOM會報錯
      this.$refs.test.innerHTML="created中操作了DOM"
  });
}

修改數(shù)據(jù),獲取DOM值

當我們修改了data里的數(shù)據(jù)時,并不能立刻通過操作DOM去獲取到里面的值

<template>
  <div class="test">
    <p ref='msg' id="msg">{{msg}}</p>
  </div>
</template>
<script>
export default {
  name: 'Test',
  data () {
    return {
      msg:"hello world",
    }
  },
  methods: {
    changeMsg() {
      this.msg = "hello Vue"  // vue數(shù)據(jù)改變,改變了DOM里的innerText
      let msgEle = this.$refs.msg.innerText  //后續(xù)js對dom的操作
      console.log(msgEle)  // hello world
      // 輸出可以看到data里的數(shù)據(jù)修改后DOM并沒有立即更新,后續(xù)的DOM不是最新的
      this.$nextTick(() => {
        console.log(this.$refs.msg.innerText) // hello Vue
      })
      this.$nextTick().then(() => {
        console.log(this.$refs.msg.innerText) // hello Vue
      })
    },
    changeMsg2() {
      this.$nextTick(() => {
        console.log(this.$refs.msg.innerText) // 1.hello world 
      })
      this.msg = "hello Vue" // 2.
      console.log(this.$refs.msg.innerText) // hello world
      this.$nextTick().then(() => {
        console.log(this.$refs.msg.innerText) // hello Vue
      })
      // nextTick中先添加的先執(zhí)行,執(zhí)行1后,才會執(zhí)行2(Vue操作Dom的異步)
    }
  }
}
</script>

v-show/v-if由隱藏變?yōu)轱@示

點擊按鈕顯示原本以 v-show=false或v-if 隱藏起來的輸入框,并獲取焦點或者獲得寬高等的場景

以上就是Vue nextTick延遲回調(diào)獲取更新后DOM機制詳解的詳細內(nèi)容,更多關(guān)于Vue nextTick延遲回調(diào)DOM獲取的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • VueRouter導(dǎo)航守衛(wèi)用法詳解

    VueRouter導(dǎo)航守衛(wèi)用法詳解

    這篇文章主要介紹了VueRouter導(dǎo)航守衛(wèi)的詳細用法以及分類介紹,有興趣的朋友學(xué)習(xí)參考下吧。
    2017-12-12
  • vue proxyTable 接口跨域請求調(diào)試的示例

    vue proxyTable 接口跨域請求調(diào)試的示例

    本篇文章主要介紹了vue proxyTable 接口跨域請求調(diào)試的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 基于Vue.js的文件選擇與多選對話框組件Dccfile的使用教程

    基于Vue.js的文件選擇與多選對話框組件Dccfile的使用教程

    在現(xiàn)代前端開發(fā)中,Vue.js 提供了強大的組件化開發(fā)能力,使得我們可以輕松構(gòu)建復(fù)雜且可復(fù)用的用戶界面,本文將介紹一個基于 Vue.js 的文件選擇與多選對話框組件——Dccfile,并詳細解析其功能和實現(xiàn)細節(jié)
    2025-04-04
  • Vue自定義模態(tài)對話框彈窗

    Vue自定義模態(tài)對話框彈窗

    這篇文章主要為大家詳細介紹了Vue自定義模態(tài)對話框彈窗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 基于Vue-Cli 打包自動生成/抽離相關(guān)配置文件的實現(xiàn)方法

    基于Vue-Cli 打包自動生成/抽離相關(guān)配置文件的實現(xiàn)方法

    基于Vue-cli 項目產(chǎn)品部署,涉及到的交互的地址等配置信息,每次都要重新打包才能生效,極大的降低了效率。這篇文章主要介紹了基于Vue-Cli 打包自動生成/抽離相關(guān)配置文件 ,需要的朋友可以參考下
    2018-12-12
  • vue實現(xiàn)的下拉框功能示例

    vue實現(xiàn)的下拉框功能示例

    這篇文章主要介紹了vue實現(xiàn)的下拉框功能,涉及vue.js數(shù)據(jù)讀取、遍歷、事件響應(yīng)等相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • vue項目中main.js的用法

    vue項目中main.js的用法

    src/main.js是入口文件,主要作用是初始化vue實例并使用需要的插件, Vue.use()的作用就是讓它里面被注冊的組件能夠被全局使用,本文通過實例代碼介紹vue項目中main.js的用法,感興趣的朋友一起看看吧
    2023-10-10
  • Vue實現(xiàn)登錄以及登出詳解

    Vue實現(xiàn)登錄以及登出詳解

    本篇文章主要介紹了vue實現(xiàn)登陸登出的實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-09-09
  • Vue3中vuex的基本使用方法實例

    Vue3中vuex的基本使用方法實例

    Vuex是一個專為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式,它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化,下面這篇文章主要給大家介紹了關(guān)于Vue3中vuex的基本使用方法,需要的朋友可以參考下
    2022-04-04
  • vue input標簽通用指令校驗的實現(xiàn)

    vue input標簽通用指令校驗的實現(xiàn)

    這篇文章主要介紹了vue input標簽通用指令校驗的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11

最新評論

霍城县| 厦门市| 光泽县| 霞浦县| 武义县| 红桥区| 顺平县| 永胜县| 仙桃市| 宝应县| 华阴市| 孙吴县| 成都市| 鄢陵县| 湟源县| 贵港市| 孟州市| 阿勒泰市| 灵山县| 阳原县| 衡山县| 尼玛县| 石楼县| 醴陵市| 德昌县| 灌云县| 南靖县| 盘山县| 汉中市| 青浦区| 稷山县| 平舆县| 阜阳市| 榆社县| 哈尔滨市| 南江县| 铜鼓县| 赤水市| 南昌县| 陵川县| 班戈县|