热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

简易实现JavaScript中的双向数据绑定

双向数据绑定技术使得对象属性与用户界面之间可以相互影响,即对象属性的更改能即时反映到界面上,同时用户的界面操作也能同步更新对象状态。本文将介绍如何利用简单的JavaScript代码实现这一功能。

双向数据绑定是一种机制,它确保当对象属性发生变化时,这些变化会立即反映在用户界面上,反之亦然。例如,若存在一个包含name属性的user对象,当我们修改user.name的值时,界面上显示的名字也会相应更新。同样,如果界面上有一个用于输入用户名的文本框,用户在此输入的新值也会导致user对象的name属性更新。

虽然像Ember.js、Angular.js或KnockoutJS这样的现代Javascript框架提供了内置的双向数据绑定功能,但这并不意味着没有它们就无法实现这一功能。实际上,实现双向数据绑定的基本原理相当简单,可以通过三个步骤来概括:

  • 定义一种方式,使UI元素能够与对象属性相绑定;
  • 监控这些属性和UI元素的状态变化;
  • 确保所有相关联的对象和元素都能接收到并响应这些变化。

一个有效的实现方法是采用发布/订阅(PubSub)模式。在这种模式下,HTML元素通过特定的数据属性与Javascript对象关联,所有相关的对象和DOM元素都订阅同一个PubSub实例。当检测到数据变化时,会触发PubSub实例上的事件,通知所有订阅者进行相应的更新。

以下是使用jQuery简化DOM事件处理的一个示例:

function DataBinder(objectId) {
const pubSub = $( {} );
const dataAttr = `bind-${objectId}`;
const message = `${objectId}:change`;

$(document).on('change', `[data-${dataAttr}]`, function(event) {
const $input = $(this);
pubSub.trigger(message, [$input.data(dataAttr), $input.val()]);
});

pubSub.on(message, function(event, propName, newVal) {
$(`[data-${dataAttr}='${propName}']`).each(function() {
const $bound = $(this);
if ($bound.is('input, textarea, select')) {
$bound.val(newVal);
} else {
$bound.html(newVal);
}
});
});

return pubSub;
}

基于上述DataBinder,我们可以创建一个简单的User模型:

function User(uid) {
const binder = new DataBinder(uid);
const user = {
attributes: {},
set(attrName, val) {
this.attributes[attrName] = val;
binder.trigger(`${uid}:change`, [attrName, val, this]);
},
get(attrName) {
return this.attributes[attrName];
},
_binder: binder
};

binder.on(`${uid}:change`, function(event, attrName, newVal, initiator) {
if (initiator !== user) {
user.set(attrName, newVal);
}
});

return user;
}

为了将User模型的属性绑定到UI上,只需在HTML元素上添加适当的数据属性即可。例如,设置用户名称的输入框如下所示:

此外,也可以不依赖jQuery来实现相同的功能。通过使用原生Javascript编写自定义的PubSub实现,并处理DOM事件,可以达到同样的效果。这种方法虽然稍微复杂一些,但完全可行,尤其适用于那些不想引入额外库的项目。

function DataBinder(objectId) {
const pubSub = {
callbacks: {},
on(msg, callback) {
(this.callbacks[msg] = this.callbacks[msg] || []).push(callback);
},
publish(msg, ...args) {
(this.callbacks[msg] || []).forEach(cb => cb(...args));
}
};

const dataAttr = `data-bind-${objectId}`;
const message = `${objectId}:change`;
const changeHandler = event => {
const target = event.target || event.srcElement;
const propName = target.getAttribute(dataAttr);
if (propName) {
pubSub.publish(message, propName, target.value);
}
};

if (document.addEventListener) {
document.addEventListener('change', changeHandler, false);
} else {
document.attachEvent('onchange', changeHandler);
}

pubSub.on(message, (event, propName, newVal) => {
document.querySelectorAll(`[${dataAttr}='${propName}']`).forEach(element => {
if (['input', 'textarea', 'select'].includes(element.tagName.toLowerCase())) {
element.value = newVal;
} else {
element.innerHTML = newVal;
}
});
});

return pubSub;
}

通过这种方式,即使在没有jQuery的情况下,也能够以简洁且高效的方式实现双向数据绑定。


推荐阅读
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • 本文讨论了如何根据特定条件动态显示或隐藏文件上传控件中的默认文本(如“未选择文件”)。通过结合CSS和JavaScript,可以实现更灵活的用户界面。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 使用Vultr云服务器和Namesilo域名搭建个人网站
    本文详细介绍了如何通过Vultr云服务器和Namesilo域名搭建一个功能齐全的个人网站,包括购买、配置服务器以及绑定域名的具体步骤。文章还提供了详细的命令行操作指南,帮助读者顺利完成建站过程。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
author-avatar
手机用户3312丿075454
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有