继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

MYYA
关注TA
已关注
手记 300
粉丝 75
获赞 326

前言 上次写了一个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


打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP