好傢伙,nextTick,
(...這玩意,不太常用)
在Vue中,nextTick是一個用於非同步執行回撥函數的方法。
它在Vue更新DOM後被呼叫,以確保在下一次DOM更新渲染完成後執行回撥函數。
而事實上,我們把佇列處理的操作封裝到了nexrTick方法中.
實際上,Vue在更新DOM時是非同步執行的。
當你修改Vue範例的資料時,Vue會對依賴這些資料的虛擬DOM進行重新渲染,然後更新到真實的DOM上。
但是,DOM更新是在下一個事件迴圈中執行的,而不是立即執行。
所以,如果你想在DOM更新後執行一些操作,你就可以使用nextTick方法。
這個方法會將回撥函數推入到微任務佇列中,並在DOM更新後執行。
這樣可以確保你在操作更新後的DOM,比如獲取元素的寬高等,而不是得到修改前的值。
舉一個非常簡單的例子
Vue.Mixin({ //全域性
created: function b() {
// console.log('b----2')
}
})
let vm = new Vue({
el: '#app', //編譯模板
// data: {
// },
data() {
// console.log(this)
return {
msg:'牛肉',
arr: [1, 2, 3],
}
},
created() {
// console.log(555)
}
})
console.log(vm.msg,"||直接列印msg的值")
setTimeout(() => {
//注意資料更新多次,vm._updata(vm._render()) 只需要執行一次
vm.arr.push({b:5})
vm.arr.push({b:6})
console.log(vm.msg,"||計時器列印msg的值")
vm.msg = '張三'
vm.$nextTick(()=>{
console.log(vm.msg,"||nextTick()方法列印msg的值")
})
}, 1000)
這裡
可以看出來
nextTick()方法中的console確實拿到了最新的值
給vm原型新增$nextTick方法
export function stateMixin(vm) {
//列隊批次處理
//1.處理vue自己的nextTick
//2.使用者自己的
vm.prototype.$nextTick = function (cb) {
// console.log(cb)
nextTick(cb)
}
}
let queue = [] // 將需要批次更新的watcher 存放到一個列隊中
let has = {}
let pending = false
//陣列重置
function flushWatcher() {
queue.forEach(item => {
item.run()})
queue = []
has = {}
pending = false
}
function queueWatcher(watcher) {
let id = watcher.id // 每個元件都是同一個 watcher
// console.log(id) //去重
if (has[id] == null) {//去重
//列隊處理
queue.push(watcher)//將wacher 新增到列隊中
has[id] = true
//防抖 :使用者觸發多次,只觸發一個 非同步,同步
if (!pending) {
//非同步:等待同步程式碼執行完畢之後,再執行
// setTimeout(()=>{
// queue.forEach(item=>item.run())
// queue = []
// has = {}
// pending = false
// },0)
nextTick(flushWatcher) // nextTick相當於定時器
}
pending = true
}
}
let callback = []
let pending = false
function flush(){
callback.forEach(cb =>cb())
pending =false
}
let timerFunc
//處理相容問題
//判斷全域性物件中是否存在Promise
//看瀏覽器是否支援promise
if(Promise){
timerFunc = ()=>{
Promise.resolve().then(flush) //非同步處理
}
}else if(MutationObserver){ //h5 非同步方法 他可以監聽 DOM 變化 ,監控完畢之後在來非同步更新
let observe = new MutationObserver(flush)
let textNode = document.createTextNode(1) //建立文字
observe.observe(textNode,{characterData:true}) //觀測文字的內容
timerFunc = ()=>{
textNode.textContent = 2
}
}else if(setImmediate){ //ie
timerFunc = ()=>{
setImmediate(flush)
}
}
export function nextTick(cb){
// 1vue 2
// console.log(cb)
//列隊 [cb1,cb2]
//此處,注意,我們要處理使用者的nextTick()也要處理vue自己的nextTick
callback.push(cb)
//Promise.then() vue3
if(!pending){
timerFunc() //這個方法就是非同步方法 但是 處理相容問題
pending = true
}
}