1.kvue.js
class KVue{
constructor(options){
this.$options=options
this.$data = options.data
observe(options.data)
proxy(this,'$data')
//创建编译器
new Compile(options.el,this)
}
}
class Observe{
constructor(value){
this.value=value
//判断类型
if(typeof value==='object'){
this.walk(value)
}
}
//对象数据响应化
walk(obj){
Object.keys(obj).forEach(key=>{
defineReactive(obj,key,obj[key])
})
}
}
function defineReactive(obj,key,value){
observe(value)
//创建一个Dep和当前的key一一对应
const dep = new Dep()
Object.defineProperty(obj,key,{
get(){
//依赖收集
Dep.target&&dep.addDep(Dep.target)
return value
},
set(newVal){
if(newVal!==value){
//如果newVal为obj,需要进行响应式处理
// console.log('set['+key+'->'+newVal+']')
observe(newVal)
value=newVal
dep.notify()
}
}
})
}
function observe(obj){
if(typeof obj!=='object'||obj===null){
return
}
//创建Observe实例
new Observe(obj)
}
//代理函数,方便用户访问$data中的数据
function proxy(vm){
Object.keys(vm.$data).forEach(key=>{
Object.defineProperty(vm,key,{
get(){
return vm.$data[key]
},
set(newVal){
vm.$data[key] =newVal
}
})
})
}
2.compile.js
//递归遍历dom树
// 判断节点类型,如果是文本,判断是否为插值绑定,若果是元素,则遍历其属性判断是否是指令或事件,递归子元素
class Compile{
//el为宿主元素
//vm是KVue实例
constructor(el,vm){
this.$vm = vm
this.$el=document.querySelector(el)
if(this.$el){
this.compile(this.$el)
}
}
compile(el){
//遍历el树
const childNodes=el.childNodes;
Array.from(childNodes).forEach(node=>{
//判断类型
if(this.isElement(node)){
this.compileElement(node)
}else if(this.isInter(node)){ //插值绑定
this.compileText(node)
}
//递归子节点
if(node.childNodes&&node.childNodes.length>0){
this.compile(node)
}
})
}
isElement(node){
return node.nodeType===1
}
isInter(node){
//首先是文本标签,其次内容是{{text}}
return node.nodeType===3&&/\{\{(.*)\}\}/.test(node.textContent)
}
compileText(node){
// node.textContent=this.$vm[RegExp.$1]
this.update(node,RegExp.$1,'text')
}
compileElement(node){
//遍历当前节点的属性列表
const nodeAttrs = node.attributes
Array.from(nodeAttrs).forEach(attr=>{
//规定:指令以k-name定义
const attrName =attr.name
const exp = attr.value
if(this.isDirective(attrName)){
const dir = attrName.substring(2)
//执行指令
this[dir]&&this[dir](node,exp)
}
})
}
isDirective(attr){
return attr.indexOf('k-')===0
}
text(node,exp){
// node.textContent = this.$vm[exp]
this.update(node,exp,'text')
}
html(node,exp){
this.update(node,exp,'html')
// node.innerHTML = this.$vm[exp]
}
update(node,exp,dir){
//初始化操作
//指令对应的更新函数
const fn = this[dir+'Update']
fn&&fn(node,this.$vm[exp])
//更新处理可以更新对应的dom元素
new Watcher(this.$vm,exp,function(val){
fn&&fn(node,val)
})
}
textUpdate(node,value){
node.textContent=value
}
htmlUpdate(node,value){
node.innerHTML = value
}
}
3.watcher.js
//观察者:保存根性函数
// const watchers = []
class Watcher{
constructor(vm,key,updatefn){
this.vm=vm
this.key=key
this.updatefn = updatefn
// watchers.push(this)
//Dep.target静态属性上设置为当前watcher实例
Dep.target=this
this.vm[this.key] //读取触发了getter
Dep.target =null //收集完防控
}
update(){
this.updatefn.call(this.vm,this.vm[this.key])
}
}
4.dep.js
//管理依赖,管理某个key相关的所有watcher实例
class Dep{
constructor(){
this.deps=[]
}
addDep(dep){
this.deps.push(dep)
}
notify(){
this.deps.forEach(dep=>dep.update())
}
}