简述
- vue实现响应式并不是数据发生变化之后DOM立即发生变化,而是按照一定的策略进行更新。
- Vue在修改数据之后,视图不会立即更新,而是等同一事件循环体制内的所有数据变化完成之后,再同意进行DOM更新。
- nextTick可以在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。
Vue.nextTic的机制
- 为什么用 Vue.nextTick()
JS的运行机制:JS执行是单线程的,它是基于事件循环的
由于Vue DOM更新是异步执行,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保能够得到更新后的DOM,所以设置了Vue.nextTick()方法。
- 怎么用 Vue.nextTick()
语法 : Vue.nextTick( [callback, context] )
参数 :
{Function} [callback]:回调函数,不传时提供promise调用
{Object} [context]:回调函数执行的上下文环境,不传默认是自动绑定到调用它的实例上。
官方示例用法 :
vm.msg = 'Hello'
Vue.nextTick(function () {
}
Vue.nextTick()
.then(function () {
})
- 总结
使用Vue.nextTick()是为了可以获取更新后的DOM 。
触发时机:在同一事件循环中的数据变化后,DOM完成更新,立即执行Vue.nextTick()的回调
Vue.nextTick源码
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
export let isUsingMicroTask = false
const callbacks = []
let pending = false
function flushCallbacks() {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
let timerFunc
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) ||
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()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}