JS 实现一个简单的双向数据绑定

一、通过 Object.defineProperty 来实现
  • 在html里面增加如下两个节点:
<input type="text" id="demo">
<div id="test"></div>
  • 在scritpt里面写如下脚本:
<script>
    const obj={}
    //用于设置obj的属性值为name
    Object.defineProperty(obj,'name',{
        //获取到设置set的值
        //读取到obj.name属性值的更改
        set:function(value){
            document.getElementById('test').innerHTML=value
        }
    })
    console.log(obj.name)
    //获取到文本框中的值并赋给obj.name
    document.getElementById('demo').oninput=function (e) {
        obj.name=e.target.value
    }
</script>

以上就是一个简单的双向数据绑定。

二、用Proxy实现

简单的Proxy双向绑定原理,其实我个人的理解就是通过拦截对象在读/写时的操作就能实现双向绑定了:

  class Observable {
    constructor(data) {
      this.data = data;
      this.proxy = new Proxy(this.data, {
        get: (target, property) => {
          console.log(`获取属性: ${property}`);
          return target[property];
        },
        set: (target, property, value) => {
          console.log(`设置属性: ${property}`);
          target[property] = value;
          // 这里可以添加更新视图的逻辑
        }
      });
    }

    getData() {
      return this.proxy;
    }
  }

  // 使用示例
  const observable = new Observable({ name: '张三', age: 30 });
  const data = observable.getData();

  data.name; // 控制台打印: 获取属性(读属性): name
  data.age = 31; // 控制台打印: 设置属性(写属性): age

proxy用于实现数据劫持,从而实现双向数据绑定。可以通过监听proxy对象的变化,将变化反应到页面上,实现的效果是:当input输入框发生变化,能将变动内容实时的更新到页面上,下面是简单的实现:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
  <title>简单的proxy双向数据绑定</title>
  <style>

  </style>
</head>
<body>
<div class="input-card">
  <input type="text" id="name">
  <p id="showInput">{{proxyObj.name}}</p>
</div>

<script>

  const regexp = /^{{.*}}$/
  const show = document.getElementById('showInput')

  let proxyObj = new Proxy({ name: '' }, {
    get(target, propKey, receiver) {
      return Reflect.get(target, propKey, receiver);
    },
    set(target, propKey, value, receiver) {
      // 此处进行视图更新
      show.innerHTML = value;
      return Reflect.set(target, propKey, value, receiver);
    }
  })

  window.onload = function() {
    if (regexp.test(show.innerHTML)) {
      show.innerHTML = '';
    }
    const n = document.getElementById('name')
    n.addEventListener('input', (event) => {
      // 进行此步操作会触发proxy中的set方法,是在进行name属性的写入操作
      proxyObj.name = event.target.value;
    })
  }

</script>
</body>
</html>

完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>双向数据绑定.v1</title>
</head>

<body>

显示title:<h1 id="h1title">{{data.title}}</h1>
输入title:<input id="input" type="text" v-model="data.title" />

</body>
<script>

  var regexp = /^{{.*}}$/
  const h1Mapping = {};

  let data = new Proxy({ "title": "" }, {
    get(target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      return result;
    },
    set(target, key, val, receiver) {
      const result = Reflect.set(target, key, val, receiver)
      updateDataView();
      return result;
    },
  })

  window.onload = () => {
    let hns = document.getElementById("h1title");
    if (regexp.test(hns.innerHTML)) {
      let val = hns.innerHTML;
      // 置空
      hns.innerHTML = "";
      //put 对应关系
      const a = val.replace("{{", "").replace("}}", "");
      h1Mapping[a] = hns;
    }

    let ipt = document.getElementById("input");
    ipt.addEventListener('input', function () {
      let val = ipt.getAttribute("v-model");
      const b = val += "=" + "'" + this.value + "'";
      eval(b);
      updateDataView();
    })
  }

  function updateDataView() {
    for (const key in h1Mapping) {
      if (eval(key)!= undefined) {
        h1Mapping[key].innerHTML = eval(key);
      }
    }
  }


</script>

</html>

vue3弃用了Object.defineProperty,采用Proxy和Reflect来实现双向数据绑定,原因有以下几点:

1.Proxy可以代理整个对象,defineProperty只代理对象上的某个属性。

2.Proxy对代理对象的监听更加丰富。

3.Proxy代理对象会生成新的对象,不会修改被代理对象本身。

4.Proxy不兼容IE浏览器。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值