我们之前描述过,通过 JavaScript,如何从 DOM 元素的属性中,解析出复杂的值,并转成合适的对象。然而,我们还希望拥有一项更酷炫的技能,那就是提供一个方法,提供一个 DOM 和一些想要获取的属性的名称,然后输出一个对象,这个对象包含一些属性,这些属性刚好就是那个 DOM 上的属性,当 DOM 上的那些属性更新后,对象上的属性也可以支持更新。由此,我们可以拥有一个更面向前端友好的方式去动态获取某个 DOM 节点上所关心的属性内容了。
听起来很棒,但怎么实现呢?废话不多说,我们赶快开始搞定这件事吧!
我们需要提供一个函数,输入的是一个 DOM 元素,以及一个字符串数组,数组里面放的是需要获取的 DOM 属性名称。在这个函数里面,我们需要先遍历所有想要获得的节点,并解析出来,然后做为属性绑定到输出对象上。
function bindAttr(element, names) {
var ele = !!element && typeof element === "string" ? document.getElementById(element) : element as HTMLElement;
if (!ele || !ele.tagName || !names) return undefined;
var obj: any = {};
names.forEach(function (attrName, i, arr) {
var attr = attr(element, attrName);
obj[attrName] = attr;
});
return obj;
}
接下来,我们要开始实现监听事件,并且其本身所需处理的事情与上面的有一些类似,由此一来,当 DOM 中的属性值变化后,会实时反应到返回对象上对应的属性的。
var listener = function (ev) {
var attrName = ev.attrName || ev.propertyName;
if (!attrName || !names || !names.some(function (name, ni, narr) {
return name === attrName;
})) return;
var attrObj = attr(element, attrName);
obj[attrName] = attrObj;
};
ele.addEventListener("DOMAttrModified", listener, false);
当然,这么做了之后,如果需要取消监听怎么办?于是我们想到可以在返回对象上加一个 dispose 方法来搞定;当然,你也可以取别的名字,但最好避免和 DOM 里可能会用到的属性名重名,也就是说前面加个下划线或者搞生僻一些;甚至是你可以把返回属性再包一层。但不管了,这里就用 dispose 方法来演示了。
obj.dispose = function () {
ele.removeEventListener("DOMAttrModified", listener, false);
};
好了,现在大功告成啦!或许你还可以再优化一下,比如我们加一个参数来控制是否需要监听变动什么的。最终,我们写好了如下完整函数。
/**
* Binds the objects parsed from specific attributes of an element to an object as its properties.
* @param element the element to get attribute.
* @param names the attribute name list.
* @param loadOnce true if just load once without attribute listening; otherwise, false.
*/
function bindAttr(element: HTMLElement | string, names: string[], loadOnce = false) {
var ele = !!element && typeof element === "string" ? document.getElementById(element) : element as HTMLElement;
if (!ele || !ele.tagName || !names) return undefined;
var obj: any = {};
names.forEach(function (attrName, i, arr) {
var attr = attr(element, attrName);
obj[attrName] = attr;
});
if (!loadOnce) {
var listener = function (ev) {
var attrName = ev.attrName || ev.propertyName;
if (!attrName || !names || !names.some(function (name, ni, narr) {
return name === attrName;
})) return;
var attrObj = attr(element, attrName);
obj[attrName] = attrObj;
};
ele.addEventListener("DOMAttrModified", listener, false);
obj.dispose = function () {
ele.removeEventListener("DOMAttrModified", listener, false);
};
}
return obj;
}
有没有觉得特别棒?
文章类型及复杂度:Web 进阶。
节选翻译自 MSDN 博文 Parse DOM attribute object,内容有所调整。
http://blogs.msdn.com/b/kingcean/archive/2016/03/18/parse-attribute-object-in-dom.aspx