返回首页
🎨 前端 / Web
Web Components 2026 复兴:Lit 4.0 + 原生支持实战
Web Components 在 2026 年正式复兴。本文演示 Lit 4.0 + 浏览器原生能力,构建跨框架可复用的 UI 组件。
Web Components · Lit · 前端 · 跨框架
📰
今日技术简讯
📰 技术简讯 · 2026-06-16
今日聚合 6 条热门技术内容。
🤖 AI / LLM
1. OpenAI 推出 Realtime API
- 链接:https://platform.openai.com/docs/realtime
- 来源:OpenAI
- 摘要:实时语音对话 API,延迟 < 300ms,支持打断和情感识别。
🎨 前端 / Web
2. Web Components 2026 复兴
- 链接:https://web.dev/web-components-2026
- 来源:web.dev
- 摘要:Lit 4.0 + 浏览器原生支持,Web Components 在 2026 年正式复兴。
3. Chrome 129 推出 View Transitions API 稳定版
- 链接:https://developer.chrome.com/blog/view-transitions
- 来源:Chrome 团队
- 摘要:页面切换动画原生支持,跨 MPA 平滑过渡,告别动画库。
⚙️ 后端 / 架构
4. PostgreSQL 18 第一个 Beta
- 链接:https://www.postgresql.org/about/news/18-beta-1
- 来源:PostgreSQL
- 摘要:原生 UUID v7、性能优化、逻辑复制增强。
🚀 独立开发 / OPC
5. Super.so 推出 Members 功能
- 链接:https://super.so/members
- 来源:Super
- 摘要:Notion 站点加会员订阅,$29/月起步,独立创作者友好。
6. ConvertKit 推出 Sponsor Network
- 链接:https://convertkit.com/sponsors
- 来源:ConvertKit
- 摘要:newsletter 作者可对接赞助商,CPM 模式分成。
数据来源:HN / Reddit / 各厂博客 采集时间:2026-06-16 09:00 (UTC+8)
📝
今日深度文
Web Components 2026 复兴:Lit 4.0 + 原生支持实战
一句话结论:Web Components 是"真正跨框架"的组件方案。2026 年 Lit 4.0 + 浏览器原生能力,让它在性能、DX 上不输 React/Vue。
背景
Web Components(WC)是一组浏览器原生 API:
- Custom Elements:自定义 HTML 元素
- Shadow DOM:封装样式和 DOM
- HTML Templates:声明式模板
- ES Modules:模块化
多年来被吐槽"复杂、慢、没人用"。但 2026 年情况变了:
- Lit 4.0 让写法类似 React/Vue
- 浏览器原生支持完善
- 微前端 / 跨框架复用场景增多
5 个核心优势
1. 真正跨框架
<!-- 在任何框架中使用 -->
<my-button variant="primary">Click</my-button>
<!-- React 中 -->
<my-button variant="primary">Click</my-button>
<!-- Vue 中 -->
<my-button variant="primary">Click</my-button>
<!-- Svelte 中 -->
<my-button variant="primary">Click</my-button>
<!-- 原生 HTML 中 -->
<my-button variant="primary">Click</my-button>
2. 零依赖、零运行时
// React 组件:打包后 ~3KB
// Vue 组件:~5KB
// Web Components(Lit):~5KB(含 Lit)
// 原生 Web Components:0KB(只有你的代码)
3. 样式完全隔离
class MyButton extends LitElement {
static styles = css`
/* 这些样式只影响组件内部,不会泄漏到全局 */
button {
background: var(--button-bg, blue);
color: white;
}
`;
}
4. 真正的封装
class CounterElement extends LitElement {
// 私有状态,不会暴露给外部
@state() private _count = 0;
// 公开 API
@property({ type: Number }) initial = 0;
}
5. 渐进增强
<!-- JS 加载前 -->
<my-counter>5</my-counter>
<!-- JS 加载后 -->
<my-counter>5 [+][-]</my-counter>
Lit 4.0 实战
安装
npm install lit
第一个组件
// components/my-button.ts
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('my-button')
export class MyButton extends LitElement {
@property({ type: String }) variant: 'primary' | 'secondary' = 'primary';
@property({ type: Boolean }) disabled = false;
static styles = css`
:host {
display: inline-block;
}
button {
padding: 8px 16px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
:host([variant="primary"]) button {
background: var(--color-primary, #3b82f6);
color: white;
}
:host([variant="secondary"]) button {
background: transparent;
color: var(--color-text, #1f2937);
border: 1px solid currentColor;
}
:host([disabled]) button {
opacity: 0.5;
cursor: not-allowed;
}
`;
render() {
return html`
<button ?disabled=${this.disabled}>
<slot></slot>
</button>
`;
}
}
使用:
<my-button variant="primary">主要按钮</my-button>
<my-button variant="secondary">次要按钮</my-button>
<my-button disabled>禁用按钮</my-button>
响应式状态
@customElement('my-counter')
export class MyCounter extends LitElement {
@state() private _count = 0;
render() {
return html`
<div>
<button @click=${() => this._count--}>-</button>
<span>${this._count}</span>
<button @click=${() => this._count++}>+</button>
</div>
`;
}
}
生命周期
connectedCallback() {
super.connectedCallback();
// 组件挂载到 DOM
console.log('Mounted');
}
disconnectedCallback() {
// 组件卸载
console.log('Unmounted');
}
updated(changedProperties: Map<string, unknown>) {
// 状态更新后
if (changedProperties.has('_count')) {
console.log('Count changed:', this._count);
}
}
跨框架使用
React
import '@components/my-button';
// 直接当 HTML 元素用
export function App() {
return (
<div>
<my-button variant="primary">React 中</my-button>
</div>
);
}
类型定义:
// types/jsx.d.ts
import { MyButton } from '@components/my-button';
declare global {
namespace JSX {
interface IntrinsicElements {
'my-button': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & {
variant?: 'primary' | 'secondary';
disabled?: boolean;
},
HTMLElement
>;
}
}
}
Vue
<template>
<my-button variant="primary">Vue 中</my-button>
</template>
<script setup>
import '@components/my-button';
</script>
原生 HTML
<!DOCTYPE html>
<html>
<head>
<script type="module" src="./components/my-button.js"></script>
</head>
<body>
<my-button variant="primary">原生 HTML</my-button>
</body>
</html>
实战:构建组件库
项目结构
packages/
components/
src/
my-button/
my-button.ts
my-button.test.ts
stories.ts # Storybook
my-input/
my-card/
index.ts
跨项目发布
// package.json
{
"name": "@myorg/web-components",
"main": "dist/index.js",
"module": "dist/index.js",
"customElements": "dist/index.js"
}
# 构建
npm run build
# 输出 ES Module 格式,可以被任何项目直接 import
在多个项目中使用
// 项目 A(Next.js)
import '@myorg/web-components';
// 项目 B(Vue)
import '@myorg/web-components';
// 项目 C(Astro)
import '@myorg/web-components';
性能对比
Bundle 体积
React + react-dom: ~140KB
Vue 3: ~50KB
Lit 4: ~5KB
原生 WC: ~0KB
运行时性能
1 万个简单组件(每个含 5 个文本节点):
React (concurrent): 200ms
Vue 3: 180ms
Lit 4: 95ms
原生 WC: 60ms
Web Components 在大量轻量组件场景下性能最佳(无 diff 开销)。
5 个常见坑
坑 1:样式隔离导致主题失效
// ❌ 全局样式 .button 不生效
// styles.css
.button { color: red; }
// ✅ 用 CSS 变量穿透 Shadow DOM
static styles = css`
button {
color: var(--button-color, red);
}
`;
// HTML 中定义变量
<style>
my-button {
--button-color: red;
}
</style>
坑 2:Form 集成问题
<!-- WC 不天然是 form 元素 -->
<my-input name="email"></my-input>
<!-- ✅ 用 ElementInternals API -->
import { attachInternals } from 'lit';
class MyInput extends LitElement {
private internals = attachInternals(this);
formAssociated = true;
private _handleInput(e: Event) {
this.internals.setFormValue((e.target as HTMLInputElement).value);
}
}
坑 3:SSR 支持
// Lit SSR 需要 @lit-labs/ssr
import { render } from '@lit-labs/ssr';
const result = render(html`<my-button>Hello</my-button>`);
坑 4:事件冒泡
// WC 默认事件不会冒泡到外部
// ✅ 用 composed: true
this.dispatchEvent(new CustomEvent('change', {
detail: { value: this.value },
bubbles: true,
composed: true, // 关键:穿透 Shadow DOM
}));
坑 5:TypeScript 类型
// ❌ 直接用 JSX 会报类型错误
<my-button>Click</my-button>
// ✅ 加类型声明
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'my-button': any;
}
}
}
什么时候用 Web Components
✅ 适合
- 跨框架组件库:在 React / Vue / Svelte 都能用
- 微前端:子应用技术栈无关
- 嵌入第三方:给客户网站提供可嵌入组件
- 设计系统:样式隔离天然适合
❌ 不适合
- 单一框架项目(React/Vue 体验更好)
- 需要复杂状态管理(用 Pinia / Redux)
- 团队不熟悉 WC 心智模型
我的看法
Web Components 不会取代 React / Vue,但在特定场景下是最佳选择:
- 跨框架组件库:唯一真正跨框架的方案
- 微前端:技术栈无关
- 嵌入第三方:不受宿主框架限制
Lit 4.0 让 WC 真正"可用了":
- 学习曲线:和 React 接近
- 性能:不输主流框架
- DX:TypeScript + 装饰器 + JSX-like 模板
未来值得关注:
- CSS 作用域标准化:跨 Shadow DOM 的样式穿透
- Form 集成 API 标准化:ElementInternals 普及
- SSR 性能:Lit SSR + Streaming 集成
参考
本文示例基于 Lit 4.0 + TypeScript 5.x,2026 年 6 月最新版本。
📚 同主题文章
🎨前端 / Web·
shadcn/ui + 设计系统 2026:现代 Web 产品的 UI 实战
shadcn/ui 是 2026 年最火的前端组件库 + 设计系统方案。本文从 0 到完整设计系统,含 5 个真实项目 + 主题定制 + 组件库扩展 + A11y。
shadcn/ui设计系统Tailwind v4
🎨前端 / Web·
React 19 实战:从 Server Components 到 Server Actions 完整指南
React 19 是前端框架的"分水岭"——Server Components 让前端从"CSR + API"转向"RSC + Actions"。本文从 0 到生产级 RSC 实战,含 4 个真实项目 + 性能对比。
ReactServer ComponentsServer Actions
🎨前端 / Web·
TypeScript 5.6 实战:从入门到生产级类型系统
TypeScript 5.6 引入 infer const / iterator helpers 等重磅特性。本文从基础到生产级类型系统实战,含 4 个真实项目 + 类型设计模式。
TypeScript类型系统前端