热门标签 | 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的情况下,也能够以简洁且高效的方式实现双向数据绑定。


推荐阅读
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社区 版权所有