五十行javascript代码实现简单的双向数据绑定

Vue框架想必从事前端开发的同学都使用过,它的双向数据绑定机制能给我们带来很大的方便。今天闲着没事,尝试着实现一下双向数据绑定,接下来给大家分享一下。

Object.defineProperty(obj, prop, descriptor)

Object.defineProperty 方法允许精确添加或修改对象的属性。它的第一个参数 obj 是要在其上定义属性的对象,第二个参数 prop 是要定义或修改的属性的名称,第三个参数 descriptor 是一个将被定义或修改的属性的描述符。

返回值: 被传递给函数的对象。

来举个例子:

var o = Object.defineProperty({}, 'name', {
value: 1
}); console.log(o) // {name: 1}

这是最基本的定义一个对象的方式。对于属性描述符,还有很多其他属性:

数据描述符和存取描述符均具有以下可选键值:

  • configurable当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,也能够被删除。默认为 false。
  • enumerable当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。

数据描述符同时具有以下可选键值:

  • value该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
  • writable当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。

存取描述符同时具有以下可选键值:

  • get一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
  • set一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给属性。默认为 undefined。

这里只说一下 getset

看一下这个例子:

var o = Object.defineProperty({}, 'name', {
get: function () {
return this._name_;
},
set: function (value) {
this._name_ = value * 2;
}
}); o.name = 1;
console.log(o.name); // 2

给属性 name 定义了一个 getset ,为什么使用 _name_而不是name呢?因为name是正在被定义的属性,如果在get或者set中使用name无形之中就会发生递归,导致栈溢出。_name_这个是自己自定义的,你完全可以设置为$name__name__等等。

另外,使用对象的字面量形式也可以设置getset

var o = {
get name(){
return this._name_;
},
set name(value){
this._name_ = value * 2;
}
}; o.name = 1;
console.log(o.name); // 2

实现双向数据绑定

要实现双向数据绑定,肯定要从 getset 下手,在 set 的函数中重新渲染相关的数据,所以一开始应该是这样的:

var o = {
get name(){
return this._name_;
},
set name(value){
this._name_ = value;
this.render('name');
},
render: function(pro){
document.write(this[pro]);
}
};

在浏览器控制台修改一下o.name 试试:

如何实现表单控件到数据的绑定呢?在 Vue 中,表单元素通过 v-model 绑定一个变量,类型这样:

<input type="text" v-model="name">

其实 v-model 的元素是绑定了一个 input的自定义事件,我们不考虑那么多,就使用原生的 oninput 事件来模拟下。

var o = {
get name(){
return this._name_;
},
set name(value){
this._name_ = value;
console.log(this._name_);
},
inputInit: function () {
var self = this;
var vModels = document.querySelectorAll('[v-model]');
for (let i = 0; i < vModels.length; i++) {
vModels[i].addEventListener('input', function () {
var property = this.getAttribute('v-model');
var value = this.value;
self.name = value;
})
}
}
}.inputInit();

至此一个简单的双向数据绑定就差不多了,我们模仿一下 Vue 的api格式,再将代码封装一下:

html:

<input type="text" v-model="name">
<p v-text="name"></p>

javascript:

function Vue(options) {
var data = options.data || {};
var dKeys = Object.keys(data);
var _this = this;
this.vData = {};
// 根据data中的变量数量动态的绑定 get 与 set
for (let i = 0; i < dKeys.length; i++) {
Object.defineProperty(this.vData, dKeys[i], {
get: function () {
return this['__' + dKeys[i] + '__'];
},
set: function (value) {
this['__' + dKeys[i] + '__'] = value;
_this.render(dKeys[i]); // 重新渲染相关数据
}
})
} for(let i in data) { // 初始化时设置一变vData,触发一遍 set
this.vData[i] = data[i];
} this.inputInit(); // 给表单组件绑定事件监听
} Vue.prototype.render = function (pro) {
var vModels = document.querySelectorAll('[v-model=' + pro + ']');
var vText = document.querySelectorAll('[v-text=' + pro + ']');
for (var i = 0; i < vModels.length; i++) {
vModels[i].value = this.vData[pro];
} for (var j = 0; j < vText.length; j++) {
vText[j].innerText = this.vData[pro];
}
}; Vue.prototype.inputInit = function () {
var self = this;
var vModels = document.querySelectorAll('[v-model]');
for (let i = 0; i < vModels.length; i++) {
vModels[i].addEventListener('input', function () {
var property = this.getAttribute('v-model');
var value = this.value;
self.vData[property] = value;
})
}
}; var vm = new Vue({
data: {
name: 1
}
})

