diff --git a/CAPABILITY.md b/CAPABILITY.md index c22626a..b2b007b 100644 --- a/CAPABILITY.md +++ b/CAPABILITY.md @@ -250,8 +250,6 @@ - **`collapsible`** (Boolean): 仅在 `tree` 模式下有效,开启树形节点的展开/收起能力。 - **`auto-select`** (Boolean): 开启后,点击列表项时自动将该项的 `id` 记录至 `state.selectedItem`,如果重复点击则会置空。 - **`auto-select-group`** (Boolean): 开启后,点击分组时自动将分组的 `id` 记录至 `state.selectedGroup`。 -- **`filter`** (String): 筛选关键字。支持通过 attribute 传入以自动同步至 `state.filter`。 -- **`order`** (String): 排序规则。支持通过 attribute 传入以自动同步至 `state.order`。 ### 4. 内部状态模型 (`State`) - `list` (读写): 原始列表数据数组。 @@ -259,11 +257,15 @@ - `collapsed` (读写): 仅在 `tree` 且 `collapsible` 时使用,存储节点 ID 折叠状态的 Map Proxy。 - `selectedItem` (读写): 当前选中的列表项 ID。 - `selectedGroup` (读写): 当前选中的分组 ID。 -- `filter` (读写): 筛选关键字(进行 label 和 summary 的不区分大小写模糊匹配)或自定义过滤函数 `(item) => boolean`。 -- `order` (读写): 排序规则。可为排序字段名(例如 `'name'`;前缀 `-` 表示降序,如 `'-name'`;或者后缀 `'desc'`/`'asc'` 语法,如 `'name desc'`),也可以为自定义排序函数 `(a, b) => number`。 +- `filter` (读写): 筛选规则。可为字符串(对 label 和 summary 进行忽略大小写的模糊包含匹配)或对象 `{ [key]: query }`(对对象特定字段进行模糊包含匹配)。 +- `order` (读写): 排序规则。可为字段名字符串(例如 `'name'`;支持前缀 `-` 表示降序,如 `'-name'`;或者后缀 `'desc'`/`'asc'` 语法,如 `'name desc'`)。 - `_flatList` (只读): 列表核心逻辑处理后的扁平化数组。 - `_renderedList` (只读): 实际在 DOM 中遍历渲染的数组片段(若开启虚拟滚动,则只包含可视区切片)。 +### 5. 实例属性 (DOM Node Properties) +- `filterFunc` (读写): 自定义过滤函数 `(item) => boolean`。设置后会重绘列表。 +- `orderFunc` (读写): 自定义排序比较函数 `(a, b) => number`。设置后会重绘列表。 + ### 5. 插槽 (Slots) - **`item`**:列表单项渲染模板插槽。在自定义模板中,可以访问当前行数据 `item` 和索引 `index`。 - **`item-actions`**:行数据右侧按钮工具栏区域。 diff --git a/README.md b/README.md index 9bfbb8e..4289368 100644 --- a/README.md +++ b/README.md @@ -1,314 +1,839 @@ -# @apigo.cc/base - AI 逻辑操作说明书 (示例驱动) +# @apigo.cc/base -本库是基于 `@apigo.cc/state` 增强的 UI 原子库,提供遵循 Bootstrap 5.3 规范的高阶业务组件。 +`@apigo.cc/base` 是基于 `@apigo.cc/state` 和 Bootstrap 5.3 的同步组件层。页面只需要按顺序引入脚本,就能在首屏完成 DOM 处理和组件渲染。 ---- +## 目录 -## 1. 快速集成 (Quick Start) +- [依赖加载](#依赖加载) - 同步加载顺序和来源说明 +- [全局变量](#全局变量) - 本包直接挂到 `window` 的变量 +- [HTTP](#http) - 请求工具 +- [API](#api) - 声明式请求节点 +- [AutoForm](#autoform) - 自动表单节点 +- [表单扩展控件](#表单扩展控件) - `DatePicker` / `ColorPicker` / `IconPicker` / `TagsInput` +- [List](#list) - 普通、分组、树形和虚拟滚动列表 +- [Nav](#nav) - 水平导航栏或垂直侧边栏 +- [Modal / Dialog](#modal--dialog) - 弹窗容器和确认弹窗 +- [Resizer](#resizer) - 拖拽分隔条 +- [UI](#ui) - toast 和对话框工具 +- [VirtualScroll / MouseMover](#virtualscroll--mousemover) - 虚拟滚动和鼠标拖拽辅助 -### 同步 UMD 集成 (推荐:消灭异步时序风险,实现“秒开”渲染) -将脚本放置在 `` 中,确保地基在 DOM 解析前就绪: +## 依赖加载 + +按顺序同步加载: + +`@apigo.cc/state` -> `@apigo.cc/bootstrap` -> `@apigo.cc/base` + +`base` 会直接使用来自 `@apigo.cc/state` 的全局对象 `State`、`Hash`、`LocalStorage`。 + +- [state 文档](https://apigo.cc/web/state) + +### 推荐加载顺序 -**本地引入示例:** ```html - - - - - - -``` - -**CDN 引入示例:** -```html - - - + - - -``` - + ``` -### ESM 模块引入 (Legacy) -```javascript -const { HTTP, UI, AutoForm, State } = window.ApigoBase +### 全局变量 + +| 变量 | 说明 | +|---|---| +| `HTTP` | 请求工具 | +| `UI` | 提示、确认、对话框工具 | +| `AutoForm` | 自动表单容器和扩展注册器 | +| `VirtualScroll` | 虚拟滚动工具 | +| `MouseMover` | 鼠标拖拽位移工具 | + +## HTTP + +`HTTP` 只处理请求,不处理 UI。 + +### 方法 + +| 方法 | 写法示例 | 说明 | +|---|---|---| +| `HTTP.request(options)` | `await HTTP.request({ url: '/api/user', method: 'POST', data: { id: 1 } })` | 通用请求入口 | +| `HTTP.get(...)` | `await HTTP.get({ url: '/api/user/1' })` | `GET` | +| `HTTP.post(...)` | `await HTTP.post({ url: '/api/user', data: form })` | `POST` | +| `HTTP.put(...)` | `await HTTP.put({ url: '/api/user/1', data: patch })` | `PUT` | +| `HTTP.delete(...)` | `await HTTP.delete({ url: '/api/user/1' })` | `DELETE` | +| `HTTP.head(...)` | `await HTTP.head({ url: '/api/user/1' })` | `HEAD` | + +### `HTTP.request` 参数 + +| 参数 | 类型 | 写法示例 | 说明 | +|---|---|---|---| +| `url` | `string` | `url: '/api/user'` | 必填 | +| `method` | `string` | `method: 'POST'` | 默认 `POST`,内部会转大写 | +| `data` | `any` | `data: { name: 'Alice' }` | 请求体 | +| `headers` | `object` | `headers: { Authorization: 'Bearer xxx' }` | 请求头 | +| `responseType` | `string` | `responseType: 'json'` | 可手动指定 | +| `timeout` | `number` | `timeout: 5000` | 默认 `10000` ms | + +### `HTTP` 对象属性 + +| 属性 | 写法示例 | 说明 | +|---|---|---| +| `keepHeaders` | `HTTP.keepHeaders = ['Session-Id']` | 需要跨请求保留的响应头名 | + +### Content-Type 规则 + +- `data` 是普通对象时,默认按 JSON 发送,并自动补 `Content-Type: application/json` +- `data` 是 `FormData` 时,不手动设置 `Content-Type`,让浏览器生成带 boundary 的 multipart 请求头 +- 如果你在 `headers` 里手动传了 `Content-Type`,普通对象请求会按你的设置发送;`FormData` 仍然以浏览器生成的请求头为准 + +### 返回值 + +```js +{ + ok, + status, + headers, + responseType, + result, + error +} ``` ---- +### 推荐示例 -## 2. 组件超能力示例 (Mega Examples) - -### 2.1 声明式数据组件 (``) ```html - + + + - + ``` -* **AI 核心要点**: - * **请求响应结构 (ResponseObject)**: - `{ ok: Boolean, status: Number, headers: Object, responseType: 'json'|'binary'|'text', result: Any, error: String|null }` - * 深度监听 `request` 任何字段的改变自动触发请求(微任务防抖)。`response` 事件为 `bubbles: false`,`error` 为 `bubbles: true`。 ---- +## API + +`` 是把请求封装成页面节点的方式。 + +### 属性和状态 + +| 名称 | 写法示例 | 说明 | +|---|---|---| +| `auto` | `` | 监听 `request` 变化后自动请求 | +| `request` | `$.request="window.userRequest"` | 请求配置对象 | +| `response` | `$.response="window.apiResponse"` | 最近一次请求状态 | +| `result` | `$.result="window.apiResult"` | 响应结果缓存 | + +### `request` 默认结构 + +```js +{ + url: '', + method: 'GET', + headers: {}, + data: null, + timeout: 10000, + responseType: '' +} +``` + +### `response` 默认结构 + +```js +{ + loading: false, + ok: null, + status: null, + error: null, + headers: {}, + responseType: '', + result: null +} +``` + +### 方法 + +| 方法 | 写法示例 | 说明 | +|---|---|---| +| `do(opt = {})` | `await userApi.do()` | 手动请求 | +| `opt.noui` | `await userApi.do({ noui: true })` | 失败时不弹 toast | + +### 事件 + +| 事件 | 触发时机 | `detail` | +|---|---|---| +| `response` | 请求成功 | 完整响应对象 | +| `error` | 请求失败或返回错误 | `Error` 对象 | + +### 备注 + +- `auto` 只在 `request.url` 存在时生效 +- `request` 深度变化会在微任务里触发一次请求,避免同一轮重复请求 + +## AutoForm + +`` 通过 `schema` 生成表单,适合和 `API`、`window` 上的页面数据直接联动。 + +### 属性 + +| 名称 | 写法示例 | 说明 | +|---|---|---| +| `vertical` | `` | 垂直布局 | +| `horizontal` | `` | 强制左右两列布局 | +| `inline` | `` | 行内紧凑布局 | +| `nobutton` | `` | 隐藏底部提交按钮 | +| `api` | `$.api="saveApi"` | 绑定 `` 实例或其引用 | +| `submitlabel` | `submitlabel="Search"` | 提交按钮文案,默认 `{#Submit#}` | + +### 状态和方法 + +| 名称 | 写法示例 | 说明 | +|---|---|---| +| `data` | `$.state.data="window.profile"` | 表单数据,建议用 `Object.assign` 更新 | +| `schema` | `$.state.schema="window.profileSchema"` | 表单定义 | +| `request` | `$.request="{ method: 'POST' }"` | 默认提交配置 | +| `response` | `$.response="window.formResponse"` | 最近一次提交结果 | +| `result` | `$.result="window.formResult"` | 最近一次提交的 `response.result` | +| `submit(opt = {})` | `form.submit()` | 主动提交 | + +### `schema` 字段 + +| 字段 | 写法示例 | 说明 | +|---|---|---| +| `name` | `name: 'role'` | 必填,数据键名 | +| `label` | `label: 'Role'` | 表单项标题 | +| `type` | `type: 'select'` | 控件类型 | +| `setting` | `setting: { required: true }` | 透传给控件的属性 | +| `options` | `options: ['A', 'B']` | `select` / `checkbox` / `radio` 选项 | +| `placeholder` | `placeholder: 'Please choose'` | `select` 的空值占位文案 | +| `if` | `if: 'this.data.enable'` | 条件渲染表达式 | + +### `if` 说明 + +- `if` 不是字符串模板拼接,而是表达式 +- 表达式执行时可直接访问 `this`、`State`、`Hash`、`LocalStorage`、`item`、`data` +- 这类条件是表单级动态渲染,适合做联动显隐 + +### 支持的 `type` + +| `type` | 用途 | +|---|---| +| `text` | 单行文本 | +| `password` | 密码 | +| `email` | 邮箱 | +| `number` | 数字 | +| `date` | 日期 | +| `datetime` | 日期时间 | +| `file` | 文件 | +| `select` | 下拉单选 | +| `checkbox` | 多选 | +| `radio` | 单选按钮组 | +| `switch` | 开关 | +| `textarea` | 多行文本 | +| `DatePicker` | 扩展日期控件 | +| `ColorPicker` | 扩展颜色控件 | +| `IconPicker` | 扩展图标控件 | +| `TagsInput` | 扩展标签控件 | + +### `options` 写法 + +```js +['Admin', 'Editor'] +[{ label: 'Admin', value: 'admin' }] +``` + +### 事件 + +| 事件 | 触发时机 | `detail` | +|---|---|---| +| `submit` | 表单校验通过、提交前 | 当前表单数据 | +| `response` | 提交成功 | 完整响应对象 | +| `error` | 提交失败 | `Error` 对象 | + +### 插槽 + +| 插槽 | 位置 | 用途 | +|---|---|---| +| `actions` | 默认提交按钮左侧 | 自定义动作按钮 | + +### 推荐示例 -### 2.2 万能表单与内嵌控件 (``) ```html - - + + - - ``` -* **AI 核心要点**: - * 容器属性:`vertical` (垂直排列)、`inline` (无边框流式行内布局)、`nobutton` (隐藏底部默认按钮)。 - * **表单数据操作红线**:禁止对 `form.state.data` 或 `form.data` 执行覆盖式重新赋值,必须使用 `Object.assign`。 ---- +### 编程注意 -### 2.3 增强列表组件 (``) +- 不要直接整体覆盖 `form.data` 或 `form.state.data` +- 需要更新时,优先用 `Object.assign(form.data, nextData)` -列表有三类布局模式,分别有不同的数据结构关联,均推荐在 HTML 中声明绑定: +### `AutoForm.register(name, typeName = '')` -#### 模式一:普通扁平列表 (`mode="normal"`) -* **关联逻辑**:直接渲染一维数组项。 -* **数据结构**: - ```javascript - const userList = [ - { id: '1', label: '小明', summary: '前端开发' }, - { id: '2', label: '小红', summary: '产品经理' } - ]; - ``` -* **HTML 写法**: - ```html - - ``` +注册可被 `schema.type` 识别的自定义控件。 -#### 模式二:分组列表 (`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 - - ``` +| 参数 | 写法示例 | 说明 | +|---|---|---| +| `name` | `AutoForm.register('MyPicker')` | 组件标签名 | +| `typeName` | `AutoForm.register('MyPicker', 'picker')` | 默认 `''`。只有当标签名和 `schema.type` 不同,或需要复用同一个标签名匹配另一个 `type` 时才传 | -#### 模式三:树形可折叠列表 (`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 - - - - - - ``` -* **AI 核心要点**: - * **属性默认值**:当数据结构符合默认字段命名(`id`, `label`, `summary`, `parent`, `group`)时,**无须填写**任何映射属性(如 `idfield`, `labelfield`, `parentfield` 等),实际编写代码时应当将其省略。 - * **筛选与过滤 (`filter`)**:可绑定筛选关键字字符串(对 label 和 summary 进行不区分大小写匹配,如 `$filter="State.searchKey || ''"`,加 `|| ''` 可方便地在输入清空时彻底重置)或自定义过滤函数 `(item) => boolean`。在 `tree` 树形模式下,过滤匹配会自动向上保留所有的祖先节点链,且仅保留匹配项分支;在 `group` 分组模式下,若分组自身或其下有任意项匹配则显示分组。 - * **排序与整理 (`order`)**:可绑定排序字段名字符串(如 `'name'`;前缀 `-` 表示降序,如 `'-name'`;或者后缀 `'desc'`/`'asc'` 语法,如 `'name desc'`),也可以绑定自定义排序比较函数 `(a, b) => number`。在 `tree` 树形模式下对同级子节点进行排序。 - * 虚拟滚动 (`fast`) 强制容器必须声明为 `overflow-auto` 类。 +### 什么时候传 `typeName` ---- +- 你想让 `` 处理 `schema.type === 'picker'` +- 你想把一个标签名映射成不同的 `type` +- 如果 `schema.type` 和标签名一致,直接省略第二个参数 + +## 表单扩展控件 + +这些控件既可以在 `AutoForm` 里作为 `schema.type` 使用,也可以单独放到页面上。单独使用时,直接绑定 `value`,再监听 `change` 即可。 + +### `` + +| 项目 | 说明 | +|---|---| +| `state.start` | 起始日期 | +| `state.end` | 结束日期 | +| `value` | 映射到 `state.start` | +| `isRange` | 是否启用范围模式 | +| `setting.rangeEnd` | 范围结束字段名 | +| `rangeEnd` | 组件属性形式的范围结束字段名 | +| `change` | 开始日期变化时触发,`detail` 为开始日期字符串 | + +### `` 示例 -### 2.4 导航组件 (`