当前位置 主页 > 本站WEB程序 > 安全 > IIS7网站监控 >

    js劫持,js数据双向绑定实现原理

    栏目:IIS7网站监控 时间:2020-12-15 14:21

         js模板引擎可以认为是一个基于MVC的结构,我们通过建立模板作为视图,然后通过引擎函数作为控制器实现数据和视图的绑定,从而实现实现数据在页面渲染,但是当数据模型发生变化时,视图不能自动更新;当视图数据发生变化时,模型数据不能实现更新,这个时候双向数据绑定应运而生。检测视图数据更新实现数据绑定的方法有很多种,目前主要分为三个流派,Angular使用的是脏检查,只在特定的事件下才会触发视图刷新,Vue使用的是Getter/Setter机制,而React则是通过 Virtual DOM 算法检查DOM的变动的刷新机制。
         创建标签:
    <div id="div1">
    <input type="text" v-model="name">
    <br> 姓名:{{name}}
    </div>
         创建一个输入框,使用v-model属性绑定变量name,注意这里只是模仿vue绑定的形式,代码中并没有引入任何vue依赖。完全靠原生js实现。
         单向绑定:
    let el = document.getElementById('app');
    let template = el.innerHTML;
    let _data = {
      name: '_BuzzLy'
    };
    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];
    });
    }
    到这我们又实现了一遍单向绑定,想要实现数据的双向绑定其实很简单,只需稍微修改我们的render函数。
    双向绑定:
    function render() {
    el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
    str = str.substring(2, str.length - 2);
    return _data[str];
    });
    // 找到所有input标签
     Array.from(el.getElementsByTagName('input'))
    // 过滤得到其中带有v-model属性的标签 
     .filter(ele => ele.getAttribute('v-model'))
     // 遍历这些input标签
    .forEach(input => {
     // 获取到v-model中绑定的key,从数据中找到key对应的value赋给input
     // 这一步就相当于数据=>视图的绑定
     let name = input.getAttribute('v-model');
     input.value = _data[name];
     // 为input绑定输入事件
    input.oninput = function () {
     // 当input修改时,将修改后的值赋给暴露在外的data对象
     // 这一步就实现了视图=>数据的绑定
     data[name] = this.value;
     };
     });
    }

    修改后的render函数通过过滤、遍历得到每一个拥有v-model属性的input标签,然后将数据绑定到视图上,并且视图修改也会触发数据的更新,这样就实现了数据的双向绑定。
    看似复杂的绑定机制其实就是通过我们熟悉的js一些基础的操作来实现的。
    完整代码:

    <!DOCTYPE html>
    <html lang="en" dir="ltr">
    <head>
    <meta charset="utf-8">
     <title></title>
    </head>
    <body>
    <div id="div1">
    <input type="text" v-model="name">
    <br> 姓名:{{name}}
    </div>
    </body>
    <script>
    let el = document.getElementById('div1');
    let template = el.innerHTML;
    let _data = {
    name: '_BuzzLy'
     };
    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];
     });
     Array.from(el.getElementsByTagName('input'))
     .filter(ele => ele.getAttribute('v-model'))
     .forEach(input => {
     let name = input.getAttribute('v-model');
     input.value = _data[name];
     input.oninput = function () {
    data[name] = this.value;
    };
     });
     }
    </script>
    </html>