一个元素有一个 javascriptstyle
对象,其中包含 css 样式的不同名称和值。我想在不使用 polling 的情况下每次更改此对象时触发一个函数。有没有办法以跨浏览器兼容的方式做到这一点,并且可以可靠地与第三方代码一起工作(因为假设您正在提供一个插入式脚本)?绑定一个 javascript 事件就像DOMAttrModified
或DOMSubtreeModified
不够,因为它们在 Chrome 中不起作用。
6 回答
编辑 4:现场演示
$(function() {
$('#toggleColor').on('click', function() {
$(this).toggleClass('darkblue');
}).attrchange({
trackValues: true,
callback: function(event) {
$(this).html("<ul><li><span>Attribute Name: </span>" + event.attributeName + "</li><li><span>Old Value: </span>" + event.oldValue + "</li><li><span>New Value: </span>" + event.newValue + "</li></ul>");
}
});
});
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
}
#toggleColor {
height: 70px;
width: 300px;
padding: 5px;
border: 1px solid #c2c2c2;
background-color: #DBEAF9;
}
#toggleColor span {
font-weight: bold;
}
#toggleColor.darkblue {
background-color: #1A9ADA;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://meetselva.github.io/attrchange/javascripts/attrchange.js"></script>
<p>Click below div to toggle class darkblue.</p>
<div id="toggleColor"></div>
编辑 3:我将所有这些放在一起作为一个插件,可以从 git attrchange下载,这里是演示页面。
编辑2:
- 修复 IE7 和 IE8 中的属性名称
编辑1:
- 处理多个元素
- 将条件排序为 MutationObserver、DOMAttrModified 和 onpropertychange 以便更好地实现。
- 在回调中添加了修改后的属性名称。
感谢@benvie 的反馈。
演示: http: //jsfiddle.net/zFVyv/10/(在 FF 12、Chrome 19 和 IE 7 中测试。)
$(function() {
(function($) {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
function isDOMAttrModifiedSupported() {
var p = document.createElement('p');
var flag = false;
if (p.addEventListener) p.addEventListener('DOMAttrModified', function() {
flag = true
}, false);
else if (p.attachEvent) p.attachEvent('onDOMAttrModified', function() {
flag = true
});
else return false;
p.setAttribute('id', 'target');
return flag;
}
$.fn.attrchange = function(callback) {
if (MutationObserver) {
var options = {
subtree: false,
attributes: true
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(e) {
callback.call(e.target, e.attributeName);
});
});
return this.each(function() {
observer.observe(this, options);
});
} else if (isDOMAttrModifiedSupported()) {
return this.on('DOMAttrModified', function(e) {
callback.call(this, e.attrName);
});
} else if ('onpropertychange' in document.body) {
return this.on('propertychange', function(e) {
callback.call(this, window.event.propertyName);
});
}
}
})(jQuery);
$('.test').attrchange(function(attrName) {
alert('Attribute: ' + attrName + ' modified ');
}).css('height', 100);
});
参考:
- 检测是否支持 DOMAttrModified
- DOMAttrModified for chrome
- 突变观察者
- 为什么我们应该避免使用 Mutation 事件?
- onPropertyChange IE
Mutation Observers 是 DOM4 中突变事件的提议替代品。预计它们将包含在 Firefox 14 和 Chrome 18 中
浏览器支持:
onpropertychange
- 在 IE 中受支持(在 IE 7 中测试)
DOMAttrModified
- 在 IE 9、FF 和 Opera 中受支持
MutationObservers
- 非常新,在Chrome 18中运行良好。不确定它支持多远,尚未在 Safari 中进行测试。
感谢@benvie添加有关 WebkitMutationObserver 的信息
编辑2:
如果您仍想使用mutation observer
,请使用此库:mutation-summary
编辑:
正如我在下面的回答中所说,并感谢 Vega 的评论,使用诸如object.watch
或mutation observers
不建议在大型应用程序中使用之类的东西。这是来自MDN的实际报价:
一般来说,你应该尽可能避免使用
watch()
andunwatch()
。这两种方法仅在 Gecko 中实现,主要用于调试。此外,使用观察点 对性能有严重的负面影响,尤其是在全局对象上使用时尤其如此,例如窗口。您通常可以改用 setter和getter或代理。有关详细信息,请参阅兼容性。警告
因此,如果跨浏览器兼容性在您的检查列表中,我再次强烈建议覆盖对象setter
的 s 和getter
s style
。
使用
object.watch
并牢记这些跨浏览器解决方案:
- Javascript Object.Watch 适用于所有浏览器?
- object.watch polyfill
- Watch for object properties changes in JavaScript
You may override getter
and setter
methods of element's style
object too.
There is a jQuery plugin available for this, jQuery watch
I have found this little plugin that does exactly that and it can be changed to add any mutation you wish... Even scrollHeight change listener.
The plugin: http://www.jqui.net/jquery-projects/jquery-mutate-official/
here is the demo: http://www.jqui.net/demo/mutate/
即使对于所有最现代的浏览器,也没有跨浏览器的方式来实现这一点。您必须通过一个可以触发事件侦听器的函数来路由所有 css 样式更改。这将是最干净的方法。
In an answer to a similar question, it was suggested that if you know that style-setting interactions would be performed via a standard interface (i.e. always using jQuery etc.) it was suggested that custom events be fired whenever the library method is called.
This would allow for a broader support matrix but would leave any property change ignored if performed without using the library method. It also appears that such an approach is not applicable to native setters as they cannot always be relied on.
You can use attrchange jQuery plugin. The main function of the plugin is to bind a listener function on attribute change of HTML elements.