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 相关文章推荐
Prototype的Class.create函数解析
Sep 22 Javascript
jQuery 获取浏览器所在的IP地址的小例子
Nov 08 Javascript
js实现飞入星星特效代码
Oct 17 Javascript
深入分析js的冒泡事件
Dec 05 Javascript
7个有用的jQuery代码片段分享
May 19 Javascript
js实现仿MSN带关闭功能的右下角弹窗代码
Sep 04 Javascript
基于jquery编写的放大镜插件
Mar 23 Javascript
AngularJS 作用域详解及示例代码
Aug 17 Javascript
Servlet实现文件上传,可多文件上传示例
Dec 05 Javascript
JS实现HTML标签转义及反转义
Apr 14 Javascript
深入解析Vue 组件命名那些事
Jul 18 Javascript
vue路由守卫,限制前端页面访问权限的例子
Nov 11 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 应用程序的安全 -- 不能违反的四条安全规则
2006/11/26 PHP
PHP中查询SQL Server或Sybase时TEXT字段被截断的解决方法
2009/03/10 PHP
幻灯片带网页设计中的20个奇妙应用示例小结
2012/05/27 Javascript
IE6下opacity与JQuery的奇妙结合
2013/03/01 Javascript
基于mouseout和mouseover等类似事件的冒泡问题解决方法
2013/11/18 Javascript
基于jquery实现瀑布流布局
2020/06/28 Javascript
浅析AngularJS Filter用法
2015/12/28 Javascript
js+css实现回到顶部按钮(back to top)
2016/03/02 Javascript
基于jquery实现即时检查格式是否正确的表单
2016/05/06 Javascript
javascript数据类型详解
2017/02/07 Javascript
详解在Vue中通过自定义指令获取dom元素
2017/03/04 Javascript
JavaScript实现隐藏省略文字效果的方法
2017/04/27 Javascript
Vue.js教程之axios与网络传输的学习实践
2017/04/29 Javascript
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
JS实现从对象获取对象中单个键值的方法示例
2019/06/05 Javascript
jQuery pager.js 插件动态分页功能实例分析
2019/08/02 jQuery
javascript Canvas动态粒子连线
2020/01/01 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
weui上传多图片,压缩,base64编码的示例代码
2020/06/22 Javascript
详解Vue.js3.0 组件是如何渲染为DOM的
2020/11/10 Javascript
Python实现过滤单个Android程序日志脚本分享
2015/01/16 Python
Python中使用hashlib模块处理算法的教程
2015/04/28 Python
python字典键值对的添加和遍历方法
2016/09/11 Python
Python实现字符串与数组相互转换功能示例
2017/09/22 Python
pycharm 实现显示project 选项卡的方法
2019/01/17 Python
Python 中使用 PyMySQL模块操作数据库的方法
2019/11/10 Python
python 实现多维数组(array)排序
2020/02/28 Python
基于python实现操作redis及消息队列
2020/08/27 Python
python 如何区分return和yield
2020/09/22 Python
python读取excel数据绘制简单曲线图的完整步骤记录
2020/10/30 Python
python实现简单的井字棋游戏(gui界面)
2021/01/22 Python
Easy Spirit官网:美国休闲鞋履中的代表品牌
2019/04/12 全球购物
致垒球运动员加油稿
2014/02/16 职场文书
音乐教学随笔感言
2014/02/19 职场文书
工商管理自荐书
2014/07/06 职场文书
委托书怎样写
2014/08/30 职场文书