среда, 5 июня 2019 г.

Javascript: поиск по селектору может работать неправильно с вложенными элементами

Отвечал недавно на вопрос "А что это тут у меня в браузере кнопки так странно разъехались? Обычно не разъезжаются, а тут вдруг разъехались..."
Оказалось что разъезжаются в конфигурации, когда один toolbar вложен в другой как один из его элементов:

<div class="toolbar">
      <div class="toolbar-items">
          <div class="toolbar">
              <div class="toolbar-items">
                  <div>some text</div>

(GDPR: конфигурация конечно упрощенная, в таком виде выглядит как "дурацкая" и "это никто никогда не будет настраивать", но вот кто-то настроил, и для сценария автора я и сам настроил бы именно такую конфигурацию).

Покопался как все работает и оказалось, что элементы в toolbox добавляет такой код:

    container = this.find(".toolbar-items");
    item.appendTo(container);

Этот код ищет элемент DOM, в который будет добавлен очередной toolbar item.
Такое использование $.find() для поиска дочернего элемента будет неправильно работать на элементах, которые вложены друг в друга как в этой конфигурации: $.find для внешнего элемента возвращает 2 элемента (свой и еще один из вложенного toolbox) и с jQuery кнопка добавляется во второй (где-то там внутри append есть for(..), который добавит item в каждый container, в результате item останется в последнем).

Покопался еще и оказалось что без jQuery ничего не разъезжается... Оказалось, что jQuery может быть заменен на другую реализацию и в ней выполняется примерно такой код:

    insertElement(container[0], element);

Он добавляет элемент только в первый элемент из коллекции, но такое добавление тоже будет неверным, если нужный элемент оказался вторым, просто в другом исходном раскладе: для рекурсивного поиска по дереву есть и алгоритмы с результатом элементов в другом порядке.

В этой конфигурации вместо find можно использовать прямую ссылку на нужный элемент, например так:

    container = this.this[".toolbar-items"];
    item.appendTo(container);

Так я и сделал.

Комментариев нет:

Отправить комментарий