为了账号安全,请及时绑定邮箱和手机立即绑定

用Object.defineProperty手写一个简单的双向绑定

前言 上次写了一个Object.defineProperty() 不详解,文末说要写用它来写个双向绑定。说话算话,说来就来

前文链接 Object.defineProperty() 不详解
先看最后效果

webp

model演示.gif


什么是双向绑定?

  1. 当一个对象(或变量)的属性改变,那么调用这个属性的地方显示也应该改变,模型到视图(model => view)

2.当调用属性的这个地方改变了这个属性(通常是一个表单元素),那么这个对象(或变量)的属性也会改为最新的值 ,即视图到模型(view => model)

我们怎么知道对象的属性变了?

上文说到,Object.defineProperty 设置对象属性的描述字段里面有两个属性 set (设置属性时被调用)和get(获取属性时被调用),只说不练,你再讲什么?眼见为实好吗?OK ,上代码

var user = {};var defaultName = "狂奔的蜗牛";Object.defineProperty(user,"name",{    get:function(){        console.log("你是不是来获取值啦");        return defaultName;
    },    set:function(value){        console.log("你是不是来设置值啦");
        defaultName = value;
    }
})console.log(user.name);
user.name = "狂奔的萝卜";console.log(user.name);

webp

get和set存取时被调用

如上图所示 每当我获取user.name属性时,get方法被调用,get 方法对应的函数被执行,输出 你是不是来获取值啦;每当我设置user.name属性时,set方法对应的函数被执行,输出 你是不是来设置值啦 ; 是的,我们监控到了代码对user.name属性的存取。

说明 假设id="model" 的元素的 valueuser.name的值,既然我们可以在改变属性的执行日志输出(console.log("你是不是来设置值啦");),那么,我们在设置值的时候给id="model" 的元素设置下新值,不就实现了从模型到视图?!!,说干就干

模型到视图(model => view)的同步

说明 假设id="model" 的元素的 valueuser.name的值,既然我们可以在改变属性的执行日志输出(console.log("你是不是来设置值啦");),那么,我们在设置值的时候给id="model" 的元素设置下新值,不就实现了从模型到视图?!!,说干就干

<body>
    手写一个简单双向绑定<br/>
    <input type="text" id="model"><br/>
    <div id="modelText"></div></body><script>var user = {};var defaultName = "狂奔的蜗牛";document.querySelector("#model").value = defaultName;document.querySelector("#modelText").textContent = defaultName;//定义属性 监控改变Object.defineProperty(user,"name",{    get:function(){        console.log("你是不是来获取值啦");        return defaultName;
    },    set:function(newValue){        console.log("设置新值");
        defaultName = newValue;        console.log("实现 模型 => 视图");        document.querySelector("#model").value = newValue;        document.querySelector("#modelText").textContent = newValue;
    }
})console.log("2s 后改变值");

setTimeout(() => {    //改变值
    user.name = "狂奔的萝卜";
}, 2000);</script>

webp

模型到视图(model => view)的同步

视图到模型(view => model)的同步

问: 我们能捕捉到view对值更改吗?
答:可以!! id="model" 的input元素的 valueuser.name的值,填充在这个文本框里面,文本框有个“ keyup” 事件,当我们在文本框中输入文字的时候,文本框的值会跟着改变,并且会连续触发keyup事件,那么我们只需要监听这个事件,是不是就可以捕捉到view对值的更改了??既然文本框的值会跟着改变,我们获取最新的值再把新值更新到user.name属性,不就实现了视图到模型(view => model)的同步?没代码说个啥

<body>
    手写一个简单双向绑定<br/>
    <input type="text" id="model"><br/>
    <div id="modelText"></div></body><script>
    var user = {};    var defaultName = "狂奔的蜗牛";    var model = document.querySelector("#model");    var modelText = document.querySelector("#modelText");

    model.value = defaultName;
    modelText.textContent = defaultName;    //定义属性 监控改变
    Object.defineProperty(user,"name",{        get:function(){            console.log("你是不是来获取值啦");            return defaultName;
        },        set:function(newValue){            console.log("设置新值");
            defaultName = newValue;
            model.value = newValue;
            modelText.textContent = newValue;
        }
    })

    model.addEventListener("keyup", function () {
        user.name = this.value;        console.log("实现 视图 => 模型");
    }, false)</script>

webp

view2model.gif


【最终源码】

在上述代码的基础上,加入了 用户输入中文的判断(用户输入中文时,频繁触发 keyup事件,但实际上输入并没有结束。)

<!DOCTYPE html><html><head>
    <meta charset="utf-8">
    <title>双向绑定</title></head><body>
    手写一个简单双向绑定<br/>
    <input type="text" id="model"><br/>
    <div id="modelText"></div></body><script>
    var model = document.querySelector("#model");    var modelText = document.querySelector("#modelText");    var defaultName = "defaultName";    var userInfo = {}
    model.value = defaultName;    Object.defineProperty(userInfo, "name", {        get: function () {            return defaultName;
        },        set: function (value) {
            defaultName = value;
            model.value = value;            console.log("-----value");            console.log(value);
            modelText.textContent = value;
        }
    })

    userInfo.name = "new value";    var isEnd = true;

    model.addEventListener("keyup", function () {        if (isEnd) {
            userInfo.name = this.value;
        }
    }, false)    //加入监听中文输入事件
    model.addEventListener("compositionstart", function () {        console.log("开始输入中文");
        isEnd = false;
    })
    model.addEventListener("compositionend", function () {
        isEnd = true;        console.log("结束输入中文");
    })</script></html>

【完结】
Object.defineProperty 可以做很多好玩儿的,自己慢慢探索哈~

个人水平有限,不喜勿喷哈,欢迎提意见~



作者:小枫学幽默
链接:https://www.jianshu.com/p/251235dd04c8


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消