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 相关文章推荐
JavaScript实现动态增加文件域表单
Feb 12 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
Sep 17 Javascript
Highcharts 多个Y轴动态刷新数据的实现代码
May 28 Javascript
jQuery查找节点并获取节点属性的方法
Sep 09 Javascript
Gulp实现静态网页模块化的方法详解
Jan 09 Javascript
vue-router 组件复用问题详解
Jan 22 Javascript
Vue.js 踩坑记之双向绑定
May 03 Javascript
Vue ElementUi同时校验多个表单(巧用new promise)
Jun 06 Javascript
vue组件横向树实现代码
Aug 02 Javascript
jQuery实时统计输入框字数及限制
Jun 24 jQuery
解决ant Design中this.props.form.validateFields未执行的问题
Oct 27 Javascript
JavaScript实现通讯录功能
Dec 27 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
ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法
2014/11/04 PHP
laravel实现分页样式替换示例代码(增加首、尾页)
2017/09/22 PHP
PHP使用JpGraph绘制折线图操作示例【附源码下载】
2019/10/18 PHP
PHP设计模式之外观模式(Facade)入门与应用详解
2019/12/13 PHP
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
JavaScript排序算法之希尔排序的2个实例
2014/04/04 Javascript
jquery实现submit提交表单
2015/02/03 Javascript
JavaScript判断是否为数组的3种方法及效率比较
2015/04/01 Javascript
原生 JS Ajax,GET和POST 请求实例代码
2016/06/08 Javascript
Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法
2016/06/23 Javascript
jQuery对table表格进行增删改查
2020/12/22 Javascript
JS实现旋转木马式图片轮播效果
2017/01/18 Javascript
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
JS 中使用Promise 实现红绿灯实例代码(demo)
2017/10/20 Javascript
详解Vue 事件修饰符capture 的使用
2017/12/29 Javascript
[00:52]黑暗之门更新 新英雄孽主驾临DOTA2
2016/08/24 DOTA
深入浅出分析Python装饰器用法
2017/07/28 Python
python实现简易版计算器
2020/06/22 Python
利用Python在一个文件的头部插入数据的实例
2018/05/02 Python
Python wxPython库Core组件BoxSizer用法示例
2018/09/03 Python
django admin后台添加导出excel功能示例代码
2019/05/15 Python
python 直接赋值和copy的区别详解
2019/08/07 Python
Django集成celery发送异步邮件实例
2019/12/17 Python
tensorflow通过模型文件,使用tensorboard查看其模型图Graph方式
2020/01/23 Python
Django使用Celery加redis执行异步任务的实例内容
2020/02/20 Python
Python使用pycharm导入pymysql教程
2020/09/16 Python
几款好用的python工具库(小结)
2020/10/20 Python
使用html5 canvas创建太空游戏的示例
2014/05/08 HTML / CSS
真正的英国宝藏:Mappin & Webb
2019/05/05 全球购物
安全生产目标责任书
2014/04/14 职场文书
学雷锋的心得体会
2014/09/04 职场文书
公司周年庆典标语
2014/10/07 职场文书
公务员个人考察材料
2014/12/23 职场文书
升学宴学生答谢词
2015/01/05 职场文书
Python控制台输出俄罗斯方块的方法实例
2021/04/17 Python
十大最强飞行系宝可梦,BUG燕上榜,第二是飞行系王者
2022/03/18 日漫