五十行javascript代码实现简单的双向数据绑定的更多相关文章

  1. JavaScript实现简单的双向数据绑定

    什么是双向数据绑定 双向数据绑定简单来说就是UI视图(View)与数据(Model)相互绑定在一起,当数据改变之后相应的UI视图也同步改变.反之,当UI视图改变之后相应的数据也同步改变. 双向数据绑定 ...

  2. 利用ES6中的Proxy和Reflect 实现简单的双向数据绑定

    利用ES6中的Proxy (代理) 和 Reflect 实现一个简单的双向数据绑定demo. 好像vue3也把 obj.defineProperty()  换成了Proxy+Reflect. 话不多说 ...

  3. React简单实现双向数据绑定

    import React, { Component } from 'react' import ReactDOM from 'react-dom' class App extends Componen ...

  4. javascript代码实现简单的五星评价功能!

    <script type="text/javascript"> //★ var spans=document.getElementsByTagName("sp ...

  5. 自己手动实现简单的双向数据绑定 mvvm

    数据绑定 数据绑定一般就是指的 将数据 展示到 视图上.目前前端的框架都是使用的mvvm模式实现双绑的.大体上有以下几种方式: 发布订阅 ng的脏检查 数据劫持 vue的话采用的是数据劫持和发布订阅相 ...

  6. 原生js简单实现双向数据绑定原理

    根据对象的访问器属性去监听对象属性的变化,访问器属性不能直接在对象中设置,而必须通过 defineProperty() 方法单独定义. 访问器属性的"值"比较特殊,读取或设置访问器 ...

  7. 简单实现双向数据绑定mvvm。

  8. angularJs初体验,实现双向数据绑定!使用体会:比较爽

    使用初体验:ng 双向数据绑定: 最简单的双向数据绑定:(使用默认模块控制) <body ng-app> <input type="text" ng-model= ...

  9. 深入vue源码,了解vue的双向数据绑定原理

    大家都知道vue是一种MVVM开发模式,数据驱动视图的前端框架,并且内部已经实现了双向数据绑定,那么双向数据绑定是怎么实现的呢? 先手动撸一个最最最简单的双向数据绑定 <div> < ...

随机推荐

  1. Min Stack leetcode

    Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. pu ...

  2. nodejs第二天之Buffer类

    2.1一个更好的操作二进制数据的类,我们在操作文件或者网络数据的时候,其实操作就是二进制数据,Node为我们提供了一个更加方便去操作这种数据流的类Buffer,它是一个全局的类. 2.2三种调用方式 ...

  3. 从零开始学习Vue.js,学习笔记

    一.为什么学习vue.js methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节. vue.js兼具angular.js和react的优点,并且剔除了他们的缺点 官网:http://cn ...

  4. a中的类型转换

    自动类型转换 当然自动类型转换是需要满足特定的条件的: 1.  目标类型能与源类型兼容,如 double 型兼容 int 型,但是 char 型不能兼容 int 型. 2.  目标类型大于源类型,如 ...

  5. PHP无锁内存nosql---Yac的实战

    无锁内存nosql---Yac的实战 最近在工作使用了yac,所以比较了下Memcache和Yac的高并发读写性能测试,发现Yac要比Memcache快很多(这里没有比较Yac和Apc的性能情况, 不 ...

  6. php函数的使用

    <?php header("Content-type:text/html; charset=utf-8"); //普通函数 echo "<br/>--- ...

  7. js应用之实现图片切换效果

    数组的操作与应用 数组的定义 var 数组名=new Array(); //创建空数组 var 数组名=new Array(size);//创建指定数组长度的数组 var 数组名=new Array( ...

  8. MySQL入门(下)

    1. 课程回顾(很清晰明了) mysql基础 1)mysql存储结构: 数据库 -> 表 -> 数据   sql语句 2)管理数据库: 增加: create database 数据库 de ...

  9. 解决!同一ajax请求获取的图片路劲,在谷歌浏览器能正确展示图片,在火狐浏览器则显示路径undefined

    今天的工作学习之路是解决了昨天的问题,可看我昨天的随笔了解问题. 非常感谢昨天各位积极地解答,在此我引用 @不带汽的可乐 的方法进行解决,问题其实挺简单就解决了,先说说原因,在火狐浏览器中,当我在js ...

  10. python计算文件夹大小(linux du命令 简化版)

    C盘又满了,怎么办?用了一些垃圾清理软件(或者bat脚本),但是还是不理想,那么具体哪些文件夹下面有巨大的文件呢?windows并不能通过详细信息看到每个文件夹的大小(PS:这里所谓的文件夹的大小是指 ...