skills/ofajs-docs/SKILL.md
ofa.js 框架完整文档知识库。当用户询问 ofa.js 的使用方法、组件开发、页面模块、路由配置、状态管理,或想要构建无需 Node.js/Webpack 的 Web 应用时使用。
npx skillsauth add ofajs/ofa.js ofajs-docsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
computed 定义计算属性(ofa.js 使用 get 关键字)query 参数以外的路由参数获取方式attrs 和 data 中使用相同的 key| ❌ 错误写法 | ✅ 正确写法 | 说明 |
|------------|-----------|------|
| computed: { double() {} } | proto: { get double() {} } | 计算属性用 getter 定义,放在 proto 中 |
| this.$route.query.id | { query } 参数 | 通过函数参数获取查询参数 |
| v-if="show" | <o-if :value="show"> | 条件渲染使用 o-if 组件 |
| v-for="item in list" | <o-fill :value="list"> | 列表渲染使用 o-fill 组件 |
| @click="handle" | on:click="handle" | 事件绑定使用 on: 前缀 |
| :class="{ active: isActive }" | class:active="isActive" | 动态类名使用 class: 语法 |
| style="width: {{val}}" | :style.width="val" | 内联样式绑定使用 :style. 前缀 |
| v-model="value" | sync:value="value" | 双向绑定使用 sync: 语法 |
| props: { msg: String } | attrs: { msg: 'default' } | 组件属性使用 attrs 定义 |
| methods: { foo() {} } | proto: { foo() {} } | 方法定义在 proto 对象中 |
| data() { return { count: 0 } } | data: { count: 0 } | data 是对象而非函数 |
| attrs 和 data 同名 key | 保持唯一 | attrs 和 data 的 key 不能重复 |
| {{item.text}} | {{$data.text}} | o-fill 内必须使用 $data 访问数据 |
| {{element.name}} | {{$data.name}} | o-fill 内必须使用 $data 访问数据 |
| {{row.price}} | {{$data.price}} | o-fill 内必须使用 $data 访问数据 |
| :class="item.type" | attr:type="$data.type" | 属性绑定也必须使用 $data |
| ❌ 错误写法 | ✅ 正确写法 | 说明 |
|------------|-----------|------|
| .click(handler) | .on("click", handler) | 事件绑定使用 .on() 方法 |
| .hide() .show() | .style.display = "none" / "" | 没有 jQuery 风格的 show/hide 方法 |
| .html("xxx") .text("xxx") | .html = "xxx" .text = "xxx" | 直接设置属性而非调用方法 |
| ofaElement.addEventListener() | ofaElement.on() | ofa.js 对象使用 on() 方法 |
| this.shadow.getElementById("id") | this.shadow.$("#id") | shadow 是 ofa.js 对象,使用 $() 方法 |
| this.shadow.querySelector(".class") | this.shadow.$(".class") | 使用 $() 方法选择元素 |
| ofaElement.scrollTop 等 | ofaElement.ele.scrollTop | ofa.js 对象通过 .ele 访问原生属性 |
| ❌ 错误写法 | ✅ 正确写法 | 说明 |
|------------|-----------|------|
| <script> 在 <template> 外部 | <script> 在 <template> 内部 | script 必须放在 template 标签内部 |
| export default async () => ({...}) | export default async ({ query }) => ({...}) | 页面模块应使用参数形式接收 query |
| <o-fill><template><div>...</div></template></o-fill> | <o-fill><div>...</div></o-fill> | 直接渲染不需要 template 包裹 |
| <template> 在 o-fill 内部 | <template> 在 o-fill 外部 + name 属性 | 模板渲染时 template 必须在外部 |
数据固有属性(如 type、status、level)应使用 attr: + 属性选择器,样式状态切换(如 active、disabled)才使用 class: + 类名选择器。
❌ 错误写法(将数据属性作为类名):
<div class="message" :class="$data.type">
{{$data.text}}
</div>
<style>
.message.sent { color: blue; }
.message.received { color: green; }
</style>
✅ 正确写法(使用属性绑定):
<div class="message" attr:type="$data.type">
{{$data.text}}
</div>
<style>
.message[type="sent"] { color: blue; }
.message[type="received"] { color: green; }
</style>
为什么这样更好?
type 是消息类型的属性,不是样式类通过 $() 获取的是 ofa.js 包装对象,提供增强方法和响应式特性;通过 .ele 属性访问原生 DOM 元素。
shadow 对象的选择器方法:this.shadow 返回的是 ofa.js 实例化的对象,不是原生 ShadowRoot。
❌ 错误写法(使用原生 API):
const messagesDiv = this.shadow.getElementById("messages");
const element = this.shadow.querySelector(".class");
✅ 正确写法(使用 ofa.js API):
const messagesDiv = this.shadow.$("#messages");
const element = this.shadow.$(".class");
原生 DOM 属性访问:element.$() 返回 ofa.js 包装对象,原生属性需通过 .ele 访问。
❌ 错误写法(直接操作 ofa.js 对象):
const messagesDiv = this.shadow.$("#messages");
messagesDiv.scrollTop = messagesDiv.scrollHeight; // scrollTop 是原生属性
✅ 正确写法(通过 .ele 访问原生属性):
const messagesDiv = this.shadow.$("#messages");
messagesDiv.ele.scrollTop = messagesDiv.ele.scrollHeight;
使用场景:
.on(), .text, .html 等).ele 访问原生 DOM 属性(如 .scrollTop, .scrollHeight, .clientWidth 等)<template page> 内包含 <style>、模板内容和 <script>,script 必须在 template 内部<template component> 内包含 <style>、模板内容和 <script>,script 必须在 template 内部,返回对象中必须包含 tag 字段<template page>
<style>
:host { display: block; }
</style>
<div>{{message}}</div>
<script>
export default async ({ query }) => {
return {
data: { message: "Hello" },
proto: { handleClick() {} }
};
};
</script>
</template>
<template component>
<style>
:host { display: block; }
</style>
<div>{{value}}</div>
<script>
export default async () => {
return {
tag: "my-component",
attrs: { value: "default" },
data: { count: 0 },
proto: { increment() {} }
};
};
</script>
</template>
| 语法 | 用途 | 示例 |
|------|------|------|
| {{var}} | 文本渲染 | <span>{{name}}</span> |
| :html | HTML 内容渲染 | <div :html="htmlContent"></div> |
| :prop="key" | 单向属性绑定 | <input :value="name"> |
| sync:prop="key" | 双向属性绑定 | <input sync:value="name"> |
| attr:name="key" | HTML 属性绑定 | <a attr:href="url"> |
| class:name="bool" | 条件类绑定 | <div class:active="isActive"> |
| :style.prop="value" | 样式属性绑定 | <p :style.color="textColor"> |
| on:event="handler" | 事件绑定 | <button on:click="handleClick"> |
| on:event="expr" | 表达式事件 | <button on:click="count++"> |
| $event | 事件对象 | on:click="handle($event)" |
proto 中使用 get xxx() {} 而非 computed$.stanz() 创建<o-fill> 组件<o-if> / <o-else-if> / <o-else> 组件<x-if> / <x-fill> 功能相同但不渲染到 DOM:toKey="fromKey" 单向,sync:toKey="fromKey" 双向watch: { prop() {} }ready() attached() detached()this.emit('event-name', { data: {...} })<slot></slot> 接收外部内容是否需要可复用的组件?
├─ 是 → 使用组件模块(<template component> + tag 字段)
└─ 否 → 使用页面模块(<template page>)
是否需要共享数据?
├─ 是 → 是否跨多层组件?
│ ├─ 是 → 使用 o-provider/o-consumer
│ └─ 否 → 使用 sync: 双向绑定 或 : 单向传递
└─ 否 → 使用 data 定义本地数据
列表渲染?
├─ 是 → 使用 o-fill 组件
│ ├─ 直接渲染(简单结构)→ 模板内容直接写在 o-fill 内部,不需要 <template> 包裹
│ └─ 模板渲染(复杂结构/复用)→ <template> 定义在 o-fill 外部,使用 name 属性绑定
└─ 否 → 正常编写模板
条件渲染?
├─ 是 → 使用 o-if/o-else-if/o-else 组件
└─ 否 → 正常编写模板
o-fill 直接渲染(推荐用于简单结构):
<o-fill :value="messages">
<div class="message" attr:type="$data.type">
[{{$data.time}}] {{$data.text}}
</div>
</o-fill>
$data、$index、$host 访问数据o-fill 模板渲染(用于复杂结构或复用):
<o-fill :value="products" name="product-template"></o-fill>
<template name="product-template">
<div class="product-card">{{$data.name}} - ¥{{$data.price}}</div>
</template>
需要根据数据设置样式?
├─ 数据固有属性(如 type、status、level)→ 使用 attr: + 属性选择器
└─ 样式状态切换(如 active、disabled)→ 使用 class: + 类名选择器
是否需要多页面应用?
├─ 是 → 使用 o-router + o-app
│ └─ 是否需要嵌套布局?
│ ├─ 是 → 父页面使用 <slot>,子页面导出 parent
│ └─ 否 → 独立页面
└─ 否 → 单页面应用
| 文档 | 说明 | |------|------| | 模板语法案例与语法说明 | 所有模板语法的完整案例和详细说明(最高优先级) | | 快速参考表 | API 和语法速查表 | | API 参考手册 | 完整 API 文档 | | 常见模式与最佳实践 | 常用代码模式 |
| 文档 | 说明 | |------|------| | 介绍 | 框架核心概念和优势 | | 脚本引用 | 引入方式 | | 快速上手 | 快速入门 | | 创建第一个应用 | 使用 OFA Studio 创建项目 | | 生产与部署 | 开发环境、生产部署、压缩混淆 |
| 速查语法 | 文档 |
|----------|------|
| {{变量}} :html | 内容渲染 |
| on:click="handler" | 事件绑定 |
| :prop="value" sync:prop="value" | 属性绑定 |
| class:active="isActive" :style.width="val" | 类/样式绑定 |
| <o-if :value="condition"> | 条件渲染 |
| <o-fill :value="list"> | 列表渲染 |
| get computedProp() {} | 计算属性 |
| watch: { prop() {} } | 侦听器 |
| ready() attached() detached() | 生命周期 |
| 速查语法 | 文档 |
|----------|------|
| <template component> tag attrs | 创建组件 |
| export default async ({ load, url, query }) | 模块返回对象属性 |
| <slot></slot> | 插槽 |
| this.emit('event') | 自定义事件 |
| attrs: { msg: 'default' } | 传递特征属性 |
| :toProp="fromProp" | 领悟属性绑定 |
| {{obj.nested.prop}} | 属性响应 |
| <inject-host> | 注入宿主样式 |
| <x-if> <x-fill> | 非显式组件 |
| <template is="replace-temp"> | 替换模板 |
| <match-var> | 样式查询 |
| 速查语法 | 文档 |
|----------|------|
| o-provider o-consumer | 上下文状态 |
| $.stanz() | 状态管理 |
| o-app o-router | 路由 |
| 父页面 <slot> 子页面 parent | 嵌套页面/路由 |
| app-config.js | 应用配置 |
| o-app 微应用 | 微应用 |
| SCSR 同构渲染 | SSR 与同构渲染 |
| 案例 | 功能要点 | 入口 | 关键文件 | |------|----------|------|----------| | 计数器 | 数据绑定、事件、计算属性、样式 | demo.html | page.html | | 开关组件 | 组件定义、属性传递、事件、插槽 | demo.html | switch.html, page.html | | 待办列表 | 数据持久化、列表渲染、状态管理 | demo.html | page.html, data.js | | 文件编辑器 | 嵌套组件通信、o-provider、依赖注入 | demo.html | page.html, filelist.html, editor.html | | SPA 路由 | o-router、o-app、页面动画 | demo.html | app-config.js, layout.html | | SCSR 渲染 | 服务端渲染、SEO、同构应用 | home.html | app-config.js | | Shadow DOM | shadow 操作、组件方法定义 | demo.html | shadow-demo.html |
development
ofa.js 框架教程。当用户询问 ofa.js 的使用方法、组件开发、页面模块,或想要构建无需 Node.js/Webpack 的 Web 应用时使用。
development
ofa.js 框架教程。当用户询问 ofa.js 的使用方法、组件开发、页面模块,或想要构建无需 Node.js/Webpack 的 Web 应用时使用。
development
Complete documentation knowledge base for ofa.js framework. Use when users ask about ofa.js usage, component development, page modules, routing configuration, state management, or want to build Web applications without Node.js/Webpack.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.