Рендеринг портов и DOM

Попробуйте использовать CodeMirror в моем приложении Elm.

Я связываю текстовую область с update функционировать так:

( ..., runCodemirror textAreaId)

куда runCodemirror это порт:

port runCodemirror : String -> Cmd msg

Проблема в том, что событие ports.runCodemirror срабатывает до появления текстовой области в DOM.

Я пытаюсь решить это с setTimeout:

app.ports.runCodemirror.subscribe(
  function (textAreaId) {
    setTimeout(
      function() {
        CodeMirror.fromTextArea(document.getElementById(textAreaId));
      },
      100
    );
  }
);

но это некрасиво 100 мс слишком медленно, я вижу мигание.

Другие варианты, которые у меня есть: связать CodeMirror с невидимым textarea или MutationObserver API.

Есть ли способ лучше?

2 ответа

Вы можете использовать наблюдатели мутаций DOM для отслеживания изменений в DOM и создания объектов JS при возникновении этих событий, поэтому вам вообще не нужно использовать порты.

ArriveJS предоставляет хорошую оболочку для этой функциональности, чтобы вы могли сделать что-то вроде:

document.arrive(".code-mirror", function() {
  CodeMirror.fromTextArea(this)
})

Вы можете пойти дальше, добавив data- атрибуты элемента в Elm и читая их на стороне JS:

document.arrive(".code-mirror", function() {
  const lineNumbers = this.getAttribute('data-line-numbers') 
  CodeMirror.fromTextArea(this, {
    lineNumbers: lineNumbers
  })
})

Если вы открыты для злоупотребления декодерами JSON, вы можете использовать их для запуска кода, когда элемент впервые появляется в DOM. Я написал об этом подходе здесь: https://medium.com/@prozacchiwawa/the-i-m-stupid-elm-language-nugget-7-8d3efd525e3e. В противном случае MutationObserver это путь.

Другие вопросы по тегам