实现一个双向绑定和v-model

发布订阅模式

我把发布订阅的实现类单独提出来,这样代码看起来简洁

/*
* 发布订阅
**/
class Pubsub {
    static instance = null;

    // 单例
    static getInstance() {
        if (Pubsub.instance == null) {
            Pubsub.instance = new Pubsub;
        }
        return Pubsub.instance;
    }

    // 注册的事件和处理器关联集合
    eventAndHandel = {};

    // 触发  
    emit(eventName, params) {
        if (this.eventAndHandel.hasOwnProperty(eventName)) {
            this.eventAndHandel[eventName].forEach(hander => {
                hander(params)
            });
        }
    }

    // 注册or订阅
    on(eventName, cbc) {
        if (!this.eventAndHandel.hasOwnProperty(eventName)) {
            this.eventAndHandel[eventName] = [cbc]
        } else {
            this.eventAndHandel[eventName].push(cbc)
        }
    }
}

第一版本

最普通的语法

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div>
        <h1 d-bind="name"></h1>
        <span d-bind="name"></span>:<span d-bind="age"></span>
    </div>
    <div>
        姓名:<input d-model="name" type="text"></br>
        性别:<input d-model="age" type="text"></br>
    </div>
    <!-- <script src="./lodash.js"></script> -->
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
    <script src="./helper.js"></script>
    <script>
        // ---------------------一个vue实例开始----------------------------


        const data = {
            name: '丁少华',
            age: 20
        };


        // v-model的实现
        const models = document.querySelectorAll(`[d-model]`);
        models.forEach(item => {
            const v = item.getAttribute('d-model');
            item.oninput = function ({ target: { value } }) {
                data[v] = value;
            }

        })

        // 双向绑定的实现
        const pubsub = Pubsub.getInstance();
        const data_ = _.cloneDeep(data);

        for (const key in data) {
            Object.defineProperty(data, key, {
                set(newValue) {
                    data_[key] = newValue;
                    pubsub.emit('vm', {
                        id: key,
                        value: newValue
                    })
                },
                get() {
                    return data_[key];
                }
            })
        }
        pubsub.on('vm', ({ id, value }) => {
            // 给普通节点复制
            const binds = document.querySelectorAll(`[d-bind=${id}]`);
            binds.forEach(item => {
                item.innerText = value;
            })

            // 给表单控件赋值
            const models = document.querySelectorAll(`[d-model=${id}]`);
            models.forEach(item => {
                item.value = value;
            })
        });

        // 初始化赋值


        for (const key in data) {
            data[key] = data[key];
        }

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

实现一个双向绑定和v-model

上一篇:Android 车载应用开发与分析(5) - CarLauncher(一)


下一篇:vue组件库封装 广播 $dispatch $broadcast