base/README.md

12 KiB
Raw Blame History

@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 解析前就绪:

<!-- 1. 基础状态机 (地基) -->
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/state@1.0.19/dist/state.min.js"></script>
<!-- 2. Bootstrap 适配层 -->
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/bootstrap@1.0.6/dist/bootstrap.min.js"></script>
<!-- 3. 本业务组件库 (原生注入) -->
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/base@1.0.17/dist/base.min.js"></script>

<script>
  // 4. 数据先行 (在 body 解析前定义)
  window.brand = { label: 'My App' };
</script>

2. 组件超能力示例 (Mega Examples)

2.1 声明式数据组件 (<API>)

<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: falseerrorbubbles: true

2.2 万能表单与内嵌控件 (<AutoForm>)

<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.dataform.data 执行覆盖式重新赋值,必须使用 Object.assign

2.3 增强列表组件 (<List>)

列表有三类布局模式,分别有不同的数据结构关联,均推荐在 HTML 中声明绑定:

模式一:普通扁平列表 (mode="normal")

  • 关联逻辑:直接渲染一维数组项。
  • 数据结构
    const userList = [
        { id: '1', label: '小明', summary: '前端开发' },
        { id: '2', label: '小红', summary: '产品经理' }
    ];
    
  • HTML 写法
    <List mode="normal" $list="userList" $onitemclick="console.log(event.detail.item)"></List>
    

模式二:分组列表 (mode="group")

  • 关联逻辑list 的项通过 group 字段去匹配 groups 数组中的 id 字段。
  • 数据结构
    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 写法
    <List mode="group" $list="groupUserList" $.state.groups="deptGroups"></List>
    

模式三:树形可折叠列表 (mode="tree") —— 超级示例

  • 关联逻辑:通过每项的 parent 关联父项的 id 属性,根项的 parent 设为空字符串 ''
  • 数据结构(内置 _itemHeight 优化虚拟滚动高度测量):
    const deptTreeList = [
        { id: '1', label: '总经办', parent: '', _itemHeight: 40 },
        { id: '2', label: '研发部', parent: '1', _itemHeight: 40 },
        { id: '3', label: '开发组', parent: '2', _itemHeight: 40 }
    ];
    
  • 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>)

<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>)

<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 核心要点
    • resizingresize 事件的 detail 结构均为 { oldSize: Number, newSize: Number }change 事件的 detailnewSize 像素数字。

3. 网络与交互工具集 (HTTP & UI)

3.1 HTTP 请求工具 (HTTP)

// 支持 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)
    • 返回值voidoptions.delay 为自动消失延迟毫秒(0 代表不消失)。可以通过传入 buttons: ['选项1'] 按钮提供交互,点击后在实例 result 上保存索引。
  • UI.toastConfirm(message, options)
    • 返回值Promise<Boolean>。在 Toast 中提供单确认按钮,点击确认返回 true,否则返回 false

4. 开发红线 (Constraints)

  1. 表单数据操作红线:严禁直接覆盖表单的 state.datadata 对象(如 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 时,框架将强行拦截并警告任何刷新/关闭页面的行为。