vue2源码简单实现stage3
Posted 自在三水一方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2源码简单实现stage3相关的知识,希望对你有一定的参考价值。
在上一节中我们已经将代码整理了一下,这一节我们要做的是比较新旧dom,然后通过diff算法判断虚拟dom时候有变化,是否需要刷新视图。为了让代码更加清晰,我们这边还是做了简化,假设父节点下只有一个元素。并且手动调用更新方法,暂时不做数据双向绑定更新视图。
理解patch函数
不管是第一次挂载到视图还是后续的手动更新,我们都要触发构建新的dom,这时候我们可以将这个逻辑写到update的函数里面,但是 要根据不同的情况触发不同的更新逻辑,所以用到了patch函数
;(function ()
function vnode (tag, data, children, text, elm)
this.tag = tag;
this.data = data;
this.children = children;
this.text = text;
this.elm = elm;
function normalizeChildren (children)
if (typeof children === \'string\')
return [createTextVNode(children)]
return children
function createTextVNode (val)
return new vnode(undefined, undefined, undefined, String(val))
function createElement (tag, data, children)
return new vnode(tag, data, normalizeChildren(children), undefined, undefined);
function createElm (vnode)
var tag = vnode.tag;
var data = vnode.data;
var children = vnode.children;
if (tag !== undefined)
vnode.elm = document.createElement(tag);
if (data.attrs !== undefined)
var attrs = data.attrs;
for (var key in attrs)
vnode.elm.setAttribute(key, attrs[key])
if (children)
createChildren(vnode, children)
else
vnode.elm = document.createTextNode(vnode.text);
return vnode.elm;
function createChildren (vnode, children)
for (var i = 0; i < children.length; ++i)
vnode.elm.appendChild(createElm(children[i]));
function sameVnode (vnode1, vnode2)
return vnode1.tag === vnode2.tag
function emptyNodeAt (elm)
return new vnode(elm.tagName.toLowerCase(), , [], undefined, elm)
function patchVnode (oldVnode, vnode)
var elm = vnode.elm = oldVnode.elm;
var oldCh = oldVnode.children;
var ch = vnode.children;
if (!vnode.text)
if (oldCh && ch)
updateChildren(oldCh, ch);
else if (oldVnode.text !== vnode.text)
elm.textContent = vnode.text;
function updateChildren (oldCh, newCh)
// 假设每一个元素下面只有一个子元素
if (sameVnode(oldCh[0], newCh[0]))
patchVnode(oldCh[0], newCh[0])
else
patch(oldCh[0], newCh[0])
function patch (oldVnode, vnode)
var isRealElement = oldVnode.nodeType !== undefined; // virtual node has no `nodeType` property
if (!isRealElement && sameVnode(oldVnode, vnode))
patchVnode(oldVnode, vnode);
else
if (isRealElement)
oldVnode = emptyNodeAt(oldVnode);
var elm = oldVnode.elm;
var parent = elm.parentNode;
createElm(vnode);
parent.insertBefore(vnode.elm, elm);
parent.removeChild(elm);
return vnode.elm
function initData (vm)
var data = vm.$data = vm.$options.data;
var keys = Object.keys(data);
var i = keys.length
// 代理之后可以直接使用this.key 而不是this.data.key
while (i--)
proxy(vm, keys[i])
function proxy (vm, key)
Object.defineProperty(vm, key,
configurable: true,
enumerable: true,
get: function ()
return vm.$data[key]
,
set: function (val)
vm.$data[key] = val
)
function Vue (options)
var vm = this;
vm.$options = options;
initData(vm);
vm.mount(document.querySelector(options.el))
Vue.prototype.mount = function (el)
var vm = this;
vm.$el = el;
vm.update(vm.render())
Vue.prototype.update = function (vnode)
var vm = this;
var prevVnode = vm._vnode;
vm._vnode = vnode;
if (!prevVnode)
vm.$el = vm.patch(vm.$el, vnode);
else
vm.$el = vm.patch(prevVnode, vnode);
Vue.prototype.patch = patch;
Vue.prototype.render = function ()
var vm = this;
return vm.$options.render.call(vm)
var vm = new Vue(
el: \'#app\',
data:
message: \'Hello world\',
isShow: true
,
render ()
return createElement(
\'div\',
attrs:
\'class\': \'wrapper\'
,
[
this.isShow
? createElement(
\'p\',
attrs:
\'class\': \'inner\'
,
this.message
)
: createElement(
\'h1\',
attrs:
\'class\': \'inner\'
,
\'Hello world\'
)
]
)
)
// test
setTimeout(function ()
vm.message = \'Hello\';
vm.update(vm.render())
, 1000)
setTimeout(function ()
vm.isShow = false;
vm.update(vm.render())
, 2000)
)();
diff算法简介
diff算法一直是比较难的,想深入了解可以参考
[组件更新]https://ustbhuangyi.github.io/vue-analysis/v2/reactive/component-update.html#新旧节点相同
以上是关于vue2源码简单实现stage3的主要内容,如果未能解决你的问题,请参考以下文章