前些天看vue2流程的時候,vnode這一塊先跳過了,現在來補
http-server執行了下example/hero文件夾
(function e(t,n,r){ // t: 各模塊映射到對象{1: [function(){}, 當前模塊所依賴模塊對象{"../../h.js":2}],2: [...],...}
// n:緩存模塊的對象
// r:入口模塊的數組
function s(o,u){
if(!n[o]){
if(!t[o]){
var a=typeof require=="function"&&require;
if(!u&&a)
return a(o,!0);
if(i)
return i(o,!0);
var f=new Error("Cannot find module '"+o+"'");
throw f.code="MODULE_NOT_FOUND",f
}
var l=n[o]={ // 定義了module,因爲瀏覽器中不支持Commonjs,沒有require也沒有module對象,所以要重新定義
exports:{}
};
t[o][0].call( // 參數1是this指向,參數2,3,4...是各模塊中的(require,module,exports)
l.exports,
function(e){ // require定義,例如require('../../snabbdom.js'),e就是'../../snabbdom.js'字符串,後續就是取模塊並存至n對象
var n=t[o][1][e];
return s(n?n:e)
},
l, // 定義了module, 參考var l的定義
l.exports, // 定義了exports, 取自module.exports
e,
t,
n,
r
)
}
return n[o].exports
}
var i=typeof require=="function"&&require;
// 依次調用入口模塊
for(var o=0;o<r.length;o++)
s(r[o]);
return s
})({
1:[
function(require,module,exports){
/* jshint esnext: true */
'use strict';
var snabbdom = require('../../snabbdom.js');
// 🤓開始了!
// 將arg[0]的modules綁至hook上,init返回的是🎄🎄🎄🎄function(oldVnode, vnode)
var patch = snabbdom.init([require('../../modules/class'), require('../../modules/hero'), require('../../modules/style'), require('../../modules/eventlisteners')]);
var h = require('../../h.js');
var vnode;
var data = {
selected: undefined,
movies: [
{ rank: 1, title: 'This is an', desc: 'Lorem ipsum...lus elit.' },
{ rank: 2, title: 'example of', desc: 'Consequuntur...wisi.' }
]
};
function render() {
vnode = patch(vnode, view(data));
}
var detailView = function detailView(movie) {
return h('div.page', { style: fadeInOutStyle }, [h('div.header',...)])
}
var overviewView = function overviewView(movies) {
return h('div.page', { style: fadeInOutStyle }, [h('div.header', [h('div.header-content.overview', {...})])
}
var view = function view(data) {
return h('div.page-container', [data.selected ? detailView(data.selected) : overviewView(data.movies)]);
};
// 省略code
window.addEventListener('DOMContentLoaded', function () {
var container = document.getElementById('container');
// 往下扒拉snabbdom.init的返回值function🎄🎄🎄🎄,記得回來
vnode = patch(container, view(data));
render();
});
},
{
"../../h.js":2,
"../../modules/class":4,
"../../modules/eventlisteners":5,
"../../modules/hero":6,
"../../modules/style":7,
"../../snabbdom.js":8
}
],
2:[
function(require,module,exports){
'use strict';
var VNode = require('./vnode');
// 省略code
},
{
"./is":3,
"./vnode":9
}
],
3:[
function(require,module,exports){
'use strict';
module.exports = {
array: Array.isArray,
primitive: function primitive(s) {
return typeof s === 'string' || typeof s === 'number';
}
};
},
{}
],
4:[
function(require,module,exports){
'use strict';
// 省略code
module.exports = { create: updateClass, update: updateClass };
},
{}
],
5:[
function(require,module,exports){
'use strict';
var is = require('../is');
// 省略code
module.exports = { create: updateEventListeners, update: updateEventListeners };
},
{
"../is":3
}
],
6:[
function(require,module,exports){
'use strict';
// 省略code
module.exports = { pre: pre, create: create, destroy: destroy, post: post };
},
{}
],
7:[
function(require,module,exports){
'use strict';
// 省略code
module.exports = { create: updateStyle, update: updateStyle, destroy: applyDestroyStyle, remove: applyRemoveStyle };
},
{}
],
8:[
function(require,module,exports){
// jshint newcap: false
/* global require, module, document, Element */
'use strict';
// 省略code
var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post'];
function init(modules) {
var i,
j,
cbs = {};
// 爲每個hook綁定相關module執行方法,存至cbs對象
for (i = 0; i < hooks.length; ++i) {
cbs[hooks[i]] = [];
for (j = 0; j < modules.length; ++j) {
if (modules[j][hooks[i]] !== undefined) cbs[hooks[i]].push(modules[j][hooks[i]]);
}
}
// 省略code
// 🎈🎈🎈🎈🎈🎈
function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
var i, hook;
if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) {
i(oldVnode, vnode);
}
if (isDef(i = oldVnode.data) && isDef(i = i.vnode)) oldVnode = i;
if (isDef(i = vnode.data) && isDef(i = i.vnode)) vnode = i;
// 將oldVnode的elm 賦值 給新的vnode.elm
var elm = vnode.elm = oldVnode.elm,
oldCh = oldVnode.children,
ch = vnode.children;
// 新舊vnode相等情況(一般不出現),結束
if (oldVnode === vnode) return;
// 執行update相關hook(內部cbs.update和外部i.update)
if (isDef(vnode.data)) {
for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode);
i = vnode.data.hook;
if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode);
}
// 新vnode無text 【elm、text、children】
if (isUndef(vnode.text)) {
// 檢查children
// 新舊都有children
if (isDef(oldCh) && isDef(ch)) {
if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue);
} else if (isDef(ch)) {
// 有新children,無舊children => 新增新children
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) {
// 有舊children,無新children => 移除舊children
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
}
} else if (oldVnode.text !== vnode.text) {
// text賦新值
elm.textContent = vnode.text;
}
// 執行vnode.data.hook.postpatch
if (isDef(hook) && isDef(i = hook.postpatch)) {
i(oldVnode, vnode);
}
}
return function (oldVnode, vnode) {
// 🎄🎄🎄🎄
var i;
var insertedVnodeQueue = [];
for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]();
// 如果snabbdom.init(oldVnode, vnode)第一個參數oldVnode是真實DOM而非vnode實例
if (oldVnode instanceof Element) {
if (oldVnode.parentElement !== null) {
createElm(vnode, insertedVnodeQueue);
oldVnode.parentElement.replaceChild(vnode.elm, oldVnode);
} else {
// 爲oldVnode創建對應vnode實例
oldVnode = emptyNodeAt(oldVnode);
// 執行上面定義的方法patchVnode🎈🎈🎈🎈🎈🎈
patchVnode(oldVnode, vnode, insertedVnodeQueue);
}
} else {
patchVnode(oldVnode, vnode, insertedVnodeQueue);
}
for (i = 0; i < insertedVnodeQueue.length; ++i) {
insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]);
}
for (i = 0; i < cbs.post.length; ++i) cbs.post[i]();
return vnode;
};
}
module.exports = { init: init };
},
{
"./is":3,
"./vnode":9
}
],
9:[
function(require,module,exports){
"use strict";
module.exports = function (sel, data, children, text, elm) {
var key = data === undefined ? undefined : data.key;
return { sel: sel, data: data, children: children,
text: text, elm: elm, key: key };
};
},
{}
]
},
{}, // 第二個參數是n,此處用一個空對象存儲
[1]
);
🎄🎄🎄🎄patch方法:
- 執行patchVnode並返回vnode對象
🎈🎈🎈🎈🎈🎈patchVnode(oldVnode, vnode, insertedVnodeQueue)方法:
- 從oldVnode中取出elm,並根據新vnode真實改變該dom,一路順帶執行了相關hook
window.addEventListener('DOMContentLoaded',..)中,我想不明白爲什麼還要再render()一遍
答:事實證明可以不調用,該綁定的都綁定了,新舊JSON.stringify(vnode)之後值一樣