vue用Object.defineProperty手写一个简单的双向绑定的示例
前言 上次写了一个Object.defineProperty() 不详解,文末说要写用它来写个双向绑定。说话算话,说来就来
前文链接 Object.defineProperty() 不详解
先看最后效果

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);

get和set存取时被调用
如上图所示 每当我获取user.name属性时,get方法被调用,get 方法对应的函数被执行,输出 你是不是来获取值啦;每当我设置user.name属性时,set方法对应的函数被执行,输出 你是不是来设置值啦 ; 是的,我们监控到了代码对user.name属性的存取。
说明 假设id="model" 的元素的 value 是user.name的值,既然我们可以在改变属性的执行日志输出(console.log("你是不是来设置值啦");),那么,我们在设置值的时候给id="model" 的元素设置下新值,不就实现了从模型到视图?!!,说干就干
模型到视图(model => view)的同步
说明 假设id="model" 的元素的 value 是user.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>

模型到视图(model => view)的同步
视图到模型(view => model)的同步
问: 我们能捕捉到view对值更改吗?
答:可以!! id="model" 的input元素的 value 是user.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>

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 可以做很多好玩儿的,自己慢慢探索哈~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
vue使用ArcGis API for js创建地图实现示例
这篇文章主要为大家介绍了vue使用ArcGis API for js创建地图实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-08-08
ant design vue中table表格滚动加载实现思路
在处理一写数据量特别大的情况下,我们不能把后端的数据一次性全部拿到前端在table表格中展示,为了考虑性能优化,使用了滚动加载表格数据,这篇文章主要介绍了ant design vue中table表格滚动加载实现思路,需要的朋友可以参考下2024-07-07
如何将iconfont图标引入到vant的Tabbar标签栏里边
这篇文章主要介绍了如何将iconfont图标引入到vant的Tabbar标签栏里边,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-04-04
vue 解决uglifyjs-webpack-plugin打包出现报错的问题
这篇文章主要介绍了vue 解决uglifyjs-webpack-plugin打包出现报错的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-08-08


最新评论