#javascript #jquery #dom-traversal
#javascript #jquery #dom-обход
Вопрос:
Я пытаюсь закрыть родительский контейнер при нажатии внутренне вложенной кнопки. В моем пользовательском интерфейсе — у меня есть много таких родительских контейнеров (я отображаю окна предварительного просмотра моего каталога продуктов на странице категории продуктов).
Как вы можете видеть из моей разметки ниже — кнопка ЗАКРЫТИЯ глубоко вложена в DOM. Когда пользователь нажимает на кнопку ЗАКРЫТИЯ — мне нужно скрыть () родительское поле-1. Имейте в виду, что у меня может отображаться до 100 продуктов на странице (100 блоков «Box-1») одновременно.
Моя разметка выглядит следующим образом:
<div class="box-1">
<div class="box-2">
<div class="box-3">...</div> <!-- end box-3 -->
<div class="box-4">
<div class="box-5">...</div> <!-- end box-5 -->
<a class="btn-close" href="#">CLOSE</a> <!-- this triggers the close event -->
</div> <!-- end box-4 -->
</div> <!-- end box-2 -->
<div class="box-6">
<div class="box-7">...</div> <!-- end box-7 -->
<div class="box-8">
...
<div class="box-9">...</div> <!-- end box-9 -->
</div> <!-- end box-8 -->
</div> <!-- end box-6 -->
</div> <!-- end box-1 -->
Мой вопрос — как мне лучше всего (и наиболее эффективно) выполнить резервное копирование DOM, чтобы получить доступ к «box-1» и выполнить метод .hide() … вот мой существующий код.
<script>
$productsResultItems.delegate('.btn-close', 'click', function (e) {
//box-1
$(this).parents('div.box-1').hide(); // <-- is this the best way?????
e.preventDefault();
</script>
Изначально я пытался сделать это —
$this.parents().find('.hover-box-large').hide();
который оказался очень медленным в IE7 и IE8.
Я обнаружил, что добавление дополнительных деталей в селектор улучшило производительность почти в 100 раз для IE7, но только в 4 раза быстрее в IE8: (IE8 по-прежнему требует около 200 мс для закрытия родительского контейнера. Где сейчас все другие браузеры (Chrome, Safari, Firefox и IE7) закрывают контейнер менее чем за 20 мс.
$this.parents('div.hover-box-large').hide();
Но есть ли метод выбора, который еще лучше? Есть какая-то конкретная причина, по которой IE8 ооочень плох в этом типе обхода вверх??
Ответ №1:
Лучшим методом для использования является closest
, который находит ближайший элемент-предок, соответствующий селектору:
$this.closest('div.box-1').hide();
Комментарии:
1. Ребята, все три ответа верны. Мне предоставлен правильный ответ на lonesomeday, поскольку он / она пришел первым. Спасибо вам всем за вашу помощь. Использование ‘closest’ было отличным предложением. Это сократило время рендеринга IE8 вдвое!
Ответ №2:
На самом деле .closest()
должно быть быстрее, чем .parents()
.
В документах jQuery на .closest()
вы можете найти:
.closest()
- Начинается с текущего элемента
- Перемещается вверх по дереву DOM до тех пор, пока не найдет соответствие для предоставленного селектора
- Возвращаемый объект jQuery содержит ноль или один элемент
.parents()
- Начинается с родительского элемента
- Перемещается вверх по дереву DOM к корневому элементу документа, добавляя каждый элемент-предок во временную коллекцию; затем он фильтрует эту коллекцию на основе селектора, если таковой предоставлен
- Возвращаемый объект jQuery содержит ноль, один или несколько элементов
Итак, в вашем случае .closest()
был бы наиболее подходящим, поскольку вам нужно найти один элемент, ближайшего предка, который соответствует вашему селектору. parents()
отфильтровал бы все возможные элементы-предки, даже если он уже нашел тот, который вам нужен.
Ответ №3:
Единственное различие между parents() и closest() заключается в том, что closest() останавливается, как только найдено совпадение, поэтому всегда возвращает 0 или 1 элемент. Parents() сопоставит все в DOM.
$(this).closest('.box-1').hide();
Комментарии:
1. Спасибо, Джон — отличный краткий ответ — очень ценится. Это сократило время рендеринга IE8 вдвое!
Ответ №4:
Не так быстро! closest()
может быть лучшим, но не всегда! Вот как вы можете выяснить это сами. Используйте функции Firebug time() и timeEnd()Firebug, чтобы фактически регистрировать ваши вызовы. Затем выберите тот, который подходит для данной ситуации.
// 59ms
console.time("Parent x 3");
$container = $element.parent().parent().parent();
console.timeEnd("Parent x 3");
// 3ms
console.time("Closest parent");
$container = $element.closest('.some-class').parent();
console.timeEnd("Closest parent");
// 2ms
console.time("Parents");
$container = $element.parents('.other-class').eq(1);
console.timeEnd("Parents");
Комментарии:
1. 1 для тестирования в конкретных экземплярах; ваш собственный DOM может сильно повлиять на ситуацию.
console.time()
иconsole.timeEnd()
есть и в Chrome. Попробуйте также выполнить эти тесты в разных порядках: когда я тестирую.closest()
сначала, пять последовательных.parent()
вызовов выполняются так же быстро, но если я сначала протестирую.parent()
s, а затем.closest()
,closest()
тест занимает половину времени.