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


Posted in Javascript onJuly 09, 2018

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

前文链接 Object.defineProperty() 不详解

先看最后效果

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

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

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>

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

模型到视图(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>

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

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 可以做很多好玩儿的,自己慢慢探索哈~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery 入门实例1
Jun 25 Javascript
jquery中实现简单的tabs插件功能的代码
Mar 02 Javascript
基于json的jquery地区联动效果代码
Jul 06 Javascript
浅谈Javascript事件模拟
Jun 27 Javascript
Jquery Ajax解析XML数据(同步及异步调用)简单实例
Feb 12 Javascript
javascript实现简单的省市区三级联动
May 14 Javascript
基于Jquery实现表单验证
Jul 20 Javascript
javascript弹出拖动窗口
Aug 11 Javascript
微信小程序 rpx 尺寸单位详细介绍
Oct 13 Javascript
jQuery.Form上传文件操作
Feb 05 Javascript
js对象实例详解(JavaScript对象深度剖析,深度理解js对象)
Sep 21 Javascript
JavaScript中EventLoop介绍
Jan 22 Javascript
js中Object.defineProperty()方法的不详解
Jul 09 #Javascript
微信小程序实现团购或秒杀批量倒计时
Nov 01 #Javascript
微信小程序实现倒计时补零功能
Jul 09 #Javascript
Angular6中使用Swiper的方法示例
Jul 09 #Javascript
微信小程序实现自定义picker选择器弹窗内容
May 26 #Javascript
微信小程序实现漂亮的弹窗效果
May 26 #Javascript
Angular通过指令动态添加组件问题
Jul 09 #Javascript
You might like
PHP新手NOTICE错误常见解决方法
2011/12/07 PHP
PHP 设计模式之观察者模式介绍
2012/02/22 PHP
php缓冲 output_buffering和ob_start使用介绍
2014/01/30 PHP
php自动提交表单的方法(基于fsockopen与curl)
2016/05/09 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
2018/06/13 PHP
浅谈thinkphp的nginx配置,以及重写隐藏index.php入口文件方法
2019/10/12 PHP
让innerHTML的脚本也可以运行起来
2006/07/01 Javascript
用Javascript做flash做的事..才完成的一个类.Auntion Action var 0.1
2007/02/23 Javascript
JavaScript 对象链式操作测试代码
2010/04/25 Javascript
document.getElementById的简写方式(获取id对象的简略写法)
2010/09/10 Javascript
获取数组中最大最小值方法js代码(自写)
2013/08/12 Javascript
JS 屏蔽按键效果与改变按键效果的示例代码
2013/12/24 Javascript
js(JavaScript)实现TAB标签切换效果的简单实例
2014/02/26 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
Node.js开发者必须了解的4个JS要点
2016/02/21 Javascript
JavaScript的ExtJS框架中表格的编写教程
2016/05/21 Javascript
浅谈JavaScript中的this指针和引用知识
2016/08/05 Javascript
javascript判断回文数详解及实现代码
2017/02/03 Javascript
js实现返回顶部效果
2017/03/10 Javascript
详解react-webpack2-热模块替换[HMR]
2017/08/03 Javascript
原生js封装添加class,删除class的实例
2017/11/06 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
vue加载自定义的js文件方法
2018/03/13 Javascript
vue2.0 如何在hash模式下实现微信分享
2019/01/22 Javascript
Vue开发之封装上传文件组件与用法示例
2019/04/25 Javascript
ES6 Object属性新的写法实例小结
2019/06/25 Javascript
layer.open弹层查看缩略图的原图,自适应大小的实例
2019/09/05 Javascript
vue 实现input表单元素的disabled示例
2019/10/28 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
JavaScript 判断浏览器是否是IE
2021/02/19 Javascript
python使用selenium登录QQ邮箱(附带滑动解锁)
2019/01/23 Python
python scipy卷积运算的实现方法
2019/09/16 Python
python 实现将小图片放到另一个较大的白色或黑色背景图片中
2019/12/12 Python
详解window.open被浏览器拦截的解决方案
2019/07/18 HTML / CSS
试用期解除劳动合同通知书
2015/04/16 职场文书
煤矿安全生产管理协议书
2016/03/22 职场文书