@apigo.cc/base

@apigo.cc/base 是基于 @apigo.cc/state 和 Bootstrap 5.3 的同步组件层。页面只需要按顺序引入脚本,就能在首屏完成 DOM 处理和组件渲染。

目录

依赖加载

按顺序同步加载:

@apigo.cc/state -> @apigo.cc/bootstrap -> @apigo.cc/base

base 会直接使用来自 @apigo.cc/state 的全局对象 StateHashLocalStorage

推荐加载顺序

<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/state@1.0.23/dist/state.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/bootstrap@1.0.9/dist/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/base@1.0.23/dist/base.min.js"></script>

全局变量

变量 说明
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
  • dataFormData 时,不手动设置 Content-Type,让浏览器生成带 boundary 的 multipart 请求头
  • 如果你在 headers 里手动传了 Content-Type,普通对象请求会按你的设置发送;FormData 仍然以浏览器生成的请求头为准

返回值

{
  ok,
  status,
  headers,
  responseType,
  result,
  error
}

推荐示例

<script>
  window.userRequest = {
    url: '/api/users/1',
    method: 'GET'
  }
  window.apiResponse = null
  window.apiResult = null
  window.user = null
</script>

<API id="userApi"
  auto
  $.request="window.userRequest"
  $onresponse="window.user = event.detail.result"
  $onerror="UI.toast(event.detail.message, { type: 'danger' })">
</API>

<button class="btn btn-primary" onclick="userApi.do({ noui: true })">Reload</button>

API

<API> 是把请求封装成页面节点的方式。

属性和状态

名称 写法示例 说明
auto <API auto> 监听 request 变化后自动请求
request $.request="window.userRequest" 请求配置对象
response $.response="window.apiResponse" 最近一次请求状态
result $.result="window.apiResult" 响应结果缓存

request 默认结构

{
  url: '',
  method: 'GET',
  headers: {},
  data: null,
  timeout: 10000,
  responseType: ''
}

response 默认结构

