最近公司要让我写部分前端,学习了一下Vue,并整理成博客。

Vue的数据绑定一直是用的很爽的一个功能,它让程序员无需关心dom操作,只需处理数据的变化。

数据的改变会自动渲染dom,数据驱动视图。

实现数据绑定用到的核心就是 Proxy

下面是两个手写单向/双向数据绑定的例子,仅供参考。

单向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        年龄:{{age}}
    </div>
    <button onclick="data.age++">age +1</button>
</body>

<script>
    //获取dom根节点
    let dom = document.getElementById('app');
    //保留原始html
    let template = dom.innerHTML;
    //内部data对象
    let _data = {
        age: 18
    };
    //对外的代理data对象
    let data = new Proxy(_data, {
        set(obj, name, value) {
            obj[name] = value;
            render();
        }
    });

    //页面渲染
    function render() {
        dom.innerHTML = template.replace(/\{\{\w+\}\}/g, s => {
            s = s.substring(2, s.length - 2);
            return _data[s];
        });
    }

    //初始化时直接渲染一次
    render();
</script>
</html>

双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        年龄:{{age}}<br>
        <input type="text" v-model="age">
    </div>
</body>

<script>
    //获取dom根节点
    let dom = document.getElementById('app');
    //保留原始html
    let template = dom.innerHTML;
    //内部data对象
    let _data = {
        age: 18
    };
    //对外的代理data对象
    let data = new Proxy(_data, {
        set(obj, name, value) {
            obj[name] = value;
            render();
        }
    });

    //页面渲染
    function render() {
        dom.innerHTML = template.replace(/\{\{\w+\}\}/g, s => {
            s = s.substring(2, s.length - 2);
            return _data[s];
        });
        //找到所有带v-model属性的input
        Array.from(dom.getElementsByTagName('input'))
            .filter(el => el.getAttribute('v-model'))
            .forEach(input => {
                let model = input.getAttribute('v-model');
                input.value = data[model];
                input.oninput = () => {
                    data[model] = input.value;
                    input.focus();
                };
            });
    }

    //初始化时直接渲染一次
    render();
</script>
</html>
Logo

前往低代码交流专区

更多推荐