我需要使用innerHTML动态更改每个节点上设置的值。
我找到的最接近的解决方案是:
...
Object.defineProperty(Element.prototype, 'innerHTML', {
set: function () {
// get value (ok)
var value = arguments[0];
// change it (ok)
var new_value = my_function(value);
// set it (problem)
this.innerHTML = new_value; // LOOP
}
}
...
但显然它是一个无限循环。 有没有办法调用原始的innerHTML集?
我也尝试Proxy way,但我无法使其发挥作用。
更多详情:
我正在开发一个实验项目,该项目使用反向代理生成CSP策略并将其添加到网站,所以:
答案 0 :(得分:5)
强制警告:
在任何生产级代码中,覆盖Element.prototype
的任何属性的setter和getter都是坏主意。如果您使用任何依赖innerHTML
的库来工作,或者项目中有其他开发人员不知道这些更改,那么事情可能会变得奇怪。您还将失去在应用程序的其他部分使用innerHTML
“正常”的能力。
那就是说,由于你没有提供任何关于为什么你想要这样做的信息,我只是假设你知道这些警告,你仍然想要覆盖浏览器自身的功能,可能用于开发目的。
解决方案:您正在覆盖浏览器Element.prototype.innerHTML
的原生设置器,但您还需要原始设置器才能实现目标。这可以使用Object.getOwnPropertyDescriptor来完成,http://thbecker.net/articles/auto_and_decltype/section_07.html是Object.defineProperty
的“对应”。
(function() {
//Store the original "hidden" getter and setter functions from Element.prototype
//using Object.getOwnPropertyDescriptor
var originalSet = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set;
Object.defineProperty(Element.prototype, 'innerHTML', {
set: function (value) {
// change it (ok)
var new_value = my_function(value);
//Call the original setter
return originalSet.call(this, new_value);
}
});
function my_function(value) {
//Do whatever you want here
return value + ' World!';
}
})();
//Test
document.getElementById('test').innerHTML = 'Hello';
<div id="test"></div>
答案 1 :(得分:1)
使用任意HTML字符串没有直接的方法,没有。
问题是您使用任意HTML字符串。目前在元素上设置任意HTML的唯一方法是使用innerHTML
。您必须找到一种在元素上设置任意HTML的不同方法,例如将HTML附加到临时节点并抓取其内容:
// Attempt: build a temporary element, append the HTML to it,
// then grab the contents
var div = document.createElement( 'div' );
div.innerHTML = new_value;
var elements = div.childNodes;
for( var i = 0; i < elements.length; i++ ) {
this.appendChild( elements[ i ] );
}
然而,这会遇到同样的问题,div.innerHTML = new_value;
会永远递归,因为您正在修改任意HTML设置的唯一入口点。
我能想到的唯一解决方案是实现一个真正的,完整的HTML解析器,它可以使用任意HTML字符串并将其转换为带有document.createElement('p')
等内容的DOM节点,然后您可以附加到当前元素appendChild
。然而,这将是一个可怕的,过度设计的解决方案。
除此之外,你不应该这样做。这段代码将毁掉某人的一天。它违反了我们在前端开发中所欣赏的几个原则:
innerHTML
劫持。最干净的解决方案可能就是在您需要的任何地方使用my_function
。它的可读性,简短,简单,香草编程:
someElement.innerHTML = my_function(value);
您也可以定义一个方法(我会对属性进行方法,因为它会破坏用户的值),例如:
Element.prototype.setUpdatedHTML = function(html) {
this.innerHTML = my_function(html);
}
这样当开发人员遇到setUpdatedHTML
时,它显然是非标准的,他们可以更容易地寻找劫持Element原型的人。