Vue數(shù)據(jù)變化后頁面更新詳細(xì)介紹
首先會通過module.hot.accept監(jiān)聽文件變化,并傳入該文件的渲染函數(shù):
module.hot.accept(/*! ./App.vue?vue&type=template&id=472cff63&scoped=true& */ "./App.vue?vue&type=template&id=472cff63&scoped=true&", __WEBPACK_OUTDATED_DEPENDENCIES__ => { /* harmony import */ _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./App.vue?vue&type=template&id=472cff63&scoped=true& */ "./App.vue?vue&type=template&id=472cff63&scoped=true&");
(function () {
api.rerender('472cff63', {
render: _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__.render,
staticRenderFns: _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__.staticRenderFns
})
})(__WEBPACK_OUTDATED_DEPENDENCIES__); })
隨后執(zhí)行rerender方法,只貼重點(diǎn)部分代碼:
record.Ctor.options.render = options.render
record.Ctor.options.staticRenderFns = options.staticRenderFns
record.instances.slice().forEach(function (instance) {
instance.$options.render = options.render
instance.$options.staticRenderFns = options.staticRenderFns
// reset static trees
// pre 2.5, all static trees are cached together on the instance
if (instance._staticTrees) {
instance._staticTrees = []
}
// 2.5.0
if (Array.isArray(record.Ctor.options.cached)) {
record.Ctor.options.cached = []
}
// 2.5.3
if (Array.isArray(instance.$options.cached)) {
instance.$options.cached = []
}
// post 2.5.4: v-once trees are cached on instance._staticTrees.
// Pure static trees are cached on the staticRenderFns array
// (both already reset above)
// 2.6: temporarily mark rendered scoped slots as unstable so that
// child components can be forced to update
var restore = patchScopedSlots(instance)
instance.$forceUpdate()
instance.$nextTick(restore)
})首先會給當(dāng)前的VueComponent的Options和實例里面的渲染函數(shù)替換為最新,然后執(zhí)行實例上的forceUpdate方法:
Vue.prototype.$forceUpdate = function () {
var vm = this;
if (vm._watcher) {
vm._watcher.update();
}
};該方法是執(zhí)行watcher實例的update方法:
Watcher.prototype.update = function () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
}
else if (this.sync) {
this.run();
}
else {
queueWatcher(this);
}
};function queueWatcher(watcher) {
var id = watcher.id;
if (has[id] != null) {
return;
}
if (watcher === Dep.target && watcher.noRecurse) {
return;
}
has[id] = true;
if (!flushing) {
queue.push(watcher);
}
else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
var i = queue.length - 1;
while (i > index$1 && queue[i].id > watcher.id) {
i--;
}
queue.splice(i + 1, 0, watcher);
}
// queue the flush
if (!waiting) {
waiting = true;
if (!config.async) {
flushSchedulerQueue();
return;
}
nextTick(flushSchedulerQueue);
}
}重點(diǎn)看 queueWatcher(this),將最新的watcher放入quene隊列并且將flushSchedulerQueue函數(shù)傳給nextTick。
function nextTick(cb, ctx) {
var _resolve;
callbacks.push(function () {
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(function (resolve) {
_resolve = resolve;
});
}
}在callbacks里面放入一個執(zhí)行回調(diào)的函數(shù)。并執(zhí)行timerFunc():
timerFunc = function () {
p_1.then(flushCallbacks);
// In problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS)
setTimeout(noop);
};該方法異步執(zhí)行flushCallbacks:
function flushCallbacks() {
pending = false;
var copies = callbacks.slice(0);
callbacks.length = 0;
for (var i = 0; i < copies.length; i++) {
copies[i]();
}
}開始執(zhí)行回調(diào)函數(shù)我們第一次放進(jìn)去的函數(shù)flushSchedulerQueue:
function flushSchedulerQueue() {
currentFlushTimestamp = getNow();
flushing = true;
var watcher, id;
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue.sort(sortCompareFn);
// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index$1 = 0; index$1 < queue.length; index$1++) {
watcher = queue[index$1];
if (watcher.before) {
watcher.before();
}
id = watcher.id;
has[id] = null;
watcher.run();
// in dev build, check and stop circular updates.
if (has[id] != null) {
circular[id] = (circular[id] || 0) + 1;
if (circular[id] > MAX_UPDATE_COUNT) {
warn$2('You may have an infinite update loop ' +
(watcher.user
? "in watcher with expression \"".concat(watcher.expression, "\"")
: "in a component render function."), watcher.vm);
break;
}
}
}
// keep copies of post queues before resetting state
var activatedQueue = activatedChildren.slice();
var updatedQueue = queue.slice();
resetSchedulerState();
// call component updated and activated hooks
callActivatedHooks(activatedQueue);
callUpdatedHooks(updatedQueue);
// devtool hook
/* istanbul ignore if */
if (devtools && config.devtools) {
devtools.emit('flush');
}
}首先觸發(fā)watcher.before(),該方法是beforeUpdate的hook。然后執(zhí)行watcher.run()方法:
Watcher.prototype.run = function () {
if (this.active) {
var value = this.get();
if (value !== this.value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
isObject(value) ||
this.deep) {
// set new value
var oldValue = this.value;
this.value = value;
if (this.user) {
var info = "callback for watcher \"".concat(this.expression, "\"");
invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info);
}
else {
this.cb.call(this.vm, value, oldValue);
}
}
}
};該方法watcher.get方法,該方法會重新執(zhí)行render方法生成vnode,然后調(diào)用update方法更新節(jié)點(diǎn):
updateComponent = function () {
vm._update(vm._render(), hydrating);
};總結(jié):
1.獲取監(jiān)聽文件最新的render和staticRenderFns并賦值給當(dāng)前的VueComponent和當(dāng)前vm實例。
2.使用$forceUpdate添加當(dāng)前的vm的watcher并在queue中,最后異步執(zhí)行flushSchedulerQueue,該函數(shù)遍歷quene執(zhí)行watcher的run方法,該方法會執(zhí)行vm實例的_update方法完成更新。
到此這篇關(guān)于Vue數(shù)據(jù)變化后頁面更新詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Vue頁面更新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中如何實現(xiàn)復(fù)制內(nèi)容到剪切板詳解
有些業(yè)務(wù)需求需要點(diǎn)擊按鈕復(fù)制鏈接,下面這篇文章主要給大家介紹了關(guān)于vue中如何實現(xiàn)復(fù)制內(nèi)容到剪切板的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10
在nuxt使用vueX代替storage的實現(xiàn)方案
這篇文章主要介紹了在nuxt使用vueX代替storage的實現(xiàn)方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
使用vue3+ts+setup獲取全局變量getCurrentInstance的方法實例
這篇文章主要給大家介紹了關(guān)于使用vue3+ts+setup獲取全局變量getCurrentInstance的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue3具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-08-08
axios發(fā)送post請求springMVC接收不到參數(shù)的解決方法
下面小編就為大家分享一篇axios發(fā)送post請求springMVC接收不到參數(shù)的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
vue中的attribute和property的具體使用及區(qū)別
本文主要介紹了vue中的attribute和property的具體使用及區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09

