初始化
Data,props,event监听
beforCreated,Created
挂载
执行编译,首次渲染、创建和追加过程
编译
编译模块分为三个阶段:
parse
、
optimize
、
generate
数据响应式
渲染函数执行时会触发
getter
进行依赖收集,将来数据变化时会触发
setter
进行更新
虚拟
dom
Vue 工作机制
// dom
<div
style
=
"color:red"
@click
=
"xx"
><a>
click me
</a>
</div>
// vdom
{
tag
:
'div'
,
props
:{
name
:
'
开课吧
'
,
style:{color:red},
onClick
:
xx
}
children
: [
{
tag
:
'a'
,
text
:
'click me'
}
]
}
更新视图
数据修改时监听器会执行更新,通过对比新旧
vdom
,得到最小修改,就是
patch
实现自己的
Vue
简化版架构图
//
创建
kvue.js// new KVue({// data: {
//
// }// })
class
KVue
{
constructor
(
options
) {
//
保存选项
this
.
$options
=
options
;
//
传入
data
选项
this
.
$data
=
options
.
data
;
//
响应化
this
.
observe
(
this
.
$data
);
}
observe(value) {
if (!value || typeof value !== "object") {
return
;}
//
遍历,执行数据响应式
Object
.
keys
(
value
).
forEach
(
key
=>
{
this.defineReactive(value, key, value[key]);
});
}
defineReactive
(
obj
,
key
,
val
) {
//
递归
this
.
observe
(
val
);
//
给
obj
定义属性
Object
.
defineProperty
(
obj
,
key
, {
get() {
return val;
},
set
(
newVal
) {
if
(
newVal
===
val
) {
return
;}
val
=
newVal
;
console
.
log
(
`${
key
}
属性更新了
`
);}
});}
}
//
创建
index.html
<
script src
=
"kvue.js"
><
/script>
<
script
>
const app = new KVue({
data: {
test: "I am test",
foo: {
bar
:
"bar"
}
}});
app.$data.test = "hello, kaikeba!";
app
.
$data
.
foo
.
bar
=
"oh my bar"
;
<
/script>
为
$data
做代理
, kvue.js
observe
(
value
) {
//...
Object
.
keys
(
value
).
forEach
(
key
=>
{
this
.
defineReactive
(
value
,
key
,
value
[
key
]);
//
代理
data
中的属性到
vue
根上
this
.
proxyData
(
key
);
});}
//
在
vue
根上定义属性代理
data
中的数据
proxyData
(
key
) {
Object.defineProperty(this, key, {
get() {
return this.$data[key];
},
set(newVal) {
this.$data[key] = newVal;
}});
}
<script>
app.test = "hello, kaikeba!";
app
.
foo
.
bar
=
"oh my bar"
;
</script>
编译
compile
class KVue {
constructor(options) {
// ...
//
新建一个
Watcher
观察者对象,这时候
Dep.target
会指向这个
Watcher
对象
new
Watcher
(
this
,
'test'
);
//
访问
get
函数,为了触发依赖收集
this
.
test
new Watcher(this,'foo.bar');
this.foo.bar
}
}
<body>
<div id="app">
<p>{{name}}</p>
<p k-text="name"></p>
<p>{{age}}</p>
<p>
{{doubleAge}}
</p>
<input
type
=
"text"
k-model
=
"name"
><button
@click
=
"changeName"
>
呵呵
</button><div
k-html
=
"html"
></div>
</div>
<script src='./compile.js'></script>
<script src='./kvue.js'></script>
<script>
const
kaikeba
=
new
KVue
({
el
:
'#app'
,
data
: {
name
:
"I am test."
,
age
:
12
,
html
:
'<button>
这是一个按钮
</button>'
},
created(){
console
.
log
(
'
开始啦
'
)
setTimeout
(()
=>
{
this
.
name
=
'
我是测试
'
},
1500
)
},
methods
:{
changeName
(){
this
.
name
=
'
哈喽,开课吧
'
this
.
age
=
1
}}
})
</script>
</body>