base/README.md

305 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# @apigo.cc/base - AI 逻辑操作说明书 (示例驱动)
本库是基于 `@apigo.cc/state` 增强的 UI 原子库,提供遵循 Bootstrap 5.3 规范的高阶业务组件。本包采用完全的全局注入模式。
---
## 全局变量与核心 API 清单
引入 `base.js` 后,以下对象将直接挂载到 `window` / `globalThis` 上,可随时随地调用:
| 全局变量名 | 用途说明 |
| :--- | :--- |
| **`HTTP`** | 异步请求工具 (`HTTP.get`, `HTTP.post`, `HTTP.request` 等)。 |
| **`UI`** | 交互组件触发器 (`UI.toast`, `UI.alert`, `UI.confirm`, `UI.showDialog`)。 |
| **`AutoForm`** | 表单组件扩展注册器 (`AutoForm.register`) 和自定义控件库 (`AutoForm.customTypes`)。 |
| **`MouseMover`** | 拖拽辅助工具 (`MouseMover.start`)。 |
| **`VirtualScroll`** / **`List`** | 虚拟滚动列表核心算法类。 |
*(注意:底层状态库 `@apigo.cc/state` 暴露的 `NewState`, `Hash`, `LocalStorage`, `State`, `$`, `$$`, `Component` 以及危险的高级 API `_unsafeRefreshState` 也在全局可用。严禁随意调用 `_unsafeRefreshState`。)*
---
## 1. 快速集成 (Quick Start)
将脚本放置在 `<head>` 中,确保地基在 DOM 解析前就绪:
```html
<!-- 1. 基础状态机 (地基) -->
<script src="dist/lib/state.js"></script>
<!-- 2. Bootstrap 适配层 -->
<script src="dist/lib/bootstrap.js"></script>
<!-- 3. 本业务组件库 (原生注入) -->
<script src="dist/lib/base.js"></script>
<script>
// 4. 数据先行 (在 body 解析前定义)
window.brand = { label: 'My App' };
</script>
```
---
## 2. 组件超能力示例 (Mega Examples)
### 2.1 声明式数据组件 (`<API>`)
```html
<API id="userSearchApi" auto
$request='{
"url": "/api/users/search",
"method": "POST",
"data": { "keyword": State.searchKey }
}'
$onresponse="console.log('加载成功,响应对象:', event.detail); State.userList = event.detail.result"
$onerror="UI.toast('加载失败:' + event.detail.message, { type: 'danger' })">
</API>
<script>
// 手动调用 API 示例 (适合动态触发/事后赋值场景)
async function forceReload() {
try {
// do() 返回 Promise<ResponseObject>。传入 noui: true 屏蔽全局 UI 弹窗报错。
const resp = await userSearchApi.do({ noui: true });
console.log("手动加载完成,结果:", resp.result);
} catch (err) {
console.error("请求失败", err);
}
}
</script>
```
* **AI 核心要点**
* **请求响应结构 (ResponseObject)**
`{ ok: Boolean, status: Number, headers: Object, responseType: 'json'|'binary'|'text', result: Any, error: String|null }`
* 深度监听 `request` 任何字段的改变自动触发请求(微任务防抖)。`response` 事件为 `bubbles: false``error``bubbles: true`
---
### 2.2 万能表单与内嵌控件 (`<AutoForm>`)
```html
<script>
// 1. 预先确定表单 Schema (合并了所有扩展控件配置)
const employeeFormSchema = [
{ name: 'name', label: '姓名', type: 'text', setting: { required: true } },
{
name: 'joinDate',
label: '入职周期',
type: 'DatePicker', // 内置日期范围选择控件
setting: { rangeEnd: 'leaveDate' } // 影子字段绑定为 leaveDate
},
{ name: 'color', label: '工位颜色', type: 'ColorPicker' }, // 内置颜色控件
{ name: 'avatarIcon', label: '头像图标', type: 'IconPicker' }, // 内置图标控件
{ name: 'skills', label: '专业技能', type: 'TagsInput' }, // 内置多标签控件
{
name: 'role',
label: '角色',
type: 'select',
options: [{ label: '管理员', value: 'admin' }, { label: '员工', value: 'staff' }],
placeholder: '请选择角色...'
},
{
name: 'status',
label: '状态',
type: 'checkbox',
options: ['在职', '离职'],
if: "this.data.age > 18" // 仅在 age > 18 时渲染this 访问 AutoForm 实例
},
{ name: 'notify', label: '启用通知', type: 'switch' }
];
</script>
<!-- 2. HTML 声明式属性绑定 schema 状态,且绑定接口 API 实例 -->
<AutoForm id="employeeForm"
vertical
$.state.schema="employeeFormSchema"
$api="saveEmployeeApi"
$onresponse="UI.toast('保存成功!')">
</AutoForm>
<script>
// 3. 数据层回显/事后赋值操作 (使用 Object.assign 保证绑定的 Proxy 响应式链路不丢失)
Object.assign(employeeForm.state.data, {
name: '张三',
joinDate: '2026-06-01',
leaveDate: '2026-06-30',
color: '#ff0000',
avatarIcon: 'person',
skills: ['Vue', 'React'],
role: 'staff',
notify: true
});
</script>
```
* **AI 核心要点**
* 容器属性:`vertical` (垂直排列)、`inline` (无边框流式行内布局)、`nobutton` (隐藏底部默认按钮)。
* **表单数据操作红线**:禁止对 `form.state.data``form.data` 执行覆盖式重新赋值,必须使用 `Object.assign`
---
### 2.3 增强列表组件 (`<List>`)
列表有三类布局模式,分别有不同的数据结构关联,均推荐在 HTML 中声明绑定:
#### 模式一:普通扁平列表 (`mode="normal"`)
* **关联逻辑**:直接渲染一维数组项。
* **数据结构**
```javascript
const userList = [
{ id: '1', label: '小明', summary: '前端开发' },
{ id: '2', label: '小红', summary: '产品经理' }
];
```
* **HTML 写法**
```html
<List mode="normal" $list="userList" $onitemclick="console.log(event.detail.item)"></List>
```
#### 模式二:分组列表 (`mode="group"`)
* **关联逻辑**`list` 的项通过 `group` 字段去匹配 `groups` 数组中的 `id` 字段。
* **数据结构**
```javascript
const deptGroups = [
{ id: 'devGroup', label: '研发中心', summary: '共 5 人' },
{ id: 'hrGroup', label: '人力资源', summary: '共 2 人' }
];
const groupUserList = [
{ id: '1', label: '小明', group: 'devGroup' },
{ id: '2', label: '小红', group: 'hrGroup' }
];
```
* **HTML 写法**
```html
<List mode="group" $list="groupUserList" $.state.groups="deptGroups"></List>
```
#### 模式三:树形可折叠列表 (`mode="tree"`) —— 超级示例
* **关联逻辑**:通过每项的 `parent` 关联父项的 `id` 属性,根项的 `parent` 设为空字符串 `''`。
* **数据结构**(内置 `_itemHeight` 优化虚拟滚动高度测量):
```javascript
const deptTreeList = [
{ id: '1', label: '总经办', parent: '', _itemHeight: 40 },
{ id: '2', label: '研发部', parent: '1', _itemHeight: 40 },
{ id: '3', label: '开发组', parent: '2', _itemHeight: 40 }
];
```
* **HTML 写法**
```html
<List id="orgTreeList"
mode="tree"
fast
collapsible
auto-select
class="overflow-auto border"
style="height: 400px;"
$list="deptTreeList"
$onitemclick="console.log('点击节点:', event.detail.item, '全局绝对索引:', event.detail.index)">
<!-- 自定义单项右侧动作区域 -->
<template slot-id="item">
<span class="fw-semibold text-primary" $text="item.label"></span>
<div slot-id="item-actions">
<button class="btn btn-sm btn-link py-0 bi bi-plus-circle" onclick="addNode(item)"></button>
</div>
</template>
</List>
```
* **AI 核心要点**
* **属性默认值**:当数据结构符合默认字段命名(`id`, `label`, `summary`, `parent`, `group`)时,**无须填写**任何映射属性(如 `idfield`, `labelfield`, `parentfield` 等),实际编写代码时应当将其省略。
* 虚拟滚动 (`fast`) 强制容器必须声明为 `overflow-auto` 类。
---
### 2.4 导航组件 (`<Nav>`)
```html
<script>
// 1. 预先确定品牌与菜单数据
const myBrand = { icon: 'shield-lock', label: '安全控制台' };
const myNavList = [
{ type: 'button', name: 'dashboard', label: '仪表盘', icon: 'speedometer' },
{
type: 'dropdown',
name: 'settings',
label: '系统设置',
icon: 'gear',
list: [
{ type: 'button', name: 'profile', label: '个人信息', icon: 'person' },
{ type: 'switch', name: 'darkMode', label: '暗黑模式', icon: 'moon', bind: LocalStorage, name: 'darkMode' }
]
},
{ type: 'fill' },
{ type: 'button', name: 'logout', label: '退出登录', icon: 'box-arrow-right', noselect: true }
];
</script>
<!-- 2. HTML 声明式属性绑定 -->
<Nav id="sidebarNav"
vertical
$.state.brand="myBrand"
$.state.list="myNavList"
$onnav="console.log('导航点击:', event.detail.item)">
</Nav>
```
* **AI 核心要点**
* 常规导航项被点击时(且 `noselect` 不为 true会自动更新全局 `Hash.nav = item.name`。
---
### 2.5 拖拽改变大小组件 (`<Resizer>`)
```html
<div class="d-flex" style="height: 300px;">
<div id="leftPanel" style="width: 200px;" class="bg-light">侧边栏</div>
<!-- 拖拽调节器,默认 target 为前一个兄弟节点 -->
<Resizer target="leftPanel"
min="100"
max="400"
$onresizing="console.log('拖动尺寸:', event.detail.newSize)"
$change="State.leftPanelWidth">
</Resizer>
<div class="flex-fill">内容区</div>
</div>
```
* **AI 核心要点**
* `resizing` 与 `resize` 事件的 `detail` 结构均为 `{ oldSize: Number, newSize: Number }``change` 事件的 `detail` 为 `newSize` 像素数字。
---
## 3. 网络与交互工具集 (`HTTP` & `UI`)
### 3.1 HTTP 请求工具 (`HTTP`)
```javascript
// 支持 HTTP.get, HTTP.post, HTTP.put, HTTP.delete, HTTP.head
const resp = await HTTP.post({
url: '/api/user/save',
data: { name: 'Alice', file: avatarFile },
timeout: 5000
});
```
* **返回值 `ResponseObject` 结构**
* `ok` (Boolean): 状态码是否在 200-299。
* `status` (Number): HTTP 状态码。
* `headers` (Object): 响应头键值对。
* `responseType` (String): `'json' | 'binary' | 'text'`。
* `result` (Any): 成功后的解析结果。
* `error` (String | null): 失败的错误描述。
* **数据自动转换**:若 `data` 内包含 `File`/`Blob`,自动转为 `FormData` 且清除 Content-Type普通对象自动序列化为 JSON 并添加 `application/json`。
### 3.2 交互工具 (`UI`)
* **`UI.showDialog({ title, message, buttons, type })`**
* **返回值**`Promise<Number>`。点击按钮返回其索引值 (从 `1` 开始),点击关闭或取消返回 `0`。
* **参数**`type` 可以为 `'primary'|'danger'|'warning'|'success'` 控制主题色;`message` 支持 HTML。
* **`UI.alert(message, options)`**
* **返回值**`Promise<Boolean>`(点击关闭按钮返回 `false`)。
* **`UI.confirm(message, options)`**
* **返回值**`Promise<Boolean>`。点击“确认”返回 `true`,点击“取消”或关闭返回 `false`。
* **`UI.toast(message, options)`**
* **返回值**`void`。`options.delay` 为自动消失延迟毫秒(`0` 代表不消失)。可以通过传入 `buttons: ['选项1']` 按钮提供交互,点击后在实例 `result` 上保存索引。
* **`UI.toastConfirm(message, options)`**
* **返回值**`Promise<Boolean>`。在 Toast 中提供单确认按钮,点击确认返回 `true`,否则返回 `false`。
---
## 4. 开发红线 (Constraints)
1. **表单数据操作红线**:严禁直接覆盖表单的 `state.data` 或 `data` 对象(如 `form.data = {}`)。这会切断与内部 Proxy 的响应式链路。必须使用 `Object.assign(form.state.data, newData)`。
2. **结构化指令红线**:所有 `$if` 与 `$each` 指令 **必须** 显式作用于 `<template>` 标签,且严禁在同一个 `<template>` 上同时使用两者(必须嵌套)。
3. **列表布局红线**:开启虚拟滚动(`fast`)时,容器必须包含 `overflow-auto` 类。
4. **指令 DOM 保护**:严禁使用原生 DOM API 直接修改由 `$each`、`$if` 或组件渲染指令生成的 DOM 节点。所有 DOM 状态的变化应当完全通过修改与之绑定的底层 `State` 属性驱动。
5. **退出拦截约束**:在全局配置有 `State.exitBlocks > 0` 时,框架将强行拦截并警告任何刷新/关闭页面的行为。