Когда мое приложение загружается, оно вызывает серверную часть, чтобы получить описание компонентов, которые пользователь решит добавить.
Эти объекты должны иметь функцию для генерации своего html, возьмем, к примеру, кнопку: она будет экспортировать метод html(), который возвращает строку, содержащую текст HTML:
const buttonText = "I'm a button"
export default {
html() {
return `<button>${buttonText}</button>`
}
}
На стороне внешнего интерфейса я буду использовать оператор импорта для загрузки вышеупомянутого модуля кнопки и сохранения его в объекте JSON, что-то вроде менеджера плагинов.
Когда пришло время рендерить его, я попытался использовать Dynamic:
<For each = {plugins()} fallback = {<p>Loading...</p>}>{ plugin =>
<div>
<Dynamic component = {plugin.module.html()}>
</Dynamic>
<div>
}</For>
Но он падает с DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('<button>I'm a button</button>') is not a valid name.
Что имеет смысл, так как ожидается что-то вроде элемента "div", а не строки вроде <button>I'm a button</button>.
Каким будет правильный способ отображения строк HTML в SolidJS?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Простым решением было бы просто использовать innerHTML вот так:
<For each = {plugins()} fallback = {<p>Loading...</p>}>
{ plugin =>
<div innerHTML = {plugin.module.html()}>
<div>
}</For>
Если вам нужно что-то более интерактивное, возможно, используйте template и cloneNode, в которые Solidjs обычно компилирует ваш код.
Ниже приведен полный пример. Создала на детской площадке.
import { render, template } from "solid-js/web";
import { For } from "solid-js";
function MakeButton() {
const plugins = ["<button>Click me</button>"];
const handleClick = () => {
console.info("Clicked button");
}
const createElem = (el: string) => {
const elem = template(el, 2);
const ret = elem.cloneNode(true);
if (ret.tagName === "BUTTON") {
ret.onclick = handleClick;
}
return ret;
}
return (<>
<For each = {plugins} fallback = {<div>Loading...</div>}>
{plugin =>
<div>{createElem(plugin)}</div>
}
</For>
</>);
}
render(() => <MakeButton />, document.getElementById("app"));
Если я правильно понимаю ваш вопрос, вы пытаетесь импортировать обычный элемент HTML и визуализировать его внутри сплошного компонента, тогда ответ прост, просто поместите его в фигурные скобки, как любое другое выражение. В отличие от React, Solid может отображать HTML-элемент напрямую.
import { render } from "solid-js/web";
import { createSignal } from "solid-js";
const el = document.createElement('p');
el.innerHTML = 'Some Content';
function App() {
return (
<div>{el}</div>
);
}
render(App, document.getElementById("app")!);
Вам не нужно использовать свойство innerHTML или вам даже не нужно оборачивать его внутри элемента JSX:
const el = document.createElement('p');
el.innerHTML = 'Some Content';
function App() {
return el;
}
Несколько проблем с вашим вопросом. Метод html возвращает не элемент HTML, а строку:
const buttonText = "I'm a button"
export default {
html() {
return `<button>${buttonText}</button>`
}
}
Вы можете исправить это, вернув фактический элемент. Я назвал импортированный объект x, чтобы избежать раздувания кода, поскольку вы можете импортировать любую переменную из другого модуля:
const buttonText = "I'm a button";
const x = {
html() {
const el = document.createElement("button");
el.innerText = buttonText;
return el;
},
};
function App() {
return x.html();
}
Если вы используете x только для возврата строки, вы можете полностью опустить его и просто экспортировать сам элемент:
const el = document.createElement("button");
el.innerText = buttonText;
export default el;
В качестве альтернативы вы можете вернуть строку и получить DOM-рендеринг для вас, используя свойство innerHTML. Вы можете создать элемент самостоятельно:
const el = document.createElement('div');
el.innerHTML = x.html();
Или попросите Solid сделать это за вас:
const txt = "<button>I'm a button</button>";
function App() {
return <div innerHTML = {txt}></div>
}
В любом случае это не имеет ничего общего с Solid, это функция браузера для отображения строки в HTML-элемент при назначении innerHTML элемента. На самом деле это то, что внутри использует функция Solid template.
В качестве примечания: Solid использует метод клонирования для эффективного рендеринга нескольких элементов. Если вы не рендерите большой HTML-текст с большим количеством элементов, createElement лучше, так как он чище и быстрее.
«Динамическая загрузка компонентов» относится к чему-то совершенно другому, как и компонент. Динамический компонент означает, что визуализированный вывод привязан к переменной, а не к условию:
const RedThing = () => <strong style = "color: red">Red Thing</strong>;
const GreenThing = () => <strong style = "color: green">Green Thing</strong>;
const BlueThing = () => <strong style = "color: blue">Blue Thing</strong>;
const [selected, setSelected] = createSignal('red');
const options = {
red: RedThing,
green: GreenThing,
blue: BlueThing
}
<Dynamic component = {options[selected()]} />
Тем не менее вам нужно передать компонент, а не строку. Строка, содержащая допустимый текст HTML, не является компонентом JSX.
Лучше всего выражать наши проблемы простыми словами и избегать технического жаргона, потому что это действительно затрудняет понимание.