У меня есть div, который содержит некоторый контент, который добавляется и удаляется динамически, поэтому его высота часто меняется. У меня также есть div, который абсолютно позиционируется прямо под ним с помощью javascript, поэтому, если я не могу определить, когда изменяется высота div, я не могу переместить div под ним.
Итак, как я могу определить, когда изменяется высота этого div? Я предполагаю, что мне нужно использовать какое-то событие jQuery, но я не уверен, к какому из них подключиться.
@ user007 Что меняет размер ваших элементов?
@roasted моя высота div изменяется, когда к нему добавляется какой-то элемент, добавление выполняется jquery
@ user007, поэтому, когда вы добавляете что-то в DIV, вы можете инициировать настраиваемое событие изменения размера для DIV. Другой способ (худший IMO) может заключаться в использовании пользовательского метода для добавления контента, который просто расширяет собственный метод jquery append (), используйте его с обратным вызовом, например
@roasted Спасибо за подсказку.
Вы можете использовать событие DOMSubtreeModified
$(something).bind('DOMSubtreeModified' ...
Но это сработает, даже если размеры не изменятся, а переназначение позиции при срабатывании может снизить производительность. По моему опыту использования этого метода, проверка того, изменились ли размеры, менее затратна, поэтому вы можете подумать об их объединении.
Или, если вы напрямую изменяете div (а не изменяете div непредсказуемым образом, например, если он является contentEditable), вы можете просто запускать настраиваемое событие всякий раз, когда вы это делаете.
Оборотная сторона: IE и Opera не реализуют это событие.
IE и Opera не реализуют это событие: quirksmode.org/dom/events/index.html
DomSubtreeModified устарел
Современный способ сделать это - использовать MutationObserver: developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Есть плагин jQuery, который отлично справляется с этим.
http://www.jqui.net/jquery-projects/jquery-mutate-official/
вот его демонстрация с различными сценариями изменения высоты, если вы измените размер div с красной рамкой.
http://www.jqui.net/demo/mutate/
Это красиво, но разве он по умолчанию не опрашивает пользовательский интерфейс каждую миллисекунду на предмет изменений? Это эффективно?
@MichaelScottCuthbert Это было написано очень давно, но я использовал setTimeout
, так что это будет 1 мс + [время, необходимое для выполнения проверок] вкратце, но идея заключалась в том, чтобы постоянно слушать, как только вы снова его активируете, это как очередь. Я уверен, что смог бы сделать это намного лучше, но не так много времени.
Ах, да, я вижу, что вы были примерно за год до решения Vega (которое я в конечном итоге использовал) и до того, как все слушатели DOMSubtreeModified и т. д. Получили широкую поддержку. Я многому научился, читая ваш код, поэтому думаю, что стоит поддерживать ссылки.
Вот как я недавно справился с этой проблемой:
$('#your-resizing-div').bind('getheight', function() {
$('#your-resizing-div').height();
});
function your_function_to_load_content() {
/*whatever your thing does*/
$('#your-resizing-div').trigger('getheight');
}
Я знаю, что опаздываю на вечеринку на несколько лет, просто думаю, что мой ответ может помочь некоторым людям в будущем, без необходимости загружать какие-либо плагины.
Я думаю, что в некотором смысле это не лучший способ сделать это, но на самом деле мне он очень нравится, так как это означает, что вы можете запускать его как обратный вызов в конце анимации. Плагин изменения размера будет продолжать работать на протяжении всей анимации, что может быть полезно, но также может вызвать проблемы. Этот метод, по крайней мере, дает вам контроль над тем, когда запускать проверку высоты.
Что именно делает ваш код? Почему мы не можем просто использовать код, который вы пишете внутри события привязки, в функции привязки и запуска?
Но это не происходит автоматически, не так ли?
В ответ на user007:
Если высота вашего элемента изменяется из-за добавления к нему элементов с помощью .append()
, вам не нужно обнаруживать изменение высоты. Просто добавьте репозицию вашего второго элемента в ту же функцию, в которой вы добавляете новый контент к своему первому элементу.
Как в:
$('.class1').click(function () {
$('.class1').append("<div class='newClass'><h1>This is some content</h1></div>");
$('.class2').css('top', $('.class1').offset().top + $('.class1').outerHeight());
});
Некоторое время назад я написал плагин для слушателя attrchange, который в основном добавляет функцию слушателя при изменении атрибута. Хотя я говорю это как плагин, на самом деле это простая функция, написанная как плагин jQuery ... так что, если вы хотите ... удалите специальный код плагина и используйте основные функции.
Примечание: этот код не использует опрос
посмотрите эту простую демонстрацию http://jsfiddle.net/aD49d/
$(function () {
var prevHeight = $('#test').height();
$('#test').attrchange({
callback: function (e) {
var curHeight = $(this).height();
if (prevHeight !== curHeight) {
$('#logger').text('height changed from ' + prevHeight + ' to ' + curHeight);
prevHeight = curHeight;
}
}
}).resizable();
});
Страница плагина:http://meetselva.github.io/attrchange/
Минифицированная версия: (1.68кб)
(function(e){function t(){var e=document.createElement("p");var t=false;if (e.addEventListener)e.addEventListener("DOMAttrModified",function(){t=true},false);else if (e.attachEvent)e.attachEvent("onDOMAttrModified",function(){t=true});else return false;e.setAttribute("id","target");return t}function n(t,n){if (t){var r=this.data("attr-old-value");if (n.attributeName.indexOf("style")>=0){if (!r["style"])r["style"] = {};var i=n.attributeName.split(".");n.attributeName=i[0];n.oldValue=r["style"][i[1]];n.newValue=i[1]+":"+this.prop("style")[e.camelCase(i[1])];r["style"][i[1]]=n.newValue}else{n.oldValue=r[n.attributeName];n.newValue=this.attr(n.attributeName);r[n.attributeName]=n.newValue}this.data("attr-old-value",r)}}var r=window.MutationObserver||window.WebKitMutationObserver;e.fn.attrchange=function(i){var s = {trackValues:false,callback:e.noop};if (typeof i== = "function"){s.callback=i}else{e.extend(s,i)}if (s.trackValues){e(this).each(function(t,n){var r = {};for(var i,t=0,s=n.attributes,o=s.length;t<o;t++){i=s.item(t);r[i.nodeName]=i.value}e(this).data("attr-old-value",r)})}if (r){var o = {subtree:false,attributes:true,attributeOldValue:s.trackValues};var u=new r(function(t){t.forEach(function(t){var n=t.target;if (s.trackValues){t.newValue=e(n).attr(t.attributeName)}s.callback.call(n,t)})});return this.each(function(){u.observe(this,o)})}else if (t()){return this.on("DOMAttrModified",function(e){if (e.originalEvent)e=e.originalEvent;e.attributeName=e.attrName;e.oldValue=e.prevValue;s.callback.call(this,e)})}else if ("onpropertychange"in document.body){return this.on("propertychange",function(t){t.attributeName=window.event.propertyName;n.call(e(this),s.trackValues,t);s.callback.call(this,t)})}return this}})(jQuery)
Это решает проблему, если вы изменяете размер div вручную, это не решает исходный вопрос, нет? Если вы добавляете контент динамически, изменение высоты не обнаруживается: jsfiddle.net/aD49d/25
Мне также было бы интересно узнать, есть ли способ заставить эту работу работать с динамическим контентом.
@JoeCoder Этот код attrchange полагается на события DOM, запускаемые браузером, когда есть действие пользователя. Однако динамическое содержимое в этом примере включено программно, что, к сожалению, не вызывает никаких событий. «Опрос» кажется здесь еще одним более простым вариантом ... другой вариант можно было бы запускать вручную после включения динамического содержимого.
Используйте датчик изменения размера из библиотеки css-element-query:
https://github.com/marcj/css-element-queries
new ResizeSensor(jQuery('#myElement'), function() {
console.info('myelement has been resized');
});
Он использует подход, основанный на событиях, и не тратит время процессора. Работает во всех браузерах, в т.ч. IE7 +.
хорошее решение, он использует невидимый новый элемент в качестве наложения на желаемую цель и использует событие «прокрутки» на наложении, чтобы инициировать изменения.
Это единственное решение, которое работает во всех случаях, в том числе когда содержимое и атрибуты не меняются, а размеры меняются (пример: процентные измерения с использованием CSS)
Лучшее решение на сегодняшний день.
Это не самый популярный ответ - трагедия. Это действительно работает на 100%.
Похоже, это не работает для элементов, которые начинаются как скрытые.
Я пробовал это, и он отлично работает, но мне нужно прикрепить это событие к нескольким элементам, а затем получить дескриптор целевого элемента внутри моей функции обратного вызова, пожалуйста, дайте мне несколько указателей относительно того, как этого добиться. Спасибо !
This doesn't seem to work for elements which start off hidden
Тем временем работает с v1.0.5.
Вы можете использовать класс MutationObserver
.
MutationObserver
предоставляет разработчикам способ реагировать на изменения в DOM. Он разработан как замена для событий мутации, определенных в спецификации событий DOM3.
Пример (источник)
// select the target node
var target = document.querySelector('#some-id');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.info(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
Это правильный ответ. Также обратите внимание на MutationSummary, библиотеку, основанную на MutationObservers: github.com/rafaelw/mutation-summary
Вы можете сделать простой setInterval.
function someJsClass()
{
var _resizeInterval = null;
var _lastHeight = 0;
var _lastWidth = 0;
this.Initialize = function(){
var _resizeInterval = setInterval(_resizeIntervalTick, 200);
};
this.Stop = function(){
if (_resizeInterval != null)
clearInterval(_resizeInterval);
};
var _resizeIntervalTick = function () {
if ($(yourDiv).width() != _lastWidth || $(yourDiv).height() != _lastHeight) {
_lastWidth = $(contentBox).width();
_lastHeight = $(contentBox).height();
DoWhatYouWantWhenTheSizeChange();
}
};
}
var class = new someJsClass();
class.Initialize();
Обновлено:
Это пример с классом. Но вы можете сделать что-нибудь простое.
Вы можете использовать это, но он поддерживает только Firefox и Chrome.
$(element).bind('DOMSubtreeModified', function () {
var $this = this;
var updateHeight = function () {
var Height = $($this).height();
console.info(Height);
};
setTimeout(updateHeight, 2000);
});
Довольно простой, но работает:
function dynamicHeight() {
var height = jQuery('').height();
jQuery('.edito-wrapper').css('height', editoHeight);
}
editoHeightSize();
jQuery(window).resize(function () {
editoHeightSize();
});
это будет запущено только в том случае, если размер окна изменится, но OP хочет привязать событие изменения размера к определенному контейнеру
Интересно, почему бы не использовать плагин при использовании jQuery.