vue的核心目的 减少DOM的渲染次数
编译
编译分为三个阶段
1、parse
使用正则解析template中的vue指令(v-xxx)变量等等 形式语法树AST
2、optimize
标记一些静态节点,用作后面的性能优化,在diff的适合直接略过
3、generate
把第一部分的AST转化为渲染函数 render function
例如:
{
tag: 'div',
props:{
name: '开始',
style:{color: red},
onClick: xxx
},
children:[
{
tag: 'a',
text: 'click me'
}
]
}
<div name='开始' style='color: red' @click='xxx'>
<a>
click me
</a>
</div>
双向数据绑定简单原理实现
<body>
<!-- 响应式数据 -->
<div id="app">
<p id="name"></p>
</div>
<script>
var obj = {
}
Object.defineProperty(obj, 'name',{
get:function(){
return document.querySelector('#name').innerHTML;
},
set:function(val){
document.querySelector('#name').innerHTML=val
}
})
obj.name='这是数据渲染'
</script>
</body>
简易实现数据更新提示
kvue.js
class Kvue {
constructor(options){
this.$optons=options
// 数据响应化
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)
const dep = new Dep()
Object.defineProperty(obj,key,{
get(){
return val
},
set(newVal){
if(newVal === val){
return;
}
val = newVal;
//console.log('属性发生变化啦')
dep.notify();
}
})
}
}
//Dep: 用来管理Watcher
class Dep {
constructor(){
//这是存放的是诺干的依赖(watcher)
this.deps=[] ;
}
//添加依赖
addDep(dep){
this.deps.push(dep)
}
//通知依赖更新
notify(){
this.deps.forEach(dep => dep.update() )
}
}
//Watcher
class Watcher {
constructor (){
//将当前的watcher实例指定到Dep静态属性target
Dep.target = this;
}
update(){
console.log('数据更新了')
}
}
<body>
<script src="./kvue.js"></script>
<script>
const app=new Kvue({
data:{
test: 'I am is cui',
foo: {
msg: 'this is mi'
}
}
})
app.$data.test= '这是数据响应化'
app.$data.foo.msg= '这是响应化数据'
</script>
</body>
数据劫持的步骤:利用Object.defineProperty属性,每一个属性都定义了 get和set方法,当这些数据发生改变时,通知其所在的视图发生相应的改变