Каков наиболее эффективный способ перехода вверх в jQuery

#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() тест занимает половину времени.