Как сделать html тэг для отображения markdown на сайте?
Есть у меня сайт со статьями на html. Я хотел бы сделать кастомный тэг для отображения markdown на сайте. К примеру:
<markdown>
# Заголовок
Текст
- 1
- 2
- 3
</markdown>
Я пробовал сделать что то такое, но знаний у меня не хватило. Помогите пожалуйста.
Ответы (1 шт):
Судя по всему, вам нужны Web Components
Одной из ключевых особенностей веб-компонентов является возможность создания пользовательских элементов: то есть HTML-элементов, поведение которых определяется веб-разработчиком и которые расширяют набор элементов, доступных в браузере.
Простейшая реализация может быть примерно такой:
class MarkdownElement extends HTMLElement {
/** Список имен обозреваемых атрибутов, сюда можно передать параметры для marked */
#observableHostAttributeNames = ['async', 'breaks', 'gfm', 'pedantic', 'silent'];
#hostAttributes = {};
constructor() {
super();
this.#initAttributes();
this.#initContent();
}
#initAttributes() {
for(const attr of this.attributes) {
if (this.#observableHostAttributeNames.includes(attr.name)) {
this.#hostAttributes[attr.name] = this.#coerceBooleanProperty(attr.value);
}
}
}
#initContent() {
marked.use(this.#hostAttributes);
/** На этом моменте стоит обратить внимание на защиту от XSS и использовать, например, DOMPurify */
const raw = marked.parse(this.textContent);
this.#clear();
/** После всех обработок, связанных с безопасностью контента, можно просто использовать innerHtml */
// this.innerHtml = raw;
/** Или распарсить строку и работать с Document, будет удобнее, если планируете использовать shadow-root */
const domParser = new DOMParser();
const markdownNodes = domParser.parseFromString(raw, 'text/html').body.childNodes;
this.append(...markdownNodes);
}
#clear() {
this.childNodes.forEach((child) => child.remove());
}
#coerceBooleanProperty(value) {
return value != null && `${value}` !== 'false';
}
}
customElements.define('html-markdown', MarkdownElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.7/marked.min.js" integrity="sha512-rPuOZPx/WHMHNx2RoALKwiCDiDrCo4ekUctyTYKzBo8NGA79NcTW2gfrbcCL2RYL7RdjX2v9zR0fKyI4U4kPew==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<html-markdown gfm="true" breaks="true">
# Заголовок
Текст
- 1
- 2
- 3
</html-markdown>
Заметьте, что имя элемента должно начинаться со строчной буквы, содержать дефис и соответствовать некоторым другим правилам, перечисленным в определении спецификации