Рендеринг портов и 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 это путь.