Context 用于把「全局 Service / 配置」注入到组件树深层,避免逐层
@property透传(prop drilling)。 与 Angular 的 DI 对标,但更轻:令牌 + provide + consume。
| API | 作用 |
|---|---|
createContext<T>(key) |
定义一个注入令牌(模块级唯一) |
provide({ context, initialValue }) |
在某个祖先元素上提供值(通常根组件) |
consume({ context, subscribe }) |
在子组件里消费值 |
// services/contexts.js —— 令牌集中定义,避免散落
import { createContext } from '@lit-labs/context';
import { authService } from './auth-service.js';
export const authContext = createContext('fmode.auth');
// 也可以为普通配置/值建令牌
export const configContext = createContext('fmode.config');
fmode.xxx)避免与第三方冲突。createContext 会得到不同令牌 → 注入失败。集中定义。// app.js 或根组件
import { LitElement, html } from 'lit';
import { provide } from '@lit-labs/context';
import { authContext, configContext } from './services/contexts.js';
import { authService } from './services/auth-service.js';
export class AppRoot extends LitElement {
render() {
return html`
${provide(authContext, authService)}
${provide(configContext, { apiBase: '/api', appName: 'Admin' })}
<app-shell></app-shell>
`;
}
}
provide 是一个「无渲染」的模板指令,放在祖先组件 render 里,向下对所有后代生效。⚠️ 无构建下禁用
@consume装饰器,改用编程式ContextConsumer。
import { LitElement, html } from 'lit';
import { ContextConsumer } from '@lit-labs/context';
import { authContext } from '../services/contexts.js';
export class UserBadge extends LitElement {
static properties = { _auth: { state: true } };
#consumer = new ContextConsumer(this, {
context: authContext,
subscribe: true, // 提供的「实例」被替换时回调
callback: (value) => { this._auth = value; },
});
render() {
return html`<span>${this._auth?.user.get()?.name ?? '未登录'}</span>`;
}
}
customElements.define('user-badge', UserBadge);
subscribe: true:当提供的值本身被替换为另一个实例时,组件重新响应(不是 signal 变化,而是「注入对象换了」)。SignalWatcher 负责驱动重渲染 —— 两者配合。provide(ctx, value)(见第三节),同样无需装饰器。| 情况 | 做法 |
|---|---|
| 全局单例 Service,确定唯一 | 直接 import 单例 即可(最简单,推荐) |
| 需要「同组件树不同区块用不同实例」(多实例 / 可测试替换) | Context(provide 不同实例) |
| 需要向下传配置 / 主题 / 环境值 | Context |
务实建议:默认直接 import 单例;只有当「同一组件要能跑在不同注入环境」时才上 Context。别为了 DI 而 DI。
consume 拿到的是 Service 实例(不一定变化)。SignalWatcher 的组件自动重渲染。consume 解决「拿到谁」,SignalWatcher 解决「谁变了要重渲染」。undefined。令牌必须集中定义、单例导出。render() 外读取 consumed 属性可能为 undefined(首次渲染前);用可选链。