vue的狀態(tài)更新方式(異步更新解決)
狀態(tài)更新(異步更新解決)
在vue中狀態(tài)更新是異步的,這一點(diǎn)和react中的setstate類似。
解決方案
非組件解決方案:
<div id="example">{{message}}</div>
var vm = new Vue({ ? el: '#example', ? data: { ? ? message: '123' ? } }) vm.message = 'new message' // 更改數(shù)據(jù) vm.$el.textContent === 'new message' // false Vue.nextTick(function () { ? vm.$el.textContent === 'new message' // true })
在組件內(nèi)使用 vm.$nextTick() 實(shí)例方法特別方便,因?yàn)樗恍枰?Vue ,并且回調(diào)函數(shù)中的 this 將自動(dòng)綁定到當(dāng)前的 Vue 實(shí)例上:
Vue.component('example', { ? template: '<span>{{ message }}</span>', ? data: function () { ? ? return { ? ? ? message: '沒有更新' ? ? } ? }, ? methods: { ? ? updateMessage: function () { ? ? ? this.message = '更新完成' ? ? ? console.log(this.$el.textContent) // => '沒有更新' ? ? ? this.$nextTick(function () { ? ? ? ? console.log(this.$el.textContent) // => '更新完成' ? ? ? }) ? ? } ? } })
因?yàn)?$nextTick() 返回一個(gè) Promise 對(duì)象,所以你可以使用新的 ES2016 async/await 語法完成相同的事情:methods: {
? updateMessage: async function () { ? ? this.message = 'updated' ? ? console.log(this.$el.textContent) // => '未更新' ? ? await this.$nextTick() ? ? console.log(this.$el.textContent) // => '已更新' ? } }
異步更新及nexttick
為什么需要異步更新
vue為了避免頻繁的操作DOM,采用異步的方式更新DOM。這些異步操作會(huì)通過nextTick函數(shù)將這些操作以cb的形式放到任務(wù)隊(duì)列中(以微任務(wù)優(yōu)先),當(dāng)每次tick結(jié)束之后就會(huì)去執(zhí)行這些cb,更新DOM。
異步更新內(nèi)部是最重要的就是nextTick方法,它負(fù)責(zé)將異步任務(wù)加入隊(duì)列和執(zhí)行異步任務(wù)。VUE 也將它暴露出來提供給用戶使用。在數(shù)據(jù)修改完成后,立即獲取相關(guān)DOM還沒那么快更新,使用nextTick便可以解決這一問題。
nextTick 原理
在下次DOM更新循環(huán)結(jié)束之后執(zhí)行的延遲回調(diào)。在修改數(shù)據(jù)之后立即使用該方法,獲取更新后的DOM。
/*存放異步執(zhí)行的回調(diào)*/ const callbacks = [] /*一個(gè)標(biāo)記位,如果已經(jīng)有timerFunc被推送到任務(wù)隊(duì)列中去則不需要重復(fù)推送*/ let pending = false /*一個(gè)函數(shù)指針,指向函數(shù)將被推送到任務(wù)隊(duì)列中,等到主線程任務(wù)執(zhí)行完時(shí),任務(wù)隊(duì)列中的timerFunc被調(diào)用*/ let timerFunc /* 推送到隊(duì)列中下一個(gè)tick時(shí)執(zhí)行 cb 回調(diào)函數(shù) ctx 上下文 */ export function nextTick (cb?: Function, ctx?: Object) { let _resolve // 第一步 傳入的cb會(huì)被push進(jìn)callbacks中存放起來 callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) // 檢查上一個(gè)異步任務(wù)隊(duì)列(即名為callbacks的任務(wù)數(shù)組)是否派發(fā)和執(zhí)行完畢了。pending此處相當(dāng)于一個(gè)鎖 if (!pending) { // 若上一個(gè)異步任務(wù)隊(duì)列已經(jīng)執(zhí)行完畢,則將pending設(shè)定為true(把鎖鎖上) pending = true // 調(diào)用判斷Promise,MutationObserver,setTimeout的優(yōu)先級(jí) timerFunc() } // 第三步執(zhí)行返回的狀態(tài) if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } }
Vue 在更新 DOM 時(shí)是異步執(zhí)行的。只要偵聽到數(shù)據(jù)變化,Vue 將開啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
如果同一個(gè) watcher 被多次觸發(fā),只會(huì)被推入到隊(duì)列中一次。這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作是非常重要的。
然后,在下一個(gè)的事件循環(huán)“tick”中,Vue 刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作。
Vue 在內(nèi)部對(duì)異步隊(duì)列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執(zhí)行環(huán)境不支持,則會(huì)采用 setTimeout(fn, 0) 代替。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- vue在使用ECharts時(shí)的異步更新和數(shù)據(jù)加載詳解
- VUE異步更新DOM - 用$nextTick解決DOM視圖的問題
- 詳解Vue的異步更新實(shí)現(xiàn)原理
- 淺談Vuejs中nextTick()異步更新隊(duì)列源碼解析
- vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù))
- vue中$nextTick的用法講解
- Vue中this.$nextTick的作用及用法
- Vue中的nextTick作用和幾個(gè)簡(jiǎn)單的使用場(chǎng)景
- Vue中this.$nextTick()的理解與使用方法
- 簡(jiǎn)單理解Vue中的nextTick方法
- vue2.0$nextTick監(jiān)聽數(shù)據(jù)渲染完成之后的回調(diào)函數(shù)方法
- 深入理解Vue nextTick 機(jī)制
- Vue2異步更新及nextTick原理詳解
相關(guān)文章
解決vue-cli單頁面手機(jī)應(yīng)用input點(diǎn)擊手機(jī)端虛擬鍵盤彈出蓋住input問題
今天小編就為大家分享一篇解決vue-cli單頁面手機(jī)應(yīng)用input點(diǎn)擊手機(jī)端虛擬鍵盤彈出蓋住input問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08Vue數(shù)據(jù)代理的實(shí)現(xiàn)流程逐步講解
通過一個(gè)對(duì)象代理對(duì)另一個(gè)對(duì)象中的屬性的操作(讀/寫),就是數(shù)據(jù)代理。要搞懂Vue數(shù)據(jù)代理這個(gè)概念,那我們就要從Object.defineProperty()入手,Object.defineProperty()是Vue中比較底層的一個(gè)方法,在數(shù)據(jù)劫持,數(shù)據(jù)代理以及計(jì)算屬性等地方都或多或少的用到了本函數(shù)2023-01-01詳解Vue.js使用Swiper.js在iOS<11時(shí)出現(xiàn)錯(cuò)誤
這篇文章主要介紹了詳解Vue.js使用Swiper.js在iOS<11時(shí)出現(xiàn)錯(cuò)誤,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09vue項(xiàng)目main.js使用方法詳細(xì)介紹
這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目main.js使用方法的相關(guān)資料,main.js文件是程序的入口文件,加載各種公共組件,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09Vue組件間通信方法總結(jié)(父子組件、兄弟組件及祖先后代組件間)
這篇文章主要給大家介紹了關(guān)于Vue組件間通信的相關(guān)資料,其中包括父子組件、兄弟組件及祖先后代組件間的通信,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04vue路由對(duì)不同界面進(jìn)行傳參及跳轉(zhuǎn)的總結(jié)
這篇文章主要介紹了vue路由對(duì)不同界面進(jìn)行傳參及跳轉(zhuǎn)的總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Element-ui的table中使用fixed后出現(xiàn)行混亂情況的解決
這篇文章主要介紹了Element-ui的table中使用fixed后出現(xiàn)行混亂情況的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10