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 相关文章推荐
js中top、clientTop、scrollTop、offsetTop的区别 文字详细说明版
Jan 08 Javascript
jquery ajax 同步异步的执行 return值不能取得的解决方案
Jan 08 Javascript
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
Apr 02 Javascript
js实现日历可获得指定日期周数及星期几示例分享(js获取星期几)
Mar 14 Javascript
JS实现图片无间断滚动代码汇总
Jul 30 Javascript
一分钟理解js闭包
May 04 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
Dec 08 Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
Jan 07 Javascript
浅谈JavaScript面向对象--继承
Mar 20 Javascript
JavaScript函数IIFE使用详解
Oct 21 Javascript
vue项目初始化到登录login页面的示例
Oct 31 Javascript
Node.JS获取GET,POST数据之queryString模块使用方法详解
Feb 06 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
Mysql的GROUP_CONCAT()函数使用方法
2008/03/28 PHP
PHP生成UTF8文件的方法
2010/05/15 PHP
PHP 使用pcntl和libevent 实现Timer功能
2013/10/27 PHP
浅谈Laravel POST,PUT,PATCH 路由的区别
2019/10/15 PHP
一个可以显示阴历的JS代码
2007/03/05 Javascript
JavaScript判断窗口是否最小化的代码(跨浏览器)
2010/08/01 Javascript
编写高效jQuery代码的4个原则和5个技巧
2014/04/24 Javascript
jQuery实现的淡入淡出二级菜单效果代码
2015/09/15 Javascript
理解AngularJs指令
2015/12/10 Javascript
AngularJS入门教程之路由机制ngRoute实例分析
2016/12/13 Javascript
微信小程序 登录实例详解
2017/01/16 Javascript
Vue生命周期示例详解
2017/04/12 Javascript
vue实现按需加载组件及异步组件功能
2019/05/27 Javascript
layui.use模块外部使用其内部定义的js封装函数方法
2019/09/16 Javascript
vue.js路由mode配置之去掉url上默认的#方法
2019/11/01 Javascript
js blob类型url的视频下载问题的解决
2019/11/29 Javascript
vue-cli设置publicPath小记
2020/04/14 Javascript
js模拟实现百度搜索
2020/06/28 Javascript
Vue组件间数据传递的方式(3种)
2020/07/13 Javascript
[36:54]Mineski vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python制作数据导入导出工具
2015/07/31 Python
基于MTCNN/TensorFlow实现人脸检测
2018/05/24 Python
Flask Web开发入门之文件上传(八)
2018/08/17 Python
Python元组常见操作示例
2019/02/19 Python
Python中sorted()排序与字母大小写的问题
2020/01/14 Python
python实现提取str字符串/json中多级目录下的某个值
2020/02/27 Python
Python操作Jira库常用方法解析
2020/04/10 Python
pytorch使用horovod多gpu训练的实现
2020/09/09 Python
详解如何用canvas画一个微笑的表情
2019/03/14 HTML / CSS
Origins加拿大官网:雅诗兰黛集团高端植物护肤品牌
2017/11/19 全球购物
27个经典Linux面试题及答案,你知道几个?
2013/01/10 面试题
经典而简洁的婚礼主持词
2014/03/13 职场文书
家庭教育的心得体会
2014/09/01 职场文书
简短的36句中秋节祝福信息语句
2019/09/09 职场文书
linux下安装redis图文详细步骤
2021/12/04 Redis
python实现手机推送 代码也就10行左右
2022/04/12 Python