12 KiB
bricks.DataViewer 技术文档
版本:1.0
继承自:bricks.VBox
用途:通用数据展示组件,支持分页加载、滚动加载、工具栏操作与动态表单交互
概述
bricks.DataViewer 是一个可扩展的数据视图组件,用于在 Web 界面中以可视化方式展示和管理结构化数据。它基于 bricks.VBox 容器构建,具备以下核心功能:
- 支持异步分页加载远程数据(通过
PageDataLoader) - 垂直滚动区域自动加载上一页/下一页
- 可配置的工具栏(支持增删改查等操作)
- 行选择与事件通知机制
- 内置编辑表单弹窗(新增、更新、克隆、删除)
- 高度可定制化(可通过子类重写关键方法实现自定义渲染)
该组件通常作为列表、表格或卡片式数据展示的基础容器使用。
组件结构
var bricks = window.bricks || {};
bricks.DataViewer = class extends bricks.VBox { ... }
注册名称
bricks.Factory.register('DataViewer', bricks.DataViewer);
可通过工厂创建:
let viewer = bricks.Factory.build('DataViewer', opts);
构造函数
constructor(opts)
参数说明
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
opts.data_url |
String | 是 | 数据请求 URL |
opts.data_params |
Object | 否 | 请求附加参数 |
opts.page_rows |
Number | 否 | 每页行数,默认由 PageDataLoader 控制 |
opts.data_method |
String | 否 | HTTP 方法(如 'GET', 'POST'),默认 'GET' |
opts.cache_limit |
Number | 否 | 缓存页面数量限制 |
opts.editable |
Object | 否 | 编辑配置对象(见下文) |
opts.toolbar |
Object | 否 | 工具栏自定义项 |
opts.row_options |
Object | 否 | 行级选项(字段、排除字段等) |
初始化行为
- 设置默认布局样式:
- 宽高为
100% - 溢出隐藏(
overflow: hidden)
- 宽高为
- 创建
PageDataLoader实例用于数据加载 - 初始化状态变量(选中行、加载锁、偏移量等)
- 绑定事件:
row_check_changed - 延迟调用
build_all()进行 UI 构建
核心属性
| 属性 | 类型 | 描述 |
|---|---|---|
loader |
PageDataLoader |
负责数据分页加载 |
scrollpanel |
VScrollPanel |
主内容滚动容器 |
filler_widget |
Filler |
占位容器,容纳 scrollpanel |
toolbar_w |
IconTextBar |
工具栏组件 |
select_row |
Widget | 当前选中的记录行 widget |
active_item |
Widget | 当前激活项目(保留字段) |
loading |
Boolean | 是否正在加载数据 |
data_offset |
Number | 数据起始偏移位置(用于反向插入) |
old_params |
Object | 上次请求参数,防止重复加载 |
key_select_items |
Array | 支持键盘导航的选择项集合 |
check_changed_row |
Object | 最近一次变更的行数据 |
keyselectable |
Boolean | 是否允许键盘选择 |
生命周期方法
async build_all()
主 UI 构建入口,按顺序执行以下步骤:
await this.build_other();
this.scrollpanel.bind('min_threshold', this.load_previous_page.bind(this));
this.scrollpanel.bind('max_threshold', this.load_next_page.bind(this));
await this.render();
this.set_key_select_items();
子构建方法:
| 方法 | 功能 |
|---|---|
build_title_widget() |
(预留)构建标题区 |
build_description_widget() |
(预留)构建描述区 |
build_toolbar_widget() |
构建顶部工具栏 |
build_records_area() |
创建滚动面板用于显示数据行 |
build_other() |
子类可扩展的额外构建逻辑(空实现) |
async render(params)
重新加载并渲染数据。
参数
params: 请求参数(合并到原始data_params)
流程
- 若参数未变化 → 返回
- 使用
loader.loadData(params)获取数据 - 清空当前内容
- 执行前置处理
before_data_handle() - 处理数据
dataHandle(d)
⚠️ 自动去重:若
params === old_params则跳过。
async before_data_handle()
钩子函数,在数据处理前调用。可用于预处理或状态清理。
默认为空,供子类覆盖。
async dataHandle(d)
处理从 loader 返回的数据对象。
输入格式示例
{
"rows": [...],
"add_page": 1,
"delete_page": 2
}
行为
- 调用
renderPageData(rows, add_page) - 如果有
delete_page,调用delete_page(page_num)删除旧页
数据渲染相关
build_records_area()
创建主数据显示区域:
this.filler_widget = new bricks.Filler({});
this.add_widget(this.filler_widget);
this.scrollpanel = new bricks.VScrollPanel({});
this.filler_widget.add_widget(this.scrollpanel);
使用
Filler + VScrollPanel结构确保布局适应。
async renderPageData(data, page)
将一批数据渲染成可视行。
参数
data: 数组,每项是一个数据记录page: 页面编号
特殊逻辑
- 如果不是最大页(历史页):数据逆序,并从前部插入(维护时间顺序)
- 否则:正常追加至末尾
内部循环调用 build_row()。
async build_record_view(record)
抽象方法:生成单条记录的 UI 组件。
默认实现
var w = new bricks.VBox({width: '100px', height:'100px'});
w.set_css('test_box');
return w;
✅ 必须由子类重写以实现具体展示样式(如表格行、卡片等)
async build_row(record, page, pos)
将一条记录添加到 scrollpanel 中。
参数
record: 数据对象page: 所属页码pos: 插入位置(null 表示末尾)
步骤
- 调用
build_record_view(record)创建 widget - 设置属性
data-page便于后续删除 - 添加到
scrollpanel指定位置
工具栏与用户交互
build_toolbar_widget()
根据配置生成工具栏按钮。
支持的操作(当 editable 存在时)
| 名称 | 图标 | 条件 | 提示 |
|---|---|---|---|
add |
add_icon 或默认图标 |
总是显示 | 新增记录 |
update |
update_icon |
需选中行 | 更新选中项 |
clone |
clone_icon |
需选中行 | 克隆选中项 |
delete |
delete_icon |
需选中行 | 删除选中项 |
图标路径通过
bricks_resource()解析 SVG 资源。
此外,支持合并外部传入的 toolbar.tools。
最终创建 IconTextBar 并绑定命令事件。
command_event_handle(event)
处理工具栏点击事件。
分发逻辑
| 命令名 | 行为 |
|---|---|
add |
调用 add_record() |
update |
调用 update_record(select_row) |
clone |
调用 clone_record(select_row) |
delete |
调用 delete_record(select_row) |
| 其他 | 触发全局事件 dispatch(name, data) |
若操作需要选中行但无选中项,则提示错误。
编辑功能
字段控制
get_edit_fields()
提取可编辑字段,过滤掉 editexclouded 中指定的字段。
结果保存在
this.fields数组中。
get_hidefields()
获取应隐藏提交的字段(来自 data_params),转换为 {name, value, uitype: 'hide'} 形式。
表单构建
| 方法 | 功能 |
|---|---|
build_add_form() |
构建“新增”表单 |
build_update_form(data) |
构建“更新”表单(带 id 隐藏域) |
build_clone_form(data) |
构建“克隆”表单(不包含 id) |
所有表单均基于 bricks.Form,并注入隐藏字段和编辑字段。
弹窗管理
build_window(icon, title, form)
创建通用弹窗(PopupWindow)封装表单。
配置
- 居中定位 (
archor: "cc") - 可移动、可缩放
- 尺寸:宽 90%,高 70%
- 绑定表单的
cancel事件关闭窗口
编辑流程
add_record()
- 创建新增表单
- 弹出窗口
- 监听
submited事件 → 调用add_record_finish(win, event)
add_record_finish(f, event)
- 关闭窗口
- 重新加载数据
- 解析响应 JSON 并构建反馈组件(如消息提示)
update_record()
- 获取当前选中行数据
- 创建更新表单(含
id隐藏域) - 弹窗并监听
submited→update_record_finish()
update_record_finish(win, form, event)
- 调用
renew_record_view(form, row)更新本地视图 - 显示服务器返回结果组件
- 关闭窗口
clone_record()
同 add_record,但初始值为原记录数据
delete_record(row, record)
弹出确认对话框(Conform),确认后调用 delete_record_act()
delete_record_act()
- 发送 DELETE 请求(POST with body)
- 接收响应并构建反馈组件
- 若成功(返回 Message 类型),移除对应行并刷新
滚动加载机制
load_previous_page()
加载前一页数据(向上滚动触底)
流程
- 检查是否已在加载 → 防抖
- 显示 loading 指示器(
Running) - 调用
loader.loadPreviousPage() - 成功则调用
dataHandle(d) - 恢复滚动位置(按
pos_rate) - 隐藏 loading
错误被捕获并打印 debug 日志。
load_next_page()
加载下一页数据(向下滚动触底)
逻辑类似 load_previous_page(),但无需调整滚动位置。
辅助方法
set_key_select_items()
设置支持键盘导航的元素集合(除去第一个 filler widget)。
用于后续方向键选择。
delete_page(page)
批量删除属于某一页的所有 DOM 元素。
通过 [data-page="X"] 查询 selector 获取 widgets 并逐个移除。
record_check_changed(event)
处理行内复选框变更事件。
转发事件为 row_check_changed,携带 user_data。
renew_record_view(form, row)
用表单最新值更新某行的 user_data。
row.user_data = { ...row.user_data, ...form._getValue() };
row.renew(data); // 视图刷新
renew()是 widget 的生命周期方法,需子类实现。
事件系统
| 事件名 | 触发时机 | 参数 |
|---|---|---|
row_check_changed |
行内复选框改变 | {user_data} |
command |
工具栏按钮点击 | {name, selected_row} |
submited |
表单提交成功 | {params: Response} |
conformed / discard |
删除确认框选择 | —— |
设计原则与扩展建议
可扩展点(推荐子类覆盖)
| 方法 | 用途 |
|---|---|
build_other() |
添加自定义组件 |
build_title_widget() |
自定义标题 |
build_record_view(record) |
自定义行渲染模板 |
before_data_handle() |
数据加载前准备 |
renew(record) in row widget |
行内容更新逻辑 |
性能优化特性
- 数据缓存与懒加载
- 滚动阈值触发分页
- 请求去重(参数比对)
- 页面级删除释放内存
使用示例(伪代码)
let viewer = new bricks.DataViewer({
data_url: '/api/users',
data_params: { dept_id: 101 },
page_rows: 20,
editable: {
add_icon: 'imgs/user_add.svg',
new_data_url: '/api/users/create',
update_data_url: '/api/users/update',
delete_data_url: '/api/users/delete'
},
row_options: {
fields: [
{ name: 'name', label: '姓名', uitype: 'text' },
{ name: 'age', label: '年龄', uitype: 'number' }
],
editexclouded: ['created_at']
}
});
// 自定义行渲染
viewer.build_record_view = function(record) {
let w = new bricks.HBox({ width: '100%', padding: 10 });
w.add_widget(new bricks.Label({ text: record.name }));
w.add_widget(new bricks.Label({ text: record.age }));
w.user_data = record;
return w;
};
调试信息
bricks.debug_obj = this.scrollpanel;—— 方便调试滚动容器- 所有关键操作均有
bricks.debug()输出 - 支持
bricks.show_error()提示用户错误
依赖组件
| 组件 | 作用 |
|---|---|
bricks.VBox |
布局基类 |
bricks.VScrollPanel |
滚动容器 |
bricks.PageDataLoader |
分页数据加载器 |
bricks.IconTextBar |
工具栏 |
bricks.Form |
表单引擎 |
bricks.PopupWindow |
弹窗容器 |
bricks.Conform |
确认对话框 |
bricks.Running |
加载指示器 |
bricks.HttpJson |
JSON 请求客户端 |
bricks.widgetBuild |
动态组件构建 |
版本历史
| 版本 | 修改内容 |
|---|---|
| 1.0 | 初始公开文档版本 |
📝 文档生成时间:2025-04-05
© 2025 Bricks Framework Team