10分钟快速实现数据双向绑定

lxf2024-03-26 00:36:41

说在前面

双向绑定概念其实很简单,就是视图(View)的变化能实时让数据模型(Model)发生变化,而数据的变化也能实时更新到视图层。我们所说的单向数据绑定就是从数据到视图这一方向的关系。

分析

1、响应式数据

使用Object.defineProperty、Proxy对数据进行监听拦截。

//obj:必需。目标对象
//prop:必需。需定义或修改的属性的名字
//descriptor:必需。目标属性所拥有的特性
Object.defineProperty(obj, prop, descriptor)

10分钟快速实现数据双向绑定

在这里插入图片描述

2、VModel.js

(1)构造VModel

class  VModel {
 constructor(el,data) {
  this.el = document.querySelector(el);
  //存放数据对象
  this._data = data;
  //存放绑定数据的dom节点
  this.domPoll = {};
  
  this.init();
 }
}

(2)初始化数据对象

使用Object.defineProperty
initData () {
 const _this = this;
 this.data = {};
 for(let key in this._data){
  Object.defineProperty(this.data,key,{
   get(){
    console.log("获取数据",key,_this._data[key]);
    return _this._data[key];
   },
   set(newVal){
    console.log("设置数据",key,newVal);
    _this.domPoll[key].innerText = newVal;
    _this._data[key] = newVal;
   }
  });
 }
}
使用Proxy
initData () {
 const _this = this;
 this.data = {};
 this.data = new Proxy(this.data,{
  get(target,key){
   return Reflect.get(target,key);
  },
  set(target,key,value){
   // _this.domPoll[key].innerText = value;
   _this.domPoll[key].forEach(item => {
    item.innerText = value;
   })
   return Reflect.set(target,key,value);
  }
 })
}

(3)绑定dom节点

bindDom(el){
 const childNodes = el.childNodes;
 childNodes.forEach(item => {
  //nodeType为3时该dom节点为文本节点
  if(item.nodeType === 3){
   const _value = item.nodeValue;
  
   if(_value.trim().length){
    //匹配是否有两个花括号包裹的数据
    let  _isValid = /{{(.+?)}}/.test(_value);
    if(_isValid){
     const _key = _value.match(/{{(.+?)}}/)[1].trim();
     // this.domPoll[_key] = item.parentNode;
     //一个数据可以被多个dom节点绑定,所以应该用数组来进行保存
      //未定义时先初始化
      if(!this.domPoll[_key]) this.domPoll[_key] = [];
      this.domPoll[_key].push(item.parentNode);
     //替换绑定的值
     item.parentNode.innerText = this.data[_key] || undefined;
    }
   }
  }
  //递归遍历子节点
  item.childNodes && this.bindDom(item);
 })
}
 
12