20 KiB
20 KiB
@apigo.cc/base 能力清单 (Capability Specification)
一、 全局导出与生命周期行为
1. 导出与全局挂载
- 模块导出:
index.js重新导出了http.js,ui.js,form.js,controls.js,list.js,nav.js,interaction.js中的所有对象,以及来自@apigo.cc/state的State。 - 全局命名空间挂载:在
window/globalThis上挂载了HTTP,UI,AutoForm,MouseMover,VirtualScroll,ApigoBase。 - 初始化自动刷新:页面加载时(
DOMContentLoaded或立即执行),对document.documentElement执行RefreshState()。
2. 退出拦截逻辑
- 拦截触发条件:当
State.exitBlocks > 0时,通过window.addEventListener('beforeunload')拦截页面刷新或关闭(调用event.preventDefault())。
3. 主题自动适配
- 逻辑行为:若
<html>元素上既没有data-bs-theme也没有$data-bs-theme,则自动注入属性:$data-bs-theme="LocalStorage.darkMode?'dark':'light'"。
二、 HTTP 请求引擎 (HTTP)
1. 核心方法
HTTP.request(options)(异步)- 参数类型:
options: Objecturl(String, 必填): 请求地址。method(String, 可选): 默认'POST'。会内部自动转为大写。data(Any, 可选): 请求载荷。headers(Object, 可选): 默认{}。responseType(String, 可选):'json' | 'binary' | 'text'。若未提供,将根据响应头Content-Type自动解析(含application/json解析为'json',匹配图片/音视频/zip/pdf等解析为'binary',其余解析为'text')。timeout(Number, 可选): 默认10000(ms)。基于AbortSignal.timeout实现。
- 请求载荷 (
data) 自动处理逻辑:- 若
data为HTMLFormElement,内部自动转换为FormData。 - 若
data为普通对象,且其属性中包含File,Blob,FileList实例,内部自动转换为FormData。其中,FileList或Array属性会依次 append 到相同 key 下,排除undefined/null。 - 若数据最终为
FormData,则 自动删除headers['Content-Type'](由浏览器自动设置 boundary)。 - 若数据为普通对象且非二进制,且
headers中无Content-Type,则序列化为 JSON 字符串并自动添加headers['Content-Type'] = 'application/json'。
- 若
- 返回值:
Promise<ResponseObject>,其结构为:{ ok: Boolean, // 请求是否成功 (status 在 200-299) status: Number, // HTTP 状态码 headers: Object, // 响应头键值对 responseType: String, // 实际解析后的响应类型 ('json' | 'binary' | 'text') result: Any, // 响应数据主体 error: String | null // 错误信息 (若请求失败或 ok === false) }
- 参数类型:
- 快捷方法 (内部包装
HTTP.request):HTTP.get({ url, ...opt })HTTP.post({ url, data, ...opt })HTTP.put({ url, data, ...opt })HTTP.delete({ url, ...opt })HTTP.head({ url, ...opt })
三、 声明式数据组件 (<API>)
1. 响应式状态模型 (State)
request(读写): 映射请求参数。结构与HTTP.request参数一致:{ url: '', method: 'GET', headers: {}, data: null, timeout: 10000, responseType: '' }response(读写): 包含当前请求执行结果。结构为:{ loading: false, ok: null, status: null, error: null, headers: {}, responseType: '', result: null }result(读写): 响应结果快捷引用。当response.result为对象时,底层通过Object.assign合并更新;否则直接覆盖。
2. 编程接口方法 (Methods)
do(opt = {})- 用途:手动执行请求。
- 参数:
opt对象的字段(如headers,data等)会与request属性合并。 - 控制参数:
opt.noui(Boolean)。若为true,则在请求失败时不自动调用UI.toast弹窗。 - 返回值:
Promise<ResponseObject>。若请求失败或接口返回{ error: ... },Promise 会抛出异常(reject)。
3. 特殊逻辑行为
auto(Attribute): 若组件含有auto属性,且request.url非空,则深度监听request对象的变化。一旦变化,会在下一微任务队列(Promise.resolve())自动、异步触发do()。有防抖机制,避免同一周期多次触发。
4. 事件派发
response:请求成功时触发。bubbles:falsecancelable:falsedetail: 完整的ResponseObject对象。
error:请求失败(网络错误、非2xx状态码、或返回数据中含error字段)时触发。bubbles:truecancelable:falsedetail: Error 对象。
四、 万能表单系统 (<AutoForm>)
1. 容器属性 (Attributes)
vertical(Boolean): 开启垂直表单布局。inline(Boolean): 开启无边框的流式行内布局(常用于顶部工具栏)。nobutton(Boolean): 隐藏底部的默认提交/保存按钮。api(String / Element): 绑定页面中<API>组件的 ID(或直接为组件实例引用),以便在提交时自动对接。submitlabel(String): 自定义提交按钮的文本内容。默认为"{#Submit#}"。
2. 实例编程接口
data(读写): 表单内部数据的响应式 Proxy 模型(映射至state.data)。可直接通过Object.assign(form.data, newData)或逐个属性赋值来修改表单中的值。request(读写): 默认提交配置,默认为{ method: 'POST' }。response(只读): 提交请求返回的完整响应对象。result(只读): 提交请求返回的response.result。submit(opt = {})- 用途:手动触发表单校验与提交。
- 校验逻辑:通过原生
form.reportValidity()校验。若失败,调用UI.toast提示"{#verify failed#}"并退出。 - 提交逻辑:如果绑定了
api属性,则调用api.do(req)(其中req.data自动绑定为表单data);否则,如果配置了request.url,则直接调用HTTP.request(req);两者皆无则在控制台抛出警告。
3. Schema 项目 (FormItem) 结构定义
state.schema 数组中每一项可配置的字段:
name(String, 必填): 数据字段键名,与form.data中的属性双向绑定。label(String, 可选): 表单项标签名称(仅在非inline模式下展示)。type(String, 必填): 表单控件类型。- 原生支持:
'text','password','email','number','date','datetime','file','select','checkbox','radio','switch','textarea'。 - 扩展注册支持:如
'DatePicker','ColorPicker','IconPicker','TagsInput'。
- 原生支持:
if(String, 可选): 控制是否显示该表单项的条件表达式字符串。使用双重计算渲染($$if),其执行上下文中this指向 AutoForm 组件实例,可以通过this.data引用其他字段值。setting(Object, 可选): 原生属性透传对象,会通过$.="item.setting || {}"绑定到控件上。options(Array, 可选): 针对select,checkbox,radio类型。- 格式可以为扁平字符串数组:
['Option1', 'Option2'] - 也可以为键值对数组:
[{ label: '选项1', value: 'val1' }]
- 格式可以为扁平字符串数组:
placeholder(String, 可选): 仅对select类型有效,表示未选中时的禁用占位选项。vertical(Boolean, 可选): 仅对checkbox或radio类型有效。若为true,各选项纵向排列;默认为false(横向排列)。text/label(String, 可选): 当checkbox或radio未提供options选项时,使用此值作为单选项的标签,其选中时的值是'on'。
4. 插槽 (Slots)
actions:在表单底部提交按钮左侧的区域插槽(仅在非inline且非nobutton模式下渲染)。
5. 事件派发
submit:在开始提交数据前触发。bubbles:falsecancelable:true(调用event.preventDefault()可彻底终止提交动作)detail: 当前表单的数据对象container.data。
response:表单自动提交成功并得到接口响应后触发。bubbles:falsecancelable:falsedetail: 完整的响应对象resp。
error:提交失败(网络错、校验错或返回的 json 带有 error 字段)时触发。bubbles:truecancelable:falsedetail: Error 对象。
6. 表单控件扩展机制 (AutoForm.register)
AutoForm.register(name, typeName)- 用途:将第三方/自定义 Web Component 注册为表单的自定义控件类型。
- 参数:
name(String): 组件标签名(如'DatePicker')。typeName(String, 可选): schema 中对应的type字符串。不传则默认等同于name。
- 实现逻辑:当在 AutoForm 的
schema中匹配到对应type时,自动在 DOM 树中插入该自定义组件,并将其属性$.绑定为item.setting,其值bind双向绑定到 AutoForm 的对应数据字段。
五、 表单自定义扩展组件
1. 日期选择器 (<DatePicker>)
- 核心能力:支持单日期选择,或双日期范围选择(主字段 + 影子字段模式)。
- 启用范围选择:在 AutoForm 的对应 Schema 项目中,配置
setting.rangeEnd: "endFieldName";或在组件上直接配置rangeEnd属性。 - 内部状态 (
state):start(String): 开始日期。end(String): 结束日期。
- 实例属性:
value(读写): 映射至state.start。isRange(只读): 根据是否配置了rangeEnd返回Boolean值。
- 操作方法:
updateStart(val): 更新state.start并分发change事件。updateEnd(val): 更新state.end,若处于 AutoForm 容器中,将该值同步写入到表单数据的rangeEnd对应字段中。
- 事件派发:
'change':当主字段/开始日期发生改变时触发。bubbles:truedetail: 改变后的开始日期字符串(state.start)。
2. 颜色选择器 (<ColorPicker>)
- 核心能力:提供颜色取色器(
type="color")与十六进制文本输入框的双向联动。 - 内部状态 (
state):value(String): 颜色值,默认为'#000000'。
- 实例属性:
value(读写): 映射至state.value。
- 方法:
updateValue(val): 更新颜色状态并分发事件。
- 事件派发:
'change':当值发生改变时触发。bubbles:truedetail: 改变后的十六进制颜色字符串。
3. 图标选择器 (<IconPicker>)
- 核心能力:基于 Bootstrap Icons 的可视化下拉搜索选择器。
- 内部状态 (
state):value(String): 当前选中的图标名。search(String): 图标搜索关键字。open(Boolean): 下拉菜单的展开状态。
- 实例属性:
value(读写): 映射至state.value。filteredIcons(只读): 经过search关键字过滤后的图标名称列表。
- 方法:
selectIcon(icon): 选中指定图标,收起下拉框并派发change事件。toggle(): 切换下拉框展开状态。若展开,会自动延时聚焦在搜索输入框中。
- 事件派发:
'change':当选中图标发生改变时触发。bubbles:truedetail: 选中的图标类名。
- 点击外部收起:监听全局
click事件,点击外部自动收起下拉框;组件被移除 DOM 时自动注销该监听。
4. 标签输入框 (<TagsInput>)
- 核心能力:可视化添加和删除标签。
- 添加交互:在输入框中输入内容后,按
Enter,,(逗号) 或(空格) 会自动将标签加入。 - 删除交互:点击标签聚焦后,按
Backspace或Delete键可将其移除,并自动聚焦到前一个标签。 - 内部状态 (
state):tags(Array): 存储标签字符串的数组。
- 实例属性:
value(读写): 映射至state.tags。
- 事件派发:
'change':当标签数组发生增删改变时触发。bubbles:truedetail: 最新标签的字符串数组。
六、 增强列表组件 (<List>)
1. 列表布局模式 (mode Attribute)
normal(默认): 扁平列表模式。group(分组):- 关联逻辑:通过
list中成员的groupfield匹配groups数组中项的groupidfield。
- 关联逻辑:通过
tree(树形):- 关联逻辑:扁平化数组,通过每一项的
parentfield匹配父项的idfield。根项的值为空字符串''。
- 关联逻辑:扁平化数组,通过每一项的
2. 字段映射配置属性 (可重写默认值)
在组件初始化时,会调用 Util.updateDefaults 将以下属性更新为默认值:
idfield: 项的主键字段名,默认'id'。labelfield: 项展示文本字段名,默认'label'。summaryfield: 项辅助文本字段名,默认'summary'。groupidfield: 分组的主键字段名,默认'id'。grouplabelfield: 分组展示文本字段名,默认'label'。groupsummaryfield: 分组辅助文本字段名,默认'summary'。groupfield: 项关联分组的字段名,默认'group'。parentfield: 树形下关联父节点的字段名,默认'parent'。groupicon: 组/父节点的图标类,默认'folder'(对应 Bootstrap Icons 的类名)。itemicon: 项/叶子节点的图标类,默认'file'。
3. 功能属性 (Attributes)
fast(Boolean): 启用虚拟滚动。- 重要约束:
<List>容器必须包含 Bootstrap 的overflow-auto类,且内置style="overflow-anchor:none"(模板自带)。
- 重要约束:
collapsible(Boolean): 仅在tree模式下有效,开启树形节点的展开/收起能力。auto-select(Boolean): 开启后,点击列表项时自动将该项的id记录至state.selectedItem,如果重复点击则会置空。auto-select-group(Boolean): 开启后,点击分组时自动将分组的id记录至state.selectedGroup。
4. 内部状态模型 (State)
list(读写): 原始列表数据数组。groups(读写): 仅在group模式下使用,分组定义数组。collapsed(读写): 仅在tree且collapsible时使用,存储节点 ID 折叠状态的 Map Proxy。selectedItem(读写): 当前选中的列表项 ID。selectedGroup(读写): 当前选中的分组 ID。_flatList(只读): 列表核心逻辑处理后的扁平化数组。_renderedList(只读): 实际在 DOM 中遍历渲染的数组片段(若开启虚拟滚动,则只包含可视区切片)。
5. 插槽 (Slots)
item:列表单项渲染模板插槽。在自定义模板中,可以访问当前行数据item和索引index。item-actions:行数据右侧按钮工具栏区域。group-actions:分组数据行右侧按钮工具栏区域。
6. 虚拟滚动运行参数
- 高度优先规则:
若列表数据的某一项上配置了数字属性
_itemHeight,虚拟滚动引擎会将其作为该项的测量高度,直接跳过 DOM 的高度测量。
7. 事件派发
itemclick:点击列表项(非分组)时触发。bubbles:falsedetail:{ item, index }(其中index为考虑虚拟滚动偏移量后的 绝对全局索引)。
groupclick:点击分组行时触发。bubbles:falsedetail:{ item, index }。
七、 导航组件 (<Nav>)
1. 结构与属性
vertical(Attribute, Boolean): 决定导航为垂直面板布局(带有右侧分割线)或水平导航栏布局(带底部阴影)。
2. 响应式数据模型 (State)
brand(Object, 可选):{ image, icon, label },控制左上角/顶部的 Logo、图标及品牌文本。list(Array, 必填): 导航栏项的数组。
3. 导航项结构(list 成员)
type: 决定导航项的渲染模式:'button': 导航按钮。'dropdown': 下拉菜单导航。含有list(子项数组),子项类型可为:'button': 子项按钮。'switch': 状态开关。需要配置bind(状态Proxy引用) 和name(要绑定的字段名)。- 水平布局下可以通过
width(Number) 控制下拉菜单宽度,默认250。
'fill': 弹性填充块(flex-fill),用于实现右对齐等布局。
name(String): 导航标识。当点击导航按钮时,该name会自动被写入Hash.nav以同步 URL 哈希。label(String): 文本展示。icon(String): 图标类名(基于 Bootstrap Icons)。noselect(Boolean, 可选): 若为true,点击该项仅派发点击事件,不会 修改Hash.nav。
4. 事件派发
nav:点击任何菜单项或下拉子菜单项时触发。bubbles:falsedetail:{ item }(被点击的导航项数据定义)。
八、 拖拽改变大小组件 (<Resizer>)
1. 组件属性
vertical(Attribute, Boolean): 为true时,鼠标为row-resize,调整高度;默认调整宽度。min(Attribute, Number): 像素下限,默认10。max(Attribute, Number): 像素上限,默认1000。target(Element): 要调整大小的目标 DOM 元素。默认是组件的前一个兄弟节点 (container.previousElementSibling)。
2. 事件与双向绑定
bind(输入拦截): 支持通过绑定表达式传入像素值(数字),自动设置为 target 的width/height。resizing:拖动调整大小的过程中持续触发。bubbles:falsedetail:{ oldSize, newSize }
resize:拖动结束时触发。bubbles:falsedetail:{ oldSize, newSize }
change:拖动结束时触发,输出最终的大小数值。常用于将新尺寸写回全局State。bubbles:falsedetail:newSize(Number)
九、 编程交互工具集 (UI)
1. 核心对话框方法 (UI.showDialog)
UI.showDialog({ title, message, buttons, type })- 参数:
title(String, 可选): 对话框标题。message(String, 必填): 提示消息,支持 HTML 标记($html渲染)。buttons(Array, 可选): 按钮文字数组,默认['{#Close#}']。type(String, 可选): 主题类型'primary' | 'danger' | 'warning' | 'success'等,控制边框、标题及最后一个主按钮的颜色。
- 返回值:
Promise<Number>。- 点击按钮返回其索引值 (从
1开始)。 - 点击关闭图标或按 ESC 取消返回
0。
- 点击按钮返回其索引值 (从
- 参数:
2. 快捷对话框
UI.alert(message, options):包装UI.showDialog。UI.confirm(message, options):确认框。- 默认按钮:
['{#Cancel#}', '{#Confirm#}']。 - 返回值:
Promise<Boolean>(选中确认按钮为true,取消为false)。
- 默认按钮:
3. 轻提示方法 (UI.toast)
UI.toast(message, options)- 参数:
message(String, 必填): 消息文本。options(Object, 可选):delay(Number): 自动关闭延迟时间(毫秒),默认5000。若传入0则永久不消失。type(String): 主题背景色'primary' | 'success' | 'danger' | 'warning'等。buttons(Array): 自定义 Toast 内嵌按钮,点击会设置result = index + 1并在点击后自动 dismiss。container(String): 目标 Toast 容器 ID,默认'default'。
- 参数:
4. 快捷 Toast 确认
UI.toastConfirm(message, options)- 弹出带有一个
Confirm按钮的 Toast。 - 返回值:
Promise<Boolean>(点击确认按钮返回true,其余情况返回false)。
- 弹出带有一个