You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

innerHTML易出错、document.createElement繁琐,能否用类JSX方式定义Web Component?

问题:是否存在类JSX的方式定义Web Component的HTML内容?

用innerHTML字符串定义Web Component的HTML内容极易出错,而document.createElement的写法又十分繁琐。想找一种类JSX的写法来替代原生的字符串拼接方式。

原有的innerHTML字符串写法:

class Foo extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `<p>foo</p>`;
  }
}

期望的类JSX写法(无需字符串包裹):

class Foo extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = (<p>foo</p>);
  }
}

可行方案

1. 自定义标签函数实现类JSX语法

自己实现一个标签函数,既能贴近JSX的写法,还能自动转义插值内容避免XSS:

function html(strings, ...values) {
  let htmlStr = strings[0];
  for (let i = 0; i < values.length; i++) {
    // 转义用户输入内容
    const escapedValue = String(values[i])
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
    htmlStr += escapedValue + strings[i + 1];
  }
  return htmlStr;
}

// 使用示例
class Foo extends HTMLElement {
  connectedCallback() {
    const userName = 'Alice';
    this.innerHTML = html`<p>Hello, ${userName}</p>`;
  }
}

这种写法和JSX类似,且无需额外构建工具,直接在浏览器中运行。

2. 用Babel转译JSX到原生DOM操作

如果项目已经使用Babel,可以配置它将JSX转换成原生document.createElement调用,完全脱离React:

  1. 安装@babel/plugin-transform-react-jsx
  2. 在Babel配置中指定自定义的元素创建函数:
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "h",
      "pragmaFrag": "DocumentFragment"
    }]
  ]
}
  1. 实现简单的h函数:
function h(tag, props = {}, ...children) {
  const element = document.createElement(tag);
  // 处理属性和事件
  Object.entries(props).forEach(([key, value]) => {
    if (key.startsWith('on')) {
      element.addEventListener(key.slice(2).toLowerCase(), value);
    } else {
      element.setAttribute(key, value);
    }
  });
  // 处理子元素
  children.forEach(child => {
    element.appendChild(
      typeof child === 'string' ? document.createTextNode(child) : child
    );
  });
  return element;
}

// 现在可以直接用JSX写法
class Foo extends HTMLElement {
  connectedCallback() {
    this.appendChild(<p onClick={() => alert('clicked')}>foo</p>);
  }
}

3. 轻量级库简化开发

如果不想自己造轮子,可以用专门为Web Component设计的轻量级库,比如lit-html:

import { html, render } from 'lit-html';

class Foo extends HTMLElement {
  connectedCallback() {
    const count = 10;
    render(html`<p>Count: ${count}</p>`, this);
  }
}

lit-html不仅提供类JSX的语法,还支持响应式更新和自动XSS防护,体积小巧,非常适合Web Component场景。


内容的提问来源于stack exchange,提问作者Rofls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:25:22