请将此问题视为严格教育 . I'm still interested in hearing new answers and ideas to implement this
tl;博士
我如何使用JavaScript实现双向数据绑定?
数据绑定到DOM
通过数据绑定到DOM我的意思是,例如,拥有一个带有属性 b
的JavaScript对象 a
. 然后有一个 <input>
DOM元素(例如),当DOM元素改变时, a
改变,反之亦然(也就是说,我的意思是双向数据绑定) .
以下是AngularJS的示意图:
所以基本上我有类似的JavaScript:
var a = {b:3};
然后输入(或其他形式)元素,如:
<input type='text' value=''>
我'd like the input'的值是 a.b
's value (for example), and when the input text changes, I' d,如 a.b
也要改变 . 当 a.b
在JavaScript中更改时,输入会更改 .
问题
在纯JavaScript中完成此操作的基本技术有哪些?
具体来说,我想要一个很好的答案来参考:
-
如何绑定对象的工作?
-
如何听取表格中的变化可能有效?
-
是否可以以简单的方式仅在模板级别修改HTML?我想不跟踪HTML文档本身的绑定,而只是跟踪JavaScript(使用DOM事件,并且JavaScript保持对所使用的DOM元素的引用) .
我尝试了什么?
我是Mustache的忠实粉丝,所以我尝试用它来模板化 . 但是,当我尝试执行数据绑定本身时遇到了问题,因为Mustache将HTML作为字符串处理,因此在得到结果之后,我没有引用viewmodel中对象的位置 . 我能想到的唯一解决方法是使用属性修改HTML字符串(或创建DOM树)本身 . 我不介意使用不同的模板引擎 .
基本上,我有一种强烈的感觉,我正在使手头的问题变得复杂,并且有一个简单的解决方案 .
Note: 请不要提供使用外部库的答案,特别是那些数千行代码的库 . 我've used (and like!) AngularJS and KnockoutJS. I really don'想要答案的形式是'use framework x' . 最理想的是,我知道如何使用许多框架来掌握如何自己实现双向数据绑定 . 我不希望得到一个完整的答案,而是一个能够理解这个想法的答案 .
12 回答
更新两个对象的抽象
我想还有其他技术,但最终我有一个对象,它持有对相关DOM元素的引用,并提供一个接口来协调对自己的数据及其相关元素的更新 .
.addEventListener()
为此提供了一个非常好的界面 . 您可以为它提供一个实现eventListener
接口的对象,并且它将使用该对象作为this
值调用其处理程序 .这使您可以自动访问元素及其相关数据 .
定义对象
原型继承是实现这一目标的好方法,当然不是必需的 . 首先,您将创建一个接收元素和一些初始数据的构造函数 .
所以这里的构造函数将元素和数据存储在新对象的属性中 . 它还将
change
事件绑定到给定的element
. 有趣的是它传递新对象而不是函数作为第二个参数 . 但仅此一点是行不通的 .实现eventListener接口
要使其工作,您的对象需要实现
eventListener
接口 . 完成此任务所需要的只是为对象提供handleEvent()
方法 .这就是继承的来源 .
有许多不同的方式可以构建它,但是对于协调更新的示例,我决定使
change()
方法只接受一个值,并让handleEvent
传递该值而不是事件对象 . 这样,change()
也可以在没有事件的情况下调用 .所以现在,当
change
事件发生时,它将更新元素和.data
属性 . 当您在JavaScript程序中调用.change()
时也会发生同样的情况 .使用代码
现在,您只需创建新对象,然后让它执行更新 . JS代码中的更新将出现在输入中,并且JS代码可以看到输入上的更改事件 .
DEMO: http://jsfiddle.net/RkTMD/
所以,我决定把自己的解决方案扔进锅里 . 这是working fiddle . 请注意,这只会运行在非常现代的浏览器上
它的用途
这种实现非常现代 - 它需要一个(非常)现代的浏览器和用户两种新技术:
MutationObservers检测dom中的更改(也使用事件侦听器)
Object.observe检测对象的变化并通知dom . 危险,因为这个答案已经写成了O.o已经被ECMAScript TC讨论并决定反对,考虑使用polyfill .
它是如何工作的
在元素上,放一个
domAttribute:objAttribute
映射 - 例如bind='textContent:name'
在dataBind函数中读取它 . 观察元素和对象的更改 .
发生更改时 - 更新相关元素 .
解决方案
这是
dataBind
函数,请注意它只有20行代码,可能更短:这是一些用法:
HTML:
JavaScript的:
这是working fiddle . 请注意,此解决方案非常通用 . 可以使用Object.observe和变异观察器填充 .
我想补充一下我的前言 . 我建议采用略有不同的方法,只需在不使用方法的情况下为对象分配新值即可 . 必须注意的是,特别是旧版浏览器不支持这一点,IE9仍然需要使用不同的界面 .
最值得注意的是我的方法没有利用事件 .
吸气员和二传手
我的建议利用了getters and setters的相对年轻的特征,特别是仅限制定者 . 一般来说,mutators允许我们__804011_某些属性被赋值和检索的行为 .
我将在这里使用的一个实现是Object.defineProperty方法 . 它适用于FireFox,GoogleChrome和 - 我认为 - IE9 . 没有测试过其他浏览器,但因为这只是理论...
无论如何,它接受三个参数 . 第一个参数是您希望为其定义新属性的对象,第二个参数是类似于新属性名称的字符串,最后一个是“描述符对象”,提供有关新属性行为的信息 .
两个特别有趣的描述符是
get
和set
. 一个例子看起来像下面这样 . 请注意,使用这两个禁止使用其他4个描述符 .现在使用它变得略有不同:
I want to emphasize that this only works for modern browsers.
工作小提琴:http://jsfiddle.net/Derija93/RkTMD/1/
我认为我的答案将更具技术性,但并没有不同,因为其他人使用不同的技术呈现相同的东西 .
所以,首先,这个问题的解决方案是使用一种称为"observer"的设计模式,它让's you decouple your data from your presentation, making the change in one thing be broadcasted to their listeners, but in this case it'做成了双向 .
对于DOM到JS的方式
要将数据从DOM绑定到js对象,您可以以
data
属性(或类,如果需要兼容性)的形式添加标记,如下所示:这样就可以通过js使用querySelectorAll(或者老友getElementsByClassName来兼容)来访问它 .
现在,您可以将侦听更改的事件绑定到以下方式:每个对象一个侦听器或容器/文档的一个大侦听器 . 绑定到文档/容器将触发事件,对于它或它的子进行的每个更改,它将具有更小的内存占用但将产生事件调用 .
代码看起来像这样:
对于JS do DOM方式
您将需要两件事:一个元对象将保存女巫DOM元素的引用绑定到每个js对象/属性以及一种监听对象更改的方式 . 它基本上是相同的方式:您必须有一种方法来监听对象中的更改然后将其绑定到DOM节点,因为您的对象“不能拥有”元数据,您将需要另一个以某种方式保存元数据的对象属性名称映射到元数据对象的属性 . 代码将是这样的:
我希望我有所帮助 .
昨天,我开始编写自己的绑定数据的方法 .
玩它很有趣 .
我认为它很漂亮,非常有用 . 至少在我使用firefox和chrome的测试中,Edge也必须正常工作 . 不确定其他人,但如果他们支持代理,我认为它会工作 .
https://jsfiddle.net/2ozoovne/1/
这是代码:
然后,设置,只需:
现在,我刚刚添加了HTMLInputElement值bind .
如果您知道如何改进它,请告诉我 .
在这个链接中有一个非常简单的准确的双向数据绑定实现"Easy Two-Way Data Binding in JavaScript"
以前的链接来自knockoutjs,backbone.js和agility.js的想法,导致了基于jQuery的this light-weight and fast MVVM framework, ModelView.js,它与jQuery很好地兼容,而且我是谦虚(或者可能不那么谦逊)的作者 .
下面重现示例代码(来自blog post link):
Sample code for DataBinder
绑定任何html输入
定义两个功能:
使用功能:
更改元素的值可以触发DOM event . 响应事件的侦听器可用于在JavaScript中实现数据绑定 .
例如:
Here是代码和演示,它显示了DOM元素如何相互绑定或与JavaScript对象绑定 .
我已经使用onkeypress和onchange事件处理程序进行了一些基本的javascript示例,以便为我们的js和js创建绑定视图
这里的示例plunker http://plnkr.co/edit/7hSOIFRTvqLAvdZT4Bcc?p=preview
将变量绑定到输入(双向绑定)的简单方法是直接访问getter和setter中的input元素:
在HTML中:
并使用:
没有getter / setter的更好的方式:
使用:
在vanilla javascript中它是非常简单的双向数据绑定....