Импорт и визуализация элемента html с помощью SolidJS

Когда мое приложение загружается, оно вызывает серверную часть, чтобы получить описание компонентов, которые пользователь решит добавить.

Эти объекты должны иметь функцию для генерации своего 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?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
410
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Простым решением было бы просто использовать 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.

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

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