zoukankan      html  css  js  c++  java
  • 双向绑定数据的实现(new Proxy 版本)

    之前有用 Object.defineProperty 实现了一个双向绑定,过于繁琐,这是 基于 Proxy 实现了一版,也优化了模版渲染的部分,代码更简洁。

    调用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>myvue</title>
        <script src="myvue.js"></script>
    </head>
    <body>
        <div id="app">
            姓名:{{name}}
            <div>
                年龄:{{age}}
                <p>
                    身高:{{height}}
                </p>
                <p>
                    体重:{{weight}}
                </p>
            </div> 
            <div>
                双向数据绑定:<input type="text" v-model="inputData">
                {{inputData}}
            </div>
        </div>
        <script>
            let vm = new Myvue({
                el: '#app',
                data: {
                    name: 'lili',
                    age: 18,
                    height: '170cm',
                    weight: '65kg',
                    inputData: '双向数据绑定'
                }
            }) 
        </script>
    </body>
    </html>
    

    myvue.js 核心实现

    // 基础知识点扫盲
    // - 自定义事件,和调用自定义事件 new CustomEvent   this.dispathEvent
    // - 监听拦截数据方法 Proxy, new Proxy(data, set(target, prop, newValue){})
    // - EventTarget  是一个 DOM 接口,由可以接收事件
    
    class Myvue extends EventTarget{
        constructor(option) {
            super();
            this.option = option
            this._data = this.option.data;
            this.el = document.querySelector(option.el);
            this.observe(this._data); // 监听观察数据
            this.complieNode(this.el) // 编译节点,渲染数据
        }
    
        observe(data) {
            let _this = this;
            // 每次访问、设置等 data 的时候,都会经过 proxy 代理过后的对象,便于拦截,监听等操作
            this._data = new Proxy(data, {
                set(target, prop, newValue){
                    // 监听到新值变化
                    // 如何通知视图修改数据?
                    console.log(newValue);
                    // 自定义事件
                    let event = new CustomEvent(prop, {
                        detail: newValue
                    });
                    _this.dispatchEvent(event);
                    return Reflect.set(...arguments)  // 设置值
                }
            })
    
        }
        complieNode(el) {
            let child = el.childNodes;
            // 类数组转成数组
            [...child].forEach(element => {
                if(element.nodeType === 3) {
                    // console.log('文本节点')
                    let textContent = element.textContent;
                    // console.log(textContent) {{name}} {{age}}
                    let reg = /{{s*([^s{}]+)s*}}/g;
                    if(reg.test(textContent)) {
                        let $1 = RegExp.$1;
                        // console.log($1); name age
                        if(this._data[$1]) {
                            element.textContent = textContent.replace(reg, this._data[$1]);
                            // 绑定自定义事件,自定义事件名就是 双向数据绑定的值 name age inputData
                            this.addEventListener($1, e => {
                                console.log(e)
                                element.textContent = textContent.replace(reg, e.detail);
                            })
                        }
                    }
                } else if(element.nodeType===1){
                    // console.log('元素节点');
                    let attr = element.attributes;
                    if(attr.hasOwnProperty('v-model')) {
                        let keyName = attr['v-model'].nodeValue; // inputData
                        element.value = this._data[keyName];
                        // 绑定input 事件, 修改input内容时候,同时更新掉所有 {{inputData}} 数据, 即监听 inputData 
                        element.addEventListener('input', e => {
                            this._data[keyName] = element.value ;
                            // this.observe(this._data);
                        })
                    }
                    this.complieNode(element)
                }
            });
        }
    }
    
    
    
  • 相关阅读:
    高效出去List集合和数组中的重复元素
    各进制间转换总结
    java集合应用类
    禁止键盘上的刷新键F5等
    Map迭代
    java 过滤字符串方法实现
    java 跟 咖啡的关系
    插件jfreechart+shh实现树状图 柱状图 折线图
    Struts2利用iText导出word文档(包含表格)
    request.getRequestURI() 、request.getRequestURL() 、request.getContextPath()、request.getServletPath()区别
  • 原文地址:https://www.cnblogs.com/adouwt/p/13661061.html
Copyright © 2011-2022 走看看