关于 jaspr-fundamentals
jaspr-fundamentals 是介绍 Jaspr 组件模型和核心界面开发实践的技能。它指导开发者处理组件状态、类型化 HTML 元素、浏览器 API 和事件。
主要功能
- 01无状态与有状态组件
- 02上下文与状态向下传递
- 03类型化 HTML 组件用法
- 04浏览器 API 与事件处理
适用场景
- 01组织 Jaspr 组件树
- 02实现可交互的 HTML 元素
- 03在不同渲染模式下访问浏览器 API
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rodydavis/ signals.dart --skill jaspr-fundamentals安装后在 Claude Code 中输入/jaspr-fundamentals确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/html/a.mdarticle.mdaside.mdaudio.mdb.mdblockquote.mdbody.mdbr.mdbutton.mdcaption.mdcircle.mdcode.mdcol.mdcolgroup.mddatalist.mddd.mddetails.mddialog.mddiv.mddl.mddt.mdellipse.mdem.mdembed.mdfieldset.mdfigcaption.mdfigure.mdfooter.mdform.mdh1.md详细介绍
组件
Jaspr 采用基于组件的架构,与 Flutter 的 widget 非常相似。UI 组合、架构和状态管理等概念都可以迁移使用。
- StatelessComponent:用于不需要可变状态的组件。必须重写
Component build(BuildContext context)。 - StatefulComponent:用于具有可变状态的组件。需要关联一个
State类。该状态类包含initState()和dispose()等生命周期方法。必须在状态类中重写Component build(BuildContext context)。 - InheritedComponent:用于在组件树中高效地向下传递上下文或状态。
从 build 返回组件
在 Jaspr 中构建 UI 时,必须从 build() 返回单个 Component。
- **规则 1:**不得使用
Iterable<Component> build(BuildContext context) sync*。这是旧式代码。 - **规则 2:**对于片段、文本和空节点,必须使用点简写,而不是首字母大写的组件名称。
- 使用
.fragment([...])(不要使用Fragment([...])或fragment([...]))。 - 使用
.text('...')(不要使用Text('...')或text('...'))。 - 使用
.empty()安全地返回空白节点。
- 使用
用法示例:
import 'package:jaspr/jaspr.dart';
import 'package:jaspr/dom.dart';
class MyComponent extends StatelessComponent {
const MyComponent({super.key});
@override
Component build(BuildContext context) {
// 1. Return a single component (e.g. div)
// 2. Use dot-shorthand (.text) instead of Text()
return div(classes: 'my-class', [
.text('Hello World'),
]);
}
}
HTML 组件
Jaspr 为标准 HTML 元素(例如 div()、p()、a()、button())提供了带类型的组件。要使用这些组件,请导入 package:jaspr/dom.dart。
所有 HTML 组件都接受标准的命名参数 Key? key、String? id、String? classes、Styles? style、Map<String, String>? attributes 和 Map<String, void Function(Event)>? events。
大多数 HTML 组件都接受位置参数 List<Component> children(自闭合标签除外,例如 img、input、br 等)。
- **规则 1:**始终将
children列表放在最后,在所有命名参数之后。 - **规则 2:**必须优先使用可用的带类型参数(例如
href、src、onClick),而不是使用原始的attributes:或events:映射。 - **规则 3:**如果不确定某个 HTML 组件有哪些带类型参数,必须阅读随此技能提供的对应参考文件:
references/html/<tag>.md包含给定标签对应组件的完整签名和用法示例。(例如,div()对应references/html/div.md,button()对应references/html/button.md等。)
- **规则 4:**如果某个标签没有对应的参考文件(因此组件本身也不存在),必须改用通用
.element(tag: '...', /* other standard params, */ children: [ /* ... */ ])构造函数。
用法示例:
import 'package:jaspr/jaspr.dart';
import 'package:jaspr/dom.dart';
class MyHtmlComponent extends StatelessComponent {
const MyHtmlComponent({super.key});
@override
Component build(BuildContext context) {
return div(id: 'my-container', classes: 'my-class', [
p(attributes: {'aria-label': 'Example Paragraph'}, [
.text('Hello World'),
]),
// E.g. signature as found at 'references/html/a.md'
a(href: 'https://example.com', [
.text('Click me'),
]),
]);
}
}
设置组件样式
Jaspr 内置了使用 CSS-in-Dart 为组件设置样式的支持。 如需了解更多信息,请参阅 jaspr-styling 技能。
交互与事件
1. 访问浏览器 API
- **规则 1:**在 server 或 static 模式下,必须使用
package:universal_web/web.dart访问浏览器 API,并使用package:universal_web/js_interop.dart访问 js interop API。 - **规则 2:**在 server 或 static 模式下使用
package:universal_web时,必须将所有 API 调用放在if (kIsWeb)检查中,以防止服务端渲染崩溃。 - **规则 3:**在 client 模式下,可以直接使用
dart:js_interop和package:web。 - **规则 4:**对于全局事件,必须使用
web.EventStreamProviders来监听window或document上的事件,因为它们会提供带类型的 DartStream事件流。
// Example of safe usage in server/static mode:
import 'package:universal_web/web.dart' as web;
void logSize() {
if (kIsWeb) {
print('Window size: ${web.window.innerWidth}x${web.window.innerHeight}');
// Example of global event listener
final sub = web.EventStreamProviders.resizeEvent.forTarget(web.window).listen((event) {
print('Window resized');
});
}
}
2. 处理事件
所有 DOM 组件都支持 events: 参数,交互式组件还提供带类型的事件回调(例如 onClick、onChange)。
- **规则 1:**为原始事件指定类型时,必须使用
web.Event。 - **规则 2:**需要时,使用
events()助手函数创建类型安全的回调。
import 'package:jaspr/jaspr.dart';
import 'package:jaspr/dom.dart';
import 'package:universal_web/web.dart' as web;
class MyButton extends StatelessComponent {
@override
Component build(BuildContext context) {
return div(
// Using raw events
events: {'click': (web.Event event) {
print('Div clicked');
}},
[
// Using typed parameters
button(
onClick: () => print('Button clicked'),
[.text('Click me')]
)
]
);
}
}
3. 访问元素(GlobalNodeKey)
如果需要直接引用 Jaspr 渲染的底层 DOM 元素,可以为其分配一个 GlobalNodeKey。
import 'package:jaspr/jaspr.dart';
import 'package:jaspr/dom.dart';
import 'package:universal_web/web.dart' as web;
class MyInput extends StatefulComponent {
@override
State<MyInput> createState() => _MyInputState();
}
class _MyInputState extends State<MyInput> {
final GlobalNodeKey<web.HTMLInputElement> inputKey = GlobalNodeKey();
void focusInput() {
inputKey.currentNode?.focus();
}
@override
Component build(BuildContext context) {
return input(key: inputKey, type: .text);
}
}
更多资源
- 关于预渲染、异步数据获取、水合和
@client注解的信息,请参阅相关技能:jaspr-pre-rendering-and-hydration。 - 关于组件样式的信息,请参阅相关技能:jaspr-styling。
- 关于如何将 HTML 转换为 Jaspr 代码的信息,请参阅相关技能:jaspr-convert-html。
- 所有可用文档的索引请见 https://jaspr.site/llms.txt。