Vue 源码学习
资料
熟悉设计模式
AST 抽象语法树
htmlParse 解析器
wue 仿Vue实现
Vue.js 源码学习笔记
Virtual DOM patching algorithm based on Snabbdom
以下是个人学习vue 源码的先后学习过程:(以下面顺序学习会轻松很多,循序渐进)
-
学习
正则表达式
-
学习js 设计模式,重点
观察者模式
50行代码的MVVM,感受闭包的艺术 -
了解
AST 抽象语法树
的概念,并通过博文开头的资料 htmlParse解析器 中分析parse
原理 -
参看githut 上的开源
仿 Vue 实现项目
wue 仿Vue实现、Vue 源码注释版 -
查看调试vue.js 2.1.3 版本单文件脚本 https://cdn.bootcss.com/vue/2.1.3/vue.js
步骤5 举例:单步调试如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 版本:vue 2.1.3 -->
<script type="text/javascript" src="./vue.js"></script>
</head>
<body>
<div id="app">
<div><span v-text="reverse"></span></div>
<div><span v-text="tip"></span></div>
<div><bar :age="info.age"></bar></div>
</div>
<script>
let bar = {
name: 'Bar',
template: '<div><span>name: {{name}}</span><br/><span>age: {{age}}</span></div>',
props: [ 'age' ],
created() {
console.log('child created.')
},
data() {
return {
name: 11
}
}
}
var app = new Vue({
el: "#app",
components: {
bar: bar
},
created() {
console.log('created.')
},
data() {
return {
message: "hello.",
info: {
age: 12
}
}
},
computed: {
reverse() {
return this.message.split("").reverse().join("")
},
tip() {
return `${this.message} world.`
}
}
})
setTimeout(()=>{
app.info.age = 23
}, 400)
</script>
</body>
</html>
编译过程中会生成render code
如下:
_h(
'div',
{attrs:{"id":"app"}},
[
_h(
'div',
[
_h('span',{domProps:{"textContent":_s(reverse)}})]),
" ",
_h(
'div',
[_h('span',{domProps:{"textContent":_s(tip)}})]
),
" ",
_h('div',[_h('bar',{attrs:{"age":info.age}})]
)
]
)
其中_h
和 _s
方法分别对应:
// shorthands used in render functions
Vue.prototype._h = createElement;
// toString for mustaches
Vue.prototype._s = _toString;
function createElement (
tag,
data,
children
) {
if (data && (Array.isArray(data) || typeof data !== 'object')) {
children = data;
data = undefined;
}
// make sure to use real instance instead of proxy as context
return _createElement(this._self, tag, data, children)
}
function _createElement (
context,
tag,
data,
children
) {
if (data && data.__ob__) {
"development" !== 'production' && warn(
"Avoid using observed data object as vnode data: " + (JSON.stringify(data)) + "\n" +
'Always create fresh vnode data objects in each render!',
context
);
return
}
if (!tag) {
// in case of component :is set to falsy value
return emptyVNode()
}
// support single function children as default scoped slot
if (Array.isArray(children) &&
typeof children[0] === 'function') {
data = data || {};
data.scopedSlots = { default: children[0] };
children.length = 0;
}
if (typeof tag === 'string') {
var Ctor;
var ns = config.getTagNamespace(tag);
if (config.isReservedTag(tag)) {
// platform built-in elements
return new VNode(
tag, data, normalizeChildren(children, ns),
undefined, undefined, ns, context
)
} else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
return createComponent(Ctor, data, context, children, tag)
} else {
// unknown or unlisted namespaced elements
// check at runtime because it may get assigned a namespace when its
// parent normalizes children
var childNs = tag === 'foreignObject' ? 'xhtml' : ns;
return new VNode(
tag, data, normalizeChildren(children, childNs),
undefined, undefined, ns, context
)
}
} else {
// direct component options / constructor
return createComponent(tag, data, context, children)
}
}
/**
* Convert a value to a string that is actually rendered.
*/
function _toString (val) {
return val == null
? ''
: typeof val === 'object'
? JSON.stringify(val, null, 2)
: String(val)
}
(未完,待续)