Определить, был ли элемент изменен с помощью javascript?
Можно ли просто добавить прослушиватели событий к определенным элементам, чтобы определить, были ли изменены их высота или ширина? Я бы хотел сделать это, не используя что-то интенсивное, например:
$(window).resize(function() { ... });
В идеале я хотел бы привязываться к определенным элементам:
$("#primaryContent p").resize(function() { ... });
Кажется, что использование обработчика изменения размера в окне - единственное решение, но это похоже на излишний. Он также не учитывает ситуации, когда размеры элемента изменяются программно.
Ответы
Ответ 1
Здесь плагин jQuery с методами watch
и unwatch
, которые могут просматривать определенные свойства элемента. Он вызывается как метод объекта jQuery. Он использует встроенные функции в браузерах, которые возвращают события при изменении DOM, и использует setTimeout()
для браузеров, которые не поддерживают эти события.
Общий синтаксис функции watch
приведен ниже:
$("selector here").watch(props, func, interval, id);
-
props
представляет собой разделенную запятыми строку свойств, которые вы хотите
(например, "width,height"
).
-
func
- это функция обратного вызова, переданная параметрами watchData, index
, где watchData
относится к объекту формы { id: itId, props: [], func: func, vals: [] }
, а index
- индекс измененного свойства. this
относится к измененному элементу.
-
interval
- это интервал в миллисекундах для setInterval()
в браузерах, которые не поддерживают просмотр свойств в DOM.
-
id
- это необязательный идентификатор, который идентифицирует этого наблюдателя и используется для удаления определенного наблюдателя из объекта jQuery.
Общий синтаксис функции unwatch
приведен ниже:
$("selector here").unwatch(id);
-
id
- необязательный идентификатор, который идентифицирует этот наблюдатель для удаления. Если id
не указан, все наблюдатели от объекта будут удалены.
Для тех, кому интересно, код плагина воспроизводится ниже:
$.fn.watch = function(props, func, interval, id) {
/// <summary>
/// Allows you to monitor changes in a specific
/// CSS property of an element by polling the value.
/// when the value changes a function is called.
/// The function called is called in the context
/// of the selected element (ie. this)
/// </summary>
/// <param name="prop" type="String">CSS Property to watch. If not specified (null) code is called on interval</param>
/// <param name="func" type="Function">
/// Function called when the value has changed.
/// </param>
/// <param name="func" type="Function">
/// optional id that identifies this watch instance. Use if
/// if you have multiple properties you're watching.
/// </param>
/// <param name="id" type="String">A unique ID that identifies this watch instance on this element</param>
/// <returns type="jQuery" />
if (!interval)
interval = 200;
if (!id)
id = "_watcher";
return this.each(function() {
var _t = this;
var el = $(this);
var fnc = function() { __watcher.call(_t, id) };
var itId = null;
if (typeof (this.onpropertychange) == "object")
el.bind("propertychange." + id, fnc);
else if ($.browser.mozilla)
el.bind("DOMAttrModified." + id, fnc);
else
itId = setInterval(fnc, interval);
var data = { id: itId,
props: props.split(","),
func: func,
vals: []
};
$.each(data.props, function(i) { data.vals[i] = el.css(data.props[i]); });
el.data(id, data);
});
function __watcher(id) {
var el = $(this);
var w = el.data(id);
var changed = false;
var i = 0;
for (i; i < w.props.length; i++) {
var newVal = el.css(w.props[i]);
if (w.vals[i] != newVal) {
w.vals[i] = newVal;
changed = true;
break;
}
}
if (changed && w.func) {
var _t = this;
w.func.call(_t, w, i)
}
}
}
$.fn.unwatch = function(id) {
this.each(function() {
var w = $(this).data(id);
var el = $(this);
el.removeData();
if (typeof (this.onpropertychange) == "object")
el.unbind("propertychange." + id, fnc);
else if ($.browser.mozilla)
el.unbind("DOMAttrModified." + id, fnc);
else
clearInterval(w.id);
});
return this;
}
Ответ 2
Я просто придумал чисто основанный на события способ определения размера элемента для любого элемента, который может содержать детей, я вставил код из нижеприведенного решения.
См. также исходное сообщение в блоге, в котором есть некоторые исторические данные. Предыдущие версии этого ответа основывались на предыдущей версии сообщения в блоге.
Ниже приведен JavaScript, для которого требуется включить прослушивание событий изменения размера.
(function(){
var attachEvent = document.attachEvent;
var isIE = navigator.userAgent.match(/Trident/);
var requestFrame = (function(){
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
function(fn){ return window.setTimeout(fn, 20); };
return function(fn){ return raf(fn); };
})();
var cancelFrame = (function(){
var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
window.clearTimeout;
return function(id){ return cancel(id); };
})();
function resizeListener(e){
var win = e.target || e.srcElement;
if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
win.__resizeRAF__ = requestFrame(function(){
var trigger = win.__resizeTrigger__;
trigger.__resizeListeners__.forEach(function(fn){
fn.call(trigger, e);
});
});
}
function objectLoad(e){
this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
this.contentDocument.defaultView.addEventListener('resize', resizeListener);
}
window.addResizeListener = function(element, fn){
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
if (attachEvent) {
element.__resizeTrigger__ = element;
element.attachEvent('onresize', resizeListener);
}
else {
if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
var obj = element.__resizeTrigger__ = document.createElement('object');
obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
obj.__resizeElement__ = element;
obj.onload = objectLoad;
obj.type = 'text/html';
if (isIE) element.appendChild(obj);
obj.data = 'about:blank';
if (!isIE) element.appendChild(obj);
}
}
element.__resizeListeners__.push(fn);
};
window.removeResizeListener = function(element, fn){
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
if (attachEvent) element.detachEvent('onresize', resizeListener);
else {
element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
}
}
}
})();
Использование
Здесь используется псевдокод для этого решения:
var myElement = document.getElementById('my_element'),
myResizeFn = function(){
/* do something on resize */
};
addResizeListener(myElement, myResizeFn);
removeResizeListener(myElement, myResizeFn);
Demo
http://www.backalleycoder.com/resize-demo.html
Ответ 3
Да, это возможно. Вам нужно будет отслеживать все элементы при загрузке и хранить их. Вы можете попробовать демо here
. В нем вам не нужно использовать какие-либо библиотеки, но я использовал jQuery только для того, чтобы быть быстрее.
Первое, что нужно сначала - сохранить их начальный размер
Вы можете сделать это, используя этот метод:
var state = []; //Create an public (not necessary) array to store sizes.
$(window).load(function() {
$("*").each(function() {
var arr = [];
arr[0] = this
arr[1] = this.offsetWidth;
arr[2] = this.offsetHeight;
state[state.length] = arr; //Store all elements' initial size
});
});
Опять же, я использовал jQuery, чтобы быть быстрым.
Вторые - Проверьте!
Конечно, вам нужно будет проверить, было ли изменено:
function checksize(ele) {
for (var i = 0; i < state.length; i++) { //Search through your "database"
if (state[i][0] == ele) {
if (state[i][1] == ele.offsetWidth && state[i][2] == ele.offsetHeight) {
return false
} else {
return true
}
}
}
}
Просто он вернет false
, если он не изменился, true
, если он был изменен.
Надеюсь, это поможет вам!
Демо: http://jsfiddle.net/DerekL/6Evk6/