-
找到build/config.js
-
找到 genConfig 方法,添加 sourceMap:true
...
function genConfig (name) {
const opts = builds[name]
const config = {
input: opts.entry,
external: opts.external,
sourceMap: true,
...
- 修改example里面引用, 比如 example/commits/index.html
<script src="../../dist/vue.js"></script>
-
执行 npm run dev
-
在需要打断点地方加入 debugger即可
核心 Object.defineProperty()
实现分为3部分
-
Observer(监听器)
: 递归的监听所有的对象属性,如果属性值有变化,触发其watcher
-
Watcher(观察者)
: 当监听属性值有变化,则执行相应回调函数,更新vue模板 -
Dep(订阅者)
: 负责连接observer
和watcher
,一个observe
对应一个dep
,内部维护一个数组,用来保存该observer
和相关watcher
源码分别在
observer: core/observer/index.js
watcher:core/observer/watcher.js
实现也分为3部分
parse
:parse会用正则方式将template
模板里进行字符串解析,得到指令,class,style等数据,形成AST
.
parse-text
: tokens
数组来存放解析结果,通过 defaultTagRE
来循环匹配该文本,如果是普通文本直接 push 到 tokens 数组中去,如果是表达式({{item}})
,则转化成“_s(${exp})
”的形式
比如
<div>hello,{{name}}.</div>
得到token
为
tokens = ['hello,', _s(name), '.'];
最终通过 join
返回表达式
最终通过 join 返回表达式
optimize
:优化代码. 将一些静态节点标记,在后面的patch
环节直接跳过,达到优化目的generate
:将优化后的AST
转化成render function
.
源码入口:
<div :class="c" class="demo" v-if="isShow"><span v-for="item in sz">{{item}}</span><span>test</span></div>
通过parseHTML方法解析 标签 class style 指令 text 为 AST为:
{
type:1,
tag:"div",
parent:null,
attrsList:[
{
name:":class",
value:"c"
},{
name:"class",
value:"demo"
}
],
attrsMap:{
:class:"c",
class:"demo",
v-if:"isShow"
},
if:"isShow",
ifProcessed:true,
ifConditions:[
{
exp:"isShow",
...
}
],
children:[
{
type:1,
tag:"span",
parent:...,
attrsList:[],
attrsMap:{
v-for:"item in sz"
},
alias:"item",
for:"sz",
forProcessed:true,
children:[
{
type:2,
expression:"_s(item)",
text:"{{item}}"
}
],
...
},
{
type:1,
tag:"span",
parent:...,
attrsList:[],
attrsMap:{},
children:[
{
type:3,
text:"test"
}
]
...
}
]
}
通过optimize 优化AST,将一些静态节点标记,optimize后AST为
{
type:1,
tag:"div",
parent:null,
static:false,
staticRoot:false,
attrsList:[
{
name:":class",
value:"c"
},{
name:"class",
value:"demo"
}
],
attrsMap:{
:class:"c",
class:"demo",
v-if:"isShow"
},
if:"isShow",
ifProcessed:true,
ifConditions:[
{
exp:"isShow",
...
}
],
children:[
{
type:1,
tag:"span",
static:false,
parent:...,
attrsList:[],
attrsMap:{
v-for:"item in sz"
},
alias:"item",
for:"sz",
forProcessed:true,
children:[
{
type:2,
static:false,
expression:"_s(item)",
text:"{{item}}"
}
],
...
},
{
type:1,
tag:"span",
parent:...,
attrsList:[],
attrsMap:{},
children:[
{
type:3,
static:true,
text:"test"
}
]
...
}
]
}
通过generate 转化为render function
with(this){return (isShow)?_c('div,'{
staticClass: c,
class: demo,
},_l((sz),function(item){return _c('span,'{
staticClass: undefined,
class: undefined,
},_v(_s(item)))}),_c('span,'{
staticClass: undefined,
class: undefined,
},_v(undefined))): _e()}
_c
:createElement创建节点
_l
:循环表达式
_v
:创建文本节点
_s
:值转为字符串
_e
: 空节点
vue.js VDom 这块基于 snabbdom 实现,并做了优化