Каков аспект Javascript и правил определения области видимости DOM и присвоения, которые не позволяют коду работать со вторым блоком html?

#javascript #variables #dom

#javascript #переменные #dom

Вопрос:

Приведенный ниже html-код экспортируется из orgmode, а функция Javascript предназначена для преобразования <pre class="src src-emacs-lisp"> блока в <pre><code class="lisp"> , чтобы он был синтаксически выделен с помощью highlightjs.

Из-за какой-то причуды Javascript, которую я не понимаю, функция не работает со вторым блоком. Я думал, что это синтаксис html-кода в нем, но когда я переставляю блоки, ошибка всегда возникает на втором. Должно быть что-то в правилах определения области видимости Javascript, чего я не понимаю. Код для определения местоположения блоков работает нормально, и если я распечатываю их без обработки, это работает, все они отображаются. Именно тогда, когда я применяю преобразования, все идет не так. Какую функцию Javascript я не понимаю?

Код, который просто выводит их, работает нормально. Все они обнаружены.

 document.addEventListener('DOMContentLoaded', (event) => {
var lispBlocks = document.getElementsByClassName('src src-emacs-lisp');
alert(lispBlocks.length);
for (i=0;i<lispBlocks.length;i  ){
    var iHtml = lispBlocks[i].outerHTML;
    //alert(lispBlocks[i].outerHTML);
    alert(iHtml);
  };
});
  

С кодом, который их преобразует, все идет наперекосяк

 document.addEventListener('DOMContentLoaded', (event) => {
var lispBlocks = document.getElementsByClassName('src src-emacs-lisp');
alert(lispBlocks.length);
var iHtml;
var lBlockText;
for (i=0;i<lispBlocks.length;i  ){
    //lispBlocks[i].className = '';
    iHtml = lispBlocks[i].innerHTML;
    alert(lispBlocks[i].innerHTML);
    alert(lispBlocks[i].outerHTML);
    lBlockText = '<pre><code class="lisp">'   iHtml   '</code></pre>';
    alert(lBlockText);
    lispBlocks[i].outerHTML = lBlockText;
    //alert(lispBlocks[i].outerHTML);
    //hljs.highlightBlock(lispBlocks[i]);
  };
});


<!-- language: lang-html -->

<div class="org-src-container">
<pre class="src src-emacs-lisp">;; after splitting a frame automatically, switch to the new window (unless we
;; were in the minibuffer)
(setq split-window-preferred-function 'my/split-window-func)
(defun my/split-window-func (amp;amp;optional window)
(let ((new-window (split-window-sensibly window)))
    (if (not (active-minibuffer-window))
    (select-window new-window))))
</pre>
</div>


<div class="org-src-container">
<pre class="src src-emacs-lisp"> (defun split-window--select-window (orig-func amp;amp;rest args)
"Switch to the other window after a `split-window'"
(let ((cur-window (selected-window))
      (new-window (apply orig-func args)))
  (when (equal (window-buffer cur-window) (window-buffer new-window))
    (select-window new-window))
  new-window))
  (advice-add amp;#39;split-window :around #amp;#39;split-window--select-window)
</pre>
</div>

<div class="org-src-container">
<pre class="src src-emacs-lisp">;; settings for default frames
(add-to-list 'default-frame-alist '(font . FONT ))
;;or

;; set-face-atribute, ='default nil= for all existing frames and new frames
;; ='default t= for new frames only
;; function sets a number of attributes besides :font see docs
(set-face-attribute 'default nil :font FONT )

;;set frame font
(set-frame-font FONT nil t)
</pre>
</div>
  

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

1. function doesn't work очевидно, иначе вас бы здесь не было — не могли бы вы описать, что происходит в сравнении с тем, что вы ожидаете, и любые ошибки в инструментах разработчика браузера, которые вы можете получать

2. функция работает с первым и третьим блоками, но не со вторым. Обнаружение работает корректно для всех 3 блоков. Преобразование не работает со вторым.

3. Да, я понял это, как только снова посмотрел на код — пропуск каждого второго блока является классическим примером изменения элементов в «живом» списке — см. Ответ для двух возможных решений

4. Спасибо. Где я могу получить дополнительную помощь по живой категории выборок?

Ответ №1:

Проблема в том, что getElementsByClassName возвращает текущий список

Следовательно, при изменении outerHTML вы изменяете список, потому что вы изменили класс элемента, который находится в текущем списке

В примере у вас будет список элементов, [a, b, c] и i == 0

Вы изменяете a таким образом, что он исчезает из списка, теперь список [b, c] но i увеличивается до 1, поэтому следующая итерация изменяется c , пропуская b

использовать

 var lispBlocks = document.querySelectorAll('.src.src-emacs-lisp');
  

вместо

В качестве альтернативы вы могли бы использовать цикл while

 while(lispBlocks.length) {
    iHtml = lispBlocks[0].innerHTML; // note, the hard coded `0` here
    // etc
}