mvvc

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <div id='app'>
  <p>
    My name is {{firstName + ' ' + lastName}}, I am {{age + ss}} years old.
  </p>
</div>
<script type="text/javascript">
const observe = (data) => {
    if (!data || typeof data !== 'object') {
        return;
    }
    // 取出所有属性遍历,监听所有属性
    for(let key in data) {
        defineReactive(data, key, data[key]);
    }
};


//利用Object.defineProperty监听数据变化
//一个defineReactive对应对象一个属性
const defineReactive = (data, key, val) => {
  //一个dep管理一个对象的属性
  //对象属性跟节点是一对多的关系
  var dep = new Dep();
  Object.defineProperty(data, key, {
    get: function() {
      if(target) {
        dep.addNode(target)
      }
      return val
    },
    set: function(newVal) {
      val = newVal;
      dep.notify();
    }
  });
}




//Dep是对象属性对节点的管理器
function Dep() {
  this.nodes = []
}


Dep.prototype = {
  addNode: function(node) {
    this.nodes.push(node)
  },
  notify: function() {
    //异步更新节点
    setTimeout(() => {
      this.nodes.map((node) => {
        node.update()
      })
    })
  }
}


//观察者 观察者观察者 观察者观察者 观察者观察者 观察者观察者 观察者观察者 观察者观察者 观察者
function Watcher(data, node) {
  //target的作用是只在new Watcher的时候建立关系
  //不然每次get都将节点压入dep
  target = this;
  //保存节点
  this.node = node;
  this.data = data;
  //保存text节点的值
  this.nodeValue = node.nodeValue;
  //将对象的每一个属性都访问一遍,建立对象属性跟节点的关系
  for(let key in data) {
    data[key]
  }
  target = null;
}
// 模板解析模板解析模板解析模板解析模板解析
Watcher.prototype = {
  //模版解析
  execute: function(exp) {
    return new Function (...Object.keys(this.data), `return ${exp}`) (...Object.values(this.data))
  },
  // new Function里的函数还是至关重要的,但是不知道是什么东西
  //更新view.此处与依赖收集的notify中的update()相关联。
  update: function() {
    //匹配到{{}}
    const newValue = this.nodeValue.replace(/{{(.*?)}}/g, (exp) => {
      //去除{{,}}
      exp = exp.replace(/{{|}}/g, '')
      return this.execute(exp)






      
    })
    this.node.nodeValue = newValue;
  }
}


//监听所有text节点
const watchTextNode = (el, data) => {
  [...el.childNodes].forEach(child => { 
    // 递归直至都是text.做相反的逻辑处理,很聪明。
    if(!(child instanceof Text)) {
      watchTextNode(child, data)
    }
    //这里监听了所有的text节点,应该做一层判断,只监听包含对象属性的文本节点(可优化)
    else new Watcher(data, child)
  })
}


const bindViewToData = (root, data) => {
  //监听数据
  observe(data);
  //数据变化则更新对应的节点
  watchTextNode(root, data);
  //先触发数据变化,更新view
  for(let key in data) {
    data[key] = data[key]
    return
  }
}


let appData = {
  firstName: 'Lucy',
  lastName: 'Green',
  age: 12222,
  ss: 22
}


bindViewToData(document.getElementById('app'), appData)
</script>
  </body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值