美文网首页
js实现数据单向绑定

js实现数据单向绑定

作者: _BuzzLy | 来源:发表于2020-04-27 19:00 被阅读0次

    如果你在学习一种前端框架,如vue、angular等,那么你一定不会对数据的单向绑定陌生。

    何为数据的单向绑定?

    传统开发模式下,如使用jQuery开发,我们想将一个变量显示到html中,首先要定义一个变量name,然后通过jq代码操作dom将变量放到HTML中,如果name发生修改,还要再次通过jq代码操作dom将新的变量值放到HTML中。这就是传统的MVC框架,其中的Model和View是我们通过代码联系在一起的。
    在MVVM框架中,我们不再过多的关注数据与视图间的操作,而是使用一种新的机制,数据的单/双向绑定。
    我在刚接触angular的时候感觉这个绑定的机制简直不要再神奇,但是当慢慢深入学习后发现其实原理非常简单,通过简短的js代码就可以实现一个简单的数据单向绑定。

    Proxy对象

    Proxy可以当做在目标对象之前架设一层拦截,或者说是代理。任何对该对象的访问都要先经过这个代理。那么也就是说我们可以通过Proxy对象拦截到外界对一个对象的访问。
    ES6中将Proxy标准化了,提供了Proxy构造函数,用来生成Proxy实例。下面就是官方的定义:

    let p = new Proxy(target, handler);
    
    • target:用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
    • handler:一个对象,其属性是当执行一个操作时定义代理的行为的函数。
      再看一个栗子:
    let p = new Proxy({}, {
        get: function(target, name){
            return name in target ? target[name] : 37;
        }
    });
    p.a = 1;
    p.b = undefined;
    console.log(p.a, p.b);    // 1, undefined
    console.log('c' in p, p.c);    // false, 37
    

    栗子中通过Proxy对象拦截了p对象的访问,当对象中不存在属性名时返回37,如果有就返回属性值。
    到这已经了解了Proxy对象的工作方式,我们就要用Proxy来做点事了。

    单向绑定

    首先
    如果你接触过一些mvvm框架,那么一定会对下面的代码非常熟悉

    <div id="app">
      姓名:{{name}}
      <br> 年龄:{{age}}
    </div>
    

    “{{}}”叫做插值表达式,vue、angular中都是使用这种方式进行数据的单向绑定。在这我们也使用这种格式绑定数据。
    然后

    let el = document.getElementById('app');
    let template = el.innerHTML;
    

    上面两步,首先获取到根元素,然后将根元素下的html保存下来。这里为什么要保存原始的html呢?
    因为接下来的数据变化会重新编译标签,既然要重新编译,那么就要保留最初的状态,否则编译一次后,第二次就无法正常编译了。
    再然后

    let _data = {
      name: '_BuzzLy',
      age: 25
    };
    

    定义一个_data对象,这个对象是给我们接下来创建的Proxy对象用的,并不是暴露出去供访问的。
    接下来

    let data = new Proxy(_data, {
      // 试图设置数据时调用
      // 参数:_data,属性名,值
      set(obj, name, value) {
        obj[name] = value;
    
        // 数据变了
        console.log(`数据变了,设置 ${name}=>${value}`);
        // 数据改变后重新渲染
        render();
      },
      // 试图获取数据的时调用,默认要什么就返回什么
      // get() {}
    });
    

    这步我们创建一个data,这个data就是对外的,是一个Proxy对象。
    Proxy是原生的对象,可以将真正的数据对象隐藏,我们修改的是代理对象。
    相当于我们想修改_data一定要经过一步代理,告诉代理我们要修改的对象及修改的值,然后代理去帮我们操作。
    在修改完成后调用render函数去重新渲染视图。
    最后
    上面已经完成了最重要的部分,当一个数据发生改变后调用了render函数,这个函数就是将改变后的数据重新渲染到视图中去。

    function render() {
        el.innerHTML = template.replace(/\{\{w+\}\}/g, str => {
            console.log(str); // 匹配出来的 {{name}}  {{age}} 
            // 截取字符串,得到属性key值
            str = str.substring(2, str.length - 2);
            // 从真实数据中拿到对应属性的值返回,替换{{key}}
            return _data[str];
        })
    }
    

    这里的实现很简单,就是匹配到html中{{key}},然后拿到key,再去_data中找到值即可。
    注意这里的template,这就是我们在上面为什么要保存一份原始的html原因。
    现在你可以去尝试手动修改data的值看看效果了。

    data.name = 'halo wode';
    data.age = 18;
    

    到这一个最简单的数据单向绑定就实现了。


    完整代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title></title>
    </head>
    <body>
      <div id="app">
        姓名:{{name}}
        <br> 年龄:{{age}}
      </div>
    </body>
    <script>
      let el = document.getElementById('app');
      let template = el.innerHTML;
      let _data = {
        name: '_BuzzLy',
        age: 25
      };
    
      let data = new Proxy(_data, {
        set(obj, name, value) {
          obj[name] = value;
          render();
        }
      });
      
      render();
    
      function render() {
        el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
          str = str.substring(2, str.length - 2);
          return _data[str];
        });
      }
    </script>
    </html>
    

    相关文章

      网友评论

          本文标题:js实现数据单向绑定

          本文链接:https://www.haomeiwen.com/subject/vbvuwhtx.html