{
  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

<AutoForm> 通过 schema 生成表单,适合和 APIwindow 上的页面数据直接联动。

属性

名称 写法示例 说明
vertical <AutoForm vertical> 垂直布局
horizontal <AutoForm horizontal> 强制左右两列布局
inline <AutoForm inline> 行内紧凑布局
nobutton <AutoForm nobutton> 隐藏底部提交按钮
api $.api="saveApi" 绑定 <API> 实例或其引用
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 不是字符串模板拼接,而是表达式
  • 表达式执行时可直接访问 thisStateHashLocalStorageitemdata
  • 这类条件是表单级动态渲染,适合做联动显隐

支持的 type

type 用途
text 单行文本
password 密码
email 邮箱
number 数字
date 日期
datetime 日期时间
file 文件
select 下拉单选
checkbox 多选
radio 单选按钮组
switch 开关
textarea 多行文本
DatePicker 扩展日期控件
ColorPicker 扩展颜色控件
IconPicker 扩展图标控件
TagsInput 扩展标签控件

options 写法

['Admin', 'Editor']
[{ label: 'Admin', value: 'admin' }]

事件

事件 触发时机 detail
submit 表单校验通过、提交前 当前表单数据
response 提交成功 完整响应对象
error 提交失败 Error 对象

插槽

插槽 位置 用途
actions 默认提交按钮左侧 自定义动作按钮

推荐示例

<script>
  window.profile = { name: 'Alice' }
  window.profileSchema = [
    { name: 'name', label: 'Name', type: 'text', setting: { required: true, placeholder: 'Enter name' } },
    { name: 'role', label: 'Role', type: 'select', options: [{ label: 'Admin', value: 'admin' }, { label: 'Editor', value: 'editor' }] },
    { name: 'active', label: 'Active', type: 'switch' },
    { name: 'birthday', label: 'Birthday', type: 'DatePicker', setting: { rangeEnd: 'birthdayEnd' } },
    { name: 'birthdayEnd', label: 'Birthday End', type: 'date' },
    { name: 'theme', label: 'Theme', type: 'ColorPicker' },
    { name: 'icon', label: 'Icon', type: 'IconPicker' },
    { name: 'tags', label: 'Tags', type: 'TagsInput' },
    { name: 'remark', label: 'Remark', type: 'textarea', if: 'this.data.active' }
  ]
</script>

<AutoForm vertical
  $.state.schema="window.profileSchema"
  $.state.data="window.profile"
  $onsubmit="UI.toast('submit: ' + JSON.stringify(event.detail))">
  <template slot="actions">
    <button type="button" class="btn btn-outline-secondary" onclick="Object.assign(window.profile, { name: 'Alice' })">Reset</button>
  </template>
</AutoForm>

编程注意

  • 不要直接整体覆盖 form.dataform.state.data
  • 需要更新时,优先用 Object.assign(form.data, nextData)

AutoForm.register(name, typeName = '')

注册可被 schema.type 识别的自定义控件。

参数 写法示例 说明
name AutoForm.register('MyPicker') 组件标签名
typeName AutoForm.register('MyPicker', 'picker') 默认 ''。只有当标签名和 schema.type 不同,或需要复用同一个标签名匹配另一个 type 时才传

什么时候传 typeName

  • 你想让 <MyPicker> 处理 schema.type === 'picker'
  • 你想把一个标签名映射成不同的 type
  • 如果 schema.type 和标签名一致,直接省略第二个参数

表单扩展控件

这些控件既可以在 AutoForm 里作为 schema.type 使用,也可以单独放到页面上。单独使用时,直接绑定 value,再监听 change 即可。

<DatePicker>

项目 说明
state.start 起始日期
state.end 结束日期
value 映射到 state.start
isRange 是否启用范围模式
setting.rangeEnd 范围结束字段名
rangeEnd 组件属性形式的范围结束字段名
change 开始日期变化时触发,detail 为开始日期字符串

<DatePicker> 示例

<script>
  window.rangeForm = {}
  window.rangeSchema = [
    { name: 'rangeStart', label: 'Range', type: 'DatePicker', setting: { rangeEnd: 'rangeEnd' } },
    { name: 'rangeEnd', label: 'Range End', type: 'date' }
  ]
</script>

<AutoForm $.state.schema="window.rangeSchema" $.state.data="window.rangeForm"></AutoForm>

<DatePicker> 单独使用

<script>
  window.birthDate = '2026-06-01'
</script>

<DatePicker $bind="window.birthDate"></DatePicker>

<ColorPicker>

项目 说明
state.value 颜色值,默认 #000000
value 可读写,映射到 state.value
change 颜色变化时触发,detail 为颜色字符串

<ColorPicker> 示例

<script>
  window.colorForm = {}
  window.colorSchema = [
    { name: 'theme', label: 'Theme', type: 'ColorPicker' }
  ]
</script>

<AutoForm $.state.schema="window.colorSchema" $.state.data="window.colorForm"></AutoForm>

<IconPicker>

项目 说明
state.value 当前图标名
state.search 搜索词
state.open 下拉是否展开
filteredIcons 过滤后的图标列表
value 可读写,映射到 state.value
change 选择图标时触发,detail 为图标名

<IconPicker> 示例

<script>
  window.iconForm = {}
  window.iconSchema = [
    { name: 'icon', label: 'Icon', type: 'IconPicker' }
  ]
</script>

<AutoForm $.state.schema="window.iconSchema" $.state.data="window.iconForm"></AutoForm>

<TagsInput>

项目 说明
state.tags 标签数组
change 标签变更时触发,detail 为最新数组

<TagsInput> 示例

<script>
  window.tagForm = {}
  window.tagsSchema = [
    { name: 'tags', label: 'Tags', type: 'TagsInput' }
  ]
</script>

<AutoForm $.state.schema="window.tagsSchema" $.state.data="window.tagForm"></AutoForm>

<TagsInput> 单独使用

<script>
  window.tags = ['Vue', 'AI']
</script>

<TagsInput $bind="window.tags"></TagsInput>

List

<List> 支持普通、分组、树形和虚拟滚动。它的重点不是“能渲染”,而是“能直接拿来绑定状态”。

属性

名称 写法示例 说明
mode <List mode="group"> normal / group / tree,默认 normal
fast <List fast> 开启虚拟滚动。任意模式都能用
collapsible <List collapsible> 树形模式下允许折叠
auto-select <List auto-select> 点击项后把当前项 id 写回 selectedItem
auto-select-group <List auto-select-group> 点击分组后把当前分组 id 写回 selectedGroup

状态

名称 说明
list 原始列表
groups 分组列表,group 模式使用
filter 字符串或对象筛选条件
order 排序规则,例如 name-namename desc
selectedItem 当前选中的项 id
selectedGroup 当前选中的分组 id
renderedList 当前实际渲染的列表片段
flatList 逻辑处理后的扁平列表
collapsed 树形折叠状态

实例属性

名称 写法示例 说明
filterFunc list.filterFunc = item => item.active 自定义过滤函数
orderFunc list.orderFunc = (a, b) => a.name.localeCompare(b.name) 自定义排序函数

事件

事件 触发时机 detail
change 选中项变化 selectedItem
itemclick 点击普通项 { item, index }
groupclick 点击分组项 { item, index }

绑定习惯

  • 推荐配合 $bind 保存当前选中 id比如 $bind="window.currentUserId"
  • 如果你只关心点击事件,也可以不绑,直接监听 itemclick / groupclick

插槽

插槽 说明
item 单项自定义内容
item-actions 单项右侧动作区
group-actions 分组右侧动作区

字段默认映射

不写映射属性时,默认字段名就是这些:

字段 默认值
idfield id
labelfield label
summaryfield summary
groupidfield id
grouplabelfield label
groupsummaryfield summary
groupfield group
parentfield parent
groupicon folder
itemicon file

推荐示例

普通列表 + $bind

<script>
  window.currentUserId = null
  window.userList = [
    { id: '1', label: 'Alice', summary: 'Admin' },
    { id: '2', label: 'Bob', summary: 'Editor' }
  ]
</script>

<List class="h-100 overflow-auto" auto-select
  $.state.list="window.userList"
  $bind="window.currentUserId"
  $onitemclick="UI.toast('item: ' + event.detail.item.label)">
  <template slot="item">
    <span $text="item.label"></span>
    <span class="ms-auto text-muted small" $text="item.summary"></span>
  </template>
</List>

分组列表

<script>
  window.groups = [
    { id: 'team-a', label: 'Team A', summary: '2 people' },
    { id: 'team-b', label: 'Team B', summary: '1 person' }
  ]

  window.members = [
    { id: '1', label: 'Alice', summary: 'Admin', group: 'team-a' },
    { id: '2', label: 'Bob', summary: 'Editor', group: 'team-b' }
  ]
</script>

<List mode="group" class="h-100 overflow-auto" auto-select-group
  $.state.list="window.members"
  $.state.groups="window.groups"
  $ongroupclick="UI.toast('group: ' + event.detail.item.label)">
  <template slot="item">
    <span $text="item.label"></span>
    <span class="ms-auto text-muted small" $text="item.summary"></span>
  </template>
</List>

树形列表

<script>
  window.treeList = [
    { id: '1', label: 'Root', parent: '' },
    { id: '2', label: 'Child A', parent: '1' },
    { id: '3', label: 'Child B', parent: '1' }
  ]
</script>

<List mode="tree" collapsible class="h-100 overflow-auto"
  $.state.list="window.treeList">
</List>

虚拟滚动

<script>
  window.bigList = Array.from({ length: 2000 }, (_, i) => ({
    id: String(i + 1),
    label: 'Row ' + (i + 1),
    summary: 'virtual row'
  }))
</script>

<List fast class="h-100 overflow-auto"
  $.state.list="window.bigList">
</List>

行为说明

  • filter 是字符串时,同时匹配 labelsummary
  • filter 是对象时,按字段模糊匹配
  • tree 模式会自动保留命中的祖先链
  • fast 模式要求外层容器有 overflow-auto
  • 数据项可加 _itemHeight 优化虚拟滚动测量

Nav

<Nav> 默认是水平导航。需要侧边栏时才加 vertical

属性

名称 写法示例 说明
vertical <Nav vertical> 垂直侧边栏

状态

名称 说明
brand { image, icon, label }
list 导航项数组
value 当前选中项
openName 当前展开的下拉项

导航项结构

字段 说明
type button / dropdown / label / fill
name 导航项标识
label 文本
icon Bootstrap Icons 名称
class 额外 class
noselect 选中时不写回 value
width dropdown 在水平模式下控制下拉宽度
list dropdown 的子项

子项结构

dropdown.list 内的子项支持:

  • type: 'button'
  • type: 'label'
  • type: 'switch'

switch 子项需要:

  • bind: 一个状态对象
  • name: 写回的字段名

事件

事件 触发时机 detail
change 选中项变化 当前 name
nav 点击或展开时 { item }{ item, open }

推荐示例

<script>
  window.currentNav = 'users'
  window.brand = { icon: 'cpu', label: 'Admin' }
  window.navSettings = { darkMode: false }
  window.navList = [
    { type: 'button', name: 'users', label: 'Users', icon: 'people' },
    { type: 'dropdown', name: 'settings', label: 'Settings', icon: 'gear', list: [
      { type: 'button', name: 'profile', label: 'Profile', icon: 'person' },
      { type: 'switch', name: 'darkMode', label: 'Dark Mode', icon: 'moon', bind: window.navSettings }
    ]}
  ]
</script>

<Nav class="border-bottom"
  $.state.brand="window.brand"
  $.state.list="window.navList"
  $bind="window.currentNav"
  $onnav="UI.toast(event.detail.item.label)">
</Nav>

备注

  • 水平模式是默认推荐形态
  • 需要左侧栏时再加 vertical
  • list 推荐在 JS 里单独定义,不要硬塞成一长串 HTML 字面量
  • 如果需要同步当前路由或菜单名,可以再加 $bind

Modal / Dialog

<Modal>

名称 写法示例 说明
show() editModal.show() 打开弹窗
hide() editModal.hide() 关闭弹窗
change @change 关闭时派发 false

<Modal> 的插槽

插槽 说明
header 弹窗头部
body 弹窗主体
footer 弹窗底部

<Modal> 示例

<Modal id="editModal">
  <div slot="header">Edit User</div>
  <div slot="body">
    <AutoForm nobutton inline $.state.schema="window.profileSchema" $.state.data="window.profile"></AutoForm>
  </div>
  <div slot="footer">
    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
  </div>
</Modal>

<button class="btn btn-primary" onclick="editModal.show()">Open</button>

<Dialog>

<Dialog> 是基于 Modal 的消息确认弹窗,平时直接用 UI.showDialog 更快。

UI.showDialog

参数 写法示例 说明
title title: 'Delete' 标题
message message: 'Are you sure?' 内容
buttons buttons: ['Cancel', 'Confirm'] 按钮文本数组
type type: 'danger' 样式类型

UI.showDialog 示例

const ok = await UI.confirm('Delete it?', { type: 'danger' })
if (ok) {
  UI.toast('deleted', { type: 'success' })
}

Resizer

<Resizer> 默认调整前一个元素的宽度。需要别的目标时再传 target

属性

名称 写法示例 说明
vertical <Resizer vertical> 调整高度,不是宽度
min min="180" 最小像素,默认 10
max max="420" 最大像素,默认 1000
target target="sidebar" 要调整的元素;不写时默认前一个兄弟节点

事件

事件 detail 说明
resizing { oldSize, newSize } 拖动中持续触发
resize { oldSize, newSize } 拖动结束触发
change newSize 拖动结束触发,适合写回状态

推荐示例

默认用法

<div id="sidebar" style="width: 280px"></div>
<Resizer min="180" max="420"></Resizer>

指定 target

<div id="sidebar" style="width: 280px"></div>
<Resizer target="sidebar" min="180" max="420"></Resizer>

UI

UI.toast(message, options)

参数 写法示例 说明
message UI.toast('Saved') 提示文案
type UI.toast('Saved', { type: 'success' }) 主题类型
delay UI.toast('Saved', { delay: 2000 }) 自动关闭延迟
buttons UI.toast('Confirm?', { buttons: ['Cancel', 'Confirm'] }) 底部按钮
container UI.toast('...', { container: 'right-top' }) 自定义容器

UI.toastConfirm(message, options)

返回 Promise<boolean>

UI.alert(message, options)

await UI.alert('Saved')

UI.confirm(message, options)

const ok = await UI.confirm('Delete it?')

UI.showDialog(options)

await UI.showDialog({
  title: 'Confirm',
  message: 'Do you want to continue?',
  buttons: ['Cancel', 'Confirm'],
  type: 'primary'
})

VirtualScroll / MouseMover

VirtualScroll(options = {})

参数:

参数 写法示例 说明
itemHeight VirtualScroll({ itemHeight: 40 }) 默认行高预估值

返回值:

方法 说明
reset(list, container) 重置缓存并返回初始可见列表
init(list, refreshCallback) 初始化高度缓存
update(index, node) 记录节点实际高度
calc(container, list) 计算当前需要渲染的片段

MouseMover.start(event, handlers)

MouseMover.start(event, {
  onmousemove: ({ w, h }) => {},
  onmouseup: ({ w, h }) => {}
})

说明

  • VirtualScroll 主要给 ListDataTable
  • MouseMover 主要给 Resizer
Description
No description provided
Readme 16 MiB
Languages
JavaScript 89.2%
HTML 10.8%