Доступ к элементу после модификации HTML inner и outer
В общем пилил запиливатель красивых элементов форм на чистом JS и нашел угарный баг браузеров.
Lets look: let test = document.querySelectorAll('#tabs'); test[0].parentElement.parentElement.outerHTML = '<div class="zalupa">'+ test[0].parentElement.parentElement.outerHTML +'</div>'; console.log( document.querySelectorAll('#logotype')[0].closest('#mainHeader') ); // work console.log( test[0].parentElement.parentElement.parentElement ); // zalupa null console.log( test[0].closest('.zalupa') ); // zalupa null <div id="shell"> <header id="mainHeader"> <h1 id="logotype"> <a href="#" data-title="and add">adds</a> :: <span>asdasdasdsad</span></h1> </header> </div><!--#shell--> <div id="testElements"> <section style="text-align: center; width: 980px; margin: 0 auto"> <aside id="tabs" class="tabs"> <ul> <li data-link="tab-1">1</li> <li class="activetab" data-link="tab-2">2</li> <li data-link="tab-3">3</li> </ul> <div data-content="tab-1">Tous mes rêves se réalisent.</div> <div class="tabactive" data-content="tab-2">Si on vit sans but, on mourra pour rien.</div> <div data-content="tab-3">Jouis de chaque moment.</div> </aside> </section> </div> В общем долго не понимал почему нет доступа к залупе :haha: и почему у меня не работает unwrap . Оказывается залупа не добавляется в какой-то там node-list и приходится каждый раз получать через querySelector. И тогда я решил создавать залупу не строчно, но c помощью запиленной в браузер функциональности: let test = document.querySelectorAll('#tabs'); let zalupa = document.createElement('div'); zalupa.classList.add('zalupa'); zalupa.innerHTML = test[0].parentElement.parentElement.outerHTML; test[0].parentElement.parentElement.outerHTML = zalupa.outerHTML console.log(test[0].closest('.zalupa')); // zalupa null Таким образом выяснилось, что даже так залупа не появляется, а кроме innerHTML и outerHTML я средств манипуляции содержимым не знаю. Может кто-то знает более изящный и простой способ манипулировать такими данными, чтобы они потом были доступны в next, previous node list и конечно closest или parentElement? Не охота мне писать createElement вообще ибо это расточительство. |
Цитата:
В первом варианте вы сохраняете в переменную test ссылку на DOM элемент, после изменяете outerHTML родителя. После внесения изменений ветка измененного родителя "перестраивается" и ваш test указывает уже на несуществующий элемент. Во втором случае все почти тоже самое, только вы родителю "скармливаете" outerHTML виртуального DOM элемента. |
Nexus, так а решить то как по другому?
|
Цитата:
|
Если не менять логику с элементами, то можно вот так
var test = document.querySelectorAll('#tabs'); var parent = test[0].parentElement.parentElement; var newParent = document.createElement('div'); newParent.className = 'zalupa'; parent.parentNode.replaceChild(newParent, parent); newParent.appendChild(parent); при этом все объекты-элементы сохраняются. |
Alexandroppolus, хм тоже выход оказывается. Но к сожалению не получается сделать без обезьяньих скачек по дереву разными методами.
|
xShift, потому что нужно правильно оформлять HTML разметку, чтобы было удобно манипулировать DOM-элементами. Лично у меня, таких извращений не было с элементами, хотя я миллион раз писал различные модули табов, форм, модалок и т.д., на чистом JS. Просто пересмотрите свой подход. Даже не могу представить, в каком случае и при каком действии может понадобиться обернуть элемент в другой. Разметка должна быть строгой, а для манимуляции с DOM - вполне должно быть достаточно добавление/удаление новых элементов в каком-либо блоке, или изменение className. Все эти методы, типа wrap и т.д. - это чистой воды извращение, такого быть не должно и не должно возникать такой нужды при грамотном подходе к разметке и скриптингу в целом!
|
ruslan_mart, окей, пишем стилизатор select. Как вы без замены стандартных options и их контейнера это сделаете без wrap. Вы конечно правы но бывают ситуации , когда в движек лезти и менять разметку нецелесообразно.
|
Цитата:
|
Nexus, и будете как обезьяна по next prev скакать чтобы selected отметить? Форма то должна работать потом а не просто для красоты.
|
xShift, что мешает объявить селекту id (или data-id) и обращаться к нему по id?
Желание спорить отсутствует. |
Nexus, у меня тоже нету. Но того требует не только быстрый доступ к свойствам, а хотя бы сущность к примеру БЕМ методологии или OOCSS, который мне в последнее время не нравится изза размножения id. Так удобнее изолировать стили от pre defined и задавать свои политики отображения. Что вы будете горбатого лепить аля замена + оригинал вместо оборачивания?
|
xShift, положите ссылку на селект в свойство класса-кастомизатора.
|
Ну обычно ссылка на select может храниться где-то в замыкании или в контексте, смотря какая реализация. А обращаться постоянно к элементам через getElemetns*/querySelector, ну или тому подобные - методика для быдлокодеров, аля jQuery головного мозга. Я вообще не признаю innerHTML для перезаписи элементов, а outerHTML уж тем более, это слишком как-то маньячно.
|
ruslan_mart, а unwrap/wrap это не маньячно?
К примеру: for(let i of e) { let parent = i.parentElement; while (i.firstChild) { parent.insertBefore(i.firstChild, i); } parent.removeChild(i); } против i.outerHTML = '<div class="wrapper">'+ i.outerHTML +'</div>'; Я просто как-то элегантнее не видел. Ладно уж parentElement может перестроиться, но closest обязан работать, чтобы не было таких вот while головного мозга. > querySelector для быдлокодеров Не правда. Очень крутая фишка, о которой вы возможно не знали это поиск в элементе другого элемента. Это и было круто в jQuery $('.some', '.some-wrapper') - оно отсекало все ненужное. Но jQuery и сам Sizzle стали не нужна когда появился querySelectorAll. То же самое: let element = document.querySelectorAll('#shell'); element[0].querySelectorAll('.somethin-in-shell'); или еще прикольнее: let element = document.querySelectorAll('#shell'); element[0].querySelectorAll('*'); // вообще все что внутри И тогда не понятно как вы их умудряетесь получать? везде тыкаете id а потом прямо пишете для div#shell обращение типа shell.dataset.shit-code = 'ololo'; ? Без этих остается только прямое обращение к объекту в window ... |
Цитата:
|
j0hnik, оберта в функцию + callback перезапускающий ее(нагрузки там не много - процессор этим не сожрет и память). я вот кстати промисы не люблю.
|
Цитата:
var elem = document.querySelector('#id1'); var range = document.createRange(); range.selectNodeContents(elem); elem.parentNode.replaceChild(range.extractContents(), elem); это unwrap, то что у тебя в цикле. Собственно, вытаскиваем весь контент из элемента, и заменяем элемент на него. Два изменения дома - вытаскивание контента и замена. wrap аналогично. outerHTML/innerHTML тут нафиг не нужен. матчасцъ - https://learn.javascript.ru/range-textrange-selection |
xShift, про querySelector я другое имел ввиду.. Что получать один и тот же элемент через querySelector при каком-либо событии - не есть хорошо. Если Вы создаёте какой-то модуль/плагин, то у Вас должна быть инициализация на динамическом уровне, а не на уровне получения элементов "туда-сюда" из вёрстки.
Цитата:
Не нужны никакие id при правильном подходе. Если Вы создаёте элемент или дерево элементов, то уже знаете об этом элементе. this.wrapper = document.createElement('div'); this.wrapper //-> вот она, ссылка на элемент. Всё что касается innerHTML/outerHTML - это безусловно нужные вещи, но при написании модулей/плагинов использовать это будет не совсем грамотно. Вернёмся к теме jQuery или querySelector. Вот типичный пример быдлокода: document.querySelector('#button').onclick = function() { document.querySelectorAll('.foo .bar')[0].style.display = 'none'; }; //Не правильно $('#button').on('click', function() { $('.block-1').css('display', 'block'); $('.block-1').css('color', 'red'); $('.block-2').html('Bla'); }); //Правильно var block_1 = $('.block-1'), block_2 = $('.block-2'); $('#button').on('click', function() { block_1.css({display: 'block', color: 'red'}); block_2.html('Bla'); }); |
Цитата:
1. id уникален, он должен быть только один на странице. Следовательно, запись document.querySelectorAll('#shell') не имеет смысла, так как мы хотим получить один единственный элемент, а не коллекцию. Получается, что лучше тогда использовать document.querySelector (без "All"), но опять же, куда быстрее и правильней будет заюзать document.getElementById. 2. Нет смысла в два шага искать элементы с определённым классом внутри элемента с определённым id. Можно сразу: document.querySelectorAll('#shell .somethin-in-shell') Но это если конечно Вам не нужны оба элемента. |
Alexandroppolus, в этом году не смотрел, но в прошлом году вот replace child имел своеобразные глюки в сафари. А про range не знал. Возможно полезно, но я даже не смотря на казалось бы более правильный подход пользоваться этим не буду никогда. Какая-то лишняя ненужна абстракция. От того еще один querySelector появится никто не умрет.
Я щас проще к Safari загляну и предложу исправить данный недочет с обновлением узлов в closest. После этого все автоматически справится в Chrome, Yandex браузере, куче поделок из хромиума и возможно даже повлияет на FF потому что Safari разработчики первоисходных стандартов. Они это быстрее решают. Я год ждал ответа от MS по поводу бага в Edge. Они только недавно отписались и приняли статус issue. Это конечно хорошо, но не правильно(если есть недоработки их не надо игнорировать путем выворачивания вселенной на изнанку). Наелись с IE - хватит. Щас еще андроида придется за это же убивать, но это уже другая история. Даже если рассматривать Ваш пример, то тут очень много противоречий. 1. id уникален, он должен быть только один на странице. Следовательно, запись document.querySelectorAll('#shell') не имеет смысла, так как мы хотим получить один единственный элемент, а не коллекцию. Получается, что лучше тогда использовать document.querySelector (без "All"), но опять же, куда быстрее и правильней будет заюзать document.getElementById. 2. Нет смысла в два шага искать элементы с определённым классом внутри элемента с определённым id. Можно сразу: document.querySelectorAll('#shell .somethin-in-shell') Но это если конечно Вам не нужны оба элемента. ruslan_mart, All у меня везде используется потому что я себе библиотеку написал которая сразу коллекциями работает, а не по одному элементу. Мне на эти копейки пофиг экномии. By id. by class, tag name - это устаревшее барахло по моему. Опять же экономить на спичках, когда можно прикуривать шикарной Zippo. |
Часовой пояс GMT +3, время: 06:16. |