Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Изменение DOM с помощью innerHTML (https://javascript.ru/forum/misc/64792-izmenenie-dom-s-pomoshhyu-innerhtml.html)

moron 05.09.2016 18:49

Изменение DOM с помощью innerHTML
 
Здраствуйте.
Получилось, что из-за собственных пробелах в знаниях я долго бился с неочевидным(возможно лишь для меня) поведением.
Опытным путем мне удалось найти источник проблемы. Проблема была в добавлении элементов дом с помощью innerHTML: после добавление таким способом к полученным ранее элементам с помощью jQuery не работали методы insertAfter или просто after(возможно не работало вообще все. Вплоть до изменение стилей).
Я сделал небольшое демо и 2 вариации.
Есть контенер с двумя типами элеметов(.b и .a). В .a примешиваются элементы .b с некоторым шансом.
Перед самим примешиванием я добавляю еще один .b элемент(разными спобами) и в варианте с innerHTML потом не могу работать с ранее полученными элементами. Если вставка через append(понятно, что метод append jquery вызывает нативный Node.appendChild), то он не генерит новый дом, а лишь действительно вставляет новый элемент[исходник jq](поэтому старые элементы все еще куда-то указывают), в то время как elem.innerHTMl += "html_text" разворачивается в elem.innerHTML = elem.innerHTML + "html_text" и весь дом у нас получается новый, плюс происходит, что старые ноды никуда не деваются, ведь на них все еще указывается jquery like обьект(и потенциально мы выхватываем лишнию память, для уже несуществующих узлов - да?)...
Итак, демо:
1) Вариант с innerHTML
2) Вариант с append
Какая помощь мне нужна:
Какой литературой я могу восполнить свои знания и в каких еще случаях я могу столкнуться с такими проблемами?
Есть ли в моих размышлениях какие-то ошибки?
Я наслышан, что прямые методы работы с dom занимают больше времени, чем простой innerHTML, но что если у нас вставки в dom происходят достаточно часто и относительно большими пачками(штук 20), при этом к тому моменту уже могут находиться ~100элементов и перерисовывать их нежелательно из-за усложенения анимации :с Может ли быть такое, что использовать innerHTML на каком-то этапе станет менее оптимально, нежели вставка через dom методы?

laimas 05.09.2016 19:14

var $a = $(".a"),
    $b = $("#root").append("<div class='b'>b-dynamic</div>").find('.b');

//и 

var $a = $(".a");
$("#root").get(0).innerHTML += "<div class='b'>b-dynamic</div>";
var $b = $("div.b");


Иначе в цикле на добавленные не сослаться.

moron 05.09.2016 19:18

Суть не совсем в этом.
1) мы получаем $a
2) добавляем в $root.get(0).innerHTML += "строка с большим количеством .b"
3) теперь $a так же недоступен.
Т.е второй вариант, тобой предложенный так же не сможет работать с .a после innerHTML

var $a = $(".a");
$("#root").get(0).innerHTML += "<div class='b'>b-dynamic</div>";
var $b = $("div.b");

moron 05.09.2016 19:21

Баг как раз был в том что после innerHTML переставали работать методы к $a, потому что он указывал на уже удаленные узлы. А удаленны они были, потому что $root.get(0).innerHTML += "html"(развернувшись в $root.get(0).innerHTML = $root.get(0).innerHTML + "html") взял и перезаписал ВСЁ содержимое, что было. В том числе и $a, которые были получены раньше.

moron 05.09.2016 19:25

Вот небольшой пример. Посмотри на комментарий в js
http://codepen.io/mogafk/pen/qaEVVV
т.е пример
var $a = $(".a");
$("#root").get(0).innerHTML += "<div class='b'>b-dynamic</div>";
var $b = $("div.b");

Так же имеет баг, потому что $a будет указывать на уже удаленные узлы..

laimas 05.09.2016 19:28

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<style>

</style> 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script> 
$(function() {
var $a = $(".a"),
    $b = $("#root").append("<div class='b'>b-dynamic</div>").find('.b');
console.log($a.length, $b.length)

$("#root").get(0).innerHTML += "<div class='b'>b-dynamic</div>";
var $b = $("div.b");

console.log($a.length, $b.length)
});

</script>     
</head> 

<body>
<div id="root">
<div class="a">a</div>
<div class="a">a</div>
<div class="a">a</div>
  <hr />
<div class="b">b</div>
<div class="b">b</div>
<div class="b">b</div>
</div>
</body> 
</html>


Хоть как добавлять, доступными они будут. А вот то что вы получили коллекцию, с которой хотите работать, а затем модифицировали DOM, вот тут могут быть неожиданности.

moron 05.09.2016 19:32

Длина будет правильной и даже содержимое коллекций будет верным, но на самом деле это будут лишь уже несуществующие дубликаты из dom, которые находятся лишь в памяти. Т.е любая манипуляция с $a не будет работать как ожидается(возможно изменения будут применяться к элементам, которых в dom в действительно уже НЕТ).
Просто модицифкация дом не даст такого поведения. Потому что не удалит все и не запишет заново, а лишь сделает частичные изменеия :с

moron 05.09.2016 19:33

т.е ты прав, что они будут доступным, но какой в этом смысл, если их нет в дом на самом деле?

laimas 05.09.2016 19:35

Цитата:

Сообщение от moron
но какой в этом смысл, если их нет в дом на самом деле?

Что значит нет? Консоль по примеру покажет
3, 4
3, 5

пятый что "бог подарил" или все такие есть в DOM?

PS. Видимо вопрос касается некоторых тонкостей присущих innerHTML, и речь об этом. Тогда здесь почитать.

moron 05.09.2016 19:38

.b пятый есть и .b четвертый, а вот a. нет в дом вообще после innerHTML.
Иначе как ты обьяснишь, что после innerHTML пропадает родитель у .a?
console.log($a.eq(0).parent().prop("tagName"))


Часовой пояс GMT +3, время: 11:35.