bricks/aidocs/cols.md
2025-10-05 06:39:58 +08:00

323 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `bricks.Cols` 技术文档
> **模块**`bricks.Cols`
> **继承自**`bricks.VBox`
> **用途**:用于展示分页数据的列式布局组件,支持滚动加载、点击事件、动态渲染记录等特性。
---
## 概述
`bricks.Cols` 是一个基于 `VBox` 布局容器构建的数据展示控件,专为高效展示大量可分页数据而设计。它通过垂直滚动加载前后页内容(懒加载),并以列的形式排列每条记录,适用于移动端和桌面端的响应式布局。
该组件常用于新闻列表、商品展示、用户卡片墙等场景。
---
## 继承结构
```
bricks.Widget
└── bricks.Container
└── bricks.Box
└── bricks.VBox
└── bricks.Cols
```
---
## 配置选项Constructor Options
| 参数 | 类型 | 说明 |
|------|------|------|
| `data_url` | `String` | 获取数据的 API 地址,用于异步加载分页数据。 |
| `data_params` | `Object` | 初始请求参数对象,在每次请求时合并发送。 |
| `data_method` | `String` | 请求方法(如 `"GET"``"POST"`),默认由 `PageDataLoader` 决定。 |
| `page_rows` | `Number` | 每页显示的数据行数。 |
| `cache_limit` | `Number` | 缓存的最大页数,超出后自动清理旧页。 |
| `col_width` | `String/Number` | 单个列的宽度CSS 格式,如 `"200px"`)。 |
| `col_cwidth` | `String` | 列的弹性宽度CSS `flex` 值,如 `"1fr"`)。 |
| `mobile_cols` | `Number` | 移动端每行显示的列数,默认为 `2`。 |
| `record_view` | `Object` | 记录项的视图配置,定义如何使用 `widgetBuild` 渲染单条数据。 |
| `title` | `String` | 可选标题文本(支持国际化)。 |
| `description` | `String` | 可选描述文本(支持 Markdown。 |
| `toolbar` | `Object` | 工具栏配置对象,将被构造成 `bricks.Toolbar` 实例。 |
---
## 事件Events
| 事件名 | 触发条件 | 参数 |
|--------|----------|------|
| `record_click` | 用户点击某条记录时触发 | `(recordData)` — 当前记录的原始数据对象 |
| `command` | 工具栏发出命令时转发此事件(通过 `dispatch` | 命令名称及参数 |
> 使用 `.bind(event, handler)` 方法监听这些事件。
---
## 属性Properties
| 属性 | 类型 | 描述 |
|------|------|------|
| `loader` | `bricks.PageDataLoader` | 分页数据加载器实例,负责管理前后页数据获取与缓存。 |
| `container` | `bricks.VScrollPanel` | 外层垂直滚动容器,监听滚动阈值以触发分页加载。 |
| `main` | `bricks.DynamicColumn` | 实际存放记录项的动态列容器。 |
| `select_record` | `Widget` | 当前选中的记录对应的 widget 实例。 |
| `loading` | `Boolean` | 是否正在加载数据,防止重复请求。 |
| `title_w` | `bricks.Title4` | 标题组件实例(如果设置了 `title`)。 |
| `desc_w` | `bricks.MdWidget` | 描述组件实例(如果设置了 `description`)。 |
| `toolbar_w` | `bricks.Toolbar` | 工具栏组件实例(如果设置了 `toolbar`)。 |
---
## 方法Methods
### `constructor(opts)`
初始化 `Cols` 组件,并创建子组件结构。
#### 流程说明:
1. 调用父类构造函数。
2. 初始化 `PageDataLoader` 加载器。
3. 创建滚动容器 `VScrollPanel` 并绑定滚动边界事件。
4. 根据配置添加标题、描述、工具栏。
5. 创建主内容区域 `DynamicColumn`
6. 延迟 0.5 秒调用 `load_first_page()` 加载首屏数据。
---
### `command_handle(event)`
处理来自工具栏的命令事件,并将其转为 `dispatch` 派发出去。
```js
this.toolbar_w.bind('command', this.command_handle.bind(this));
```
---
### `async handle_click(rw, event)`
处理单个记录项的点击事件。
#### 功能:
- 阻止事件冒泡。
- 取消上一个选中项的高亮样式。
- 设置当前项为选中状态并添加 `selected_record` CSS 类。
- 打印日志并派发 `record_click` 事件,携带 `user_data`
> `rw.user_data` 存储的是该记录的原始数据对象。
---
### `async dataHandle(d)`
处理从 `loader` 返回的数据包,并渲染到界面。
#### 参数:
- `d`: 数据对象,格式如下:
```js
{
rows: [...], // 数据数组
add_page: Number, // 添加到哪一页
delete_page: Number, // (可选)需删除的页码(用于翻页替换)
pos_rate: Number // 滚动位置比例0~1
}
```
#### 行为逻辑:
- 若是向前翻页(非最大页),则反转数据顺序以便插入顶部。
- 使用 `widgetBuild(record_view, parent, data)` 动态生成每个记录 widget。
- 绑定点击事件。
- 设置 `data-page` 属性用于后续删除。
- 插入至 `main` 容器开头或末尾。
- 如有 `delete_page`,调用 `delete_page()` 清理旧页。
---
### `delete_page(page)`
删除指定页码的所有 DOM 元素及其 widget。
#### 实现方式:
- 查询所有 `[data-page="X"]` 的元素。
- 获取其关联的 `bricks_widget` 实例。
- 从 `main` 中移除对应 widget。
---
### `create_main_widget()`
重新创建主内容区域(`DynamicColumn`),通常在刷新或重置布局时调用。
```js
this.main = new bricks.DynamicColumn({
width: "100%",
col_cwidth: this.col_cwidth,
mobile_cols: this.mobile_cols || 2
});
```
---
### `async show_with_data(data)`
直接传入本地数据进行展示(绕过 `data_url` 请求)。
> ⚠️ 注意:目前代码中存在错误,应为 `await this.load_first_page(params);` 而不是 `await load_first_page(params);`
#### 正确实现建议:
```js
async show_with_data(data){
this.data = data;
this.data_url = null;
await this.load_first_page(); // 不需要参数
}
```
---
### `async load_first_page(params)`
加载第一页数据。
#### 流程:
1. 显示加载动画(`Running` 组件)。
2. 检查是否已在加载中,避免重复请求。
3. 合并 `data_params` 与传入的 `params`。
4. 调用 `loader.loadData()` 获取数据。
5. 成功后清空主容器并调用 `dataHandle(d)`。
6. 出错时打印调试信息。
7. 最终隐藏加载动画,释放锁。
---
### `async load_previous_page()`
向上滚动触底时加载前一页。
- 自动计算滚动位置并恢复。
- 支持 `pos_rate` 定位。
- 错误时仅输出 debug 日志。
---
### `async load_next_page()`
向下滚动触底时加载下一页。
- 类似于 `load_previous_page`,但加载下一页。
- 注释掉的 `scrollTop` 表示暂未启用精确滚动定位。
---
## 内部机制
### 分页加载策略
利用 `bricks.PageDataLoader` 实现智能分页:
- 支持双向分页(上一页 / 下一页)。
- 支持缓存控制(`cache_pages`)。
- 数据按“页”组织,可通过 `data-page` 属性追踪来源。
### 滚动加载触发
通过 `VScrollPanel` 的两个事件实现无限滚动:
| 事件 | 触发条件 |
|------|----------|
| `min_threshold` | 滚动到顶部附近 → 加载前一页 |
| `max_threshold` | 滚动到底部附近 → 加载下一页 |
绑定方式:
```js
this.container.bind('min_threshold', this.load_previous_page.bind(this));
this.container.bind('max_threshold', this.load_next_page.bind(this));
```
---
## 使用示例
### 基本用法
```js
var cols = new bricks.Cols({
title: "Latest Articles",
description: "A list of recent posts.",
data_url: "/api/articles",
data_params: { category: "tech" },
page_rows: 10,
cache_limit: 5,
col_cwidth: "1fr",
mobile_cols: 2,
record_view: {
type: "CardView",
fields: ["title", "summary", "image"]
}
});
cols.bind("record_click", function(data) {
console.log("Selected:", data);
});
document.body.appendChild(cols.dom_element);
```
### 手动加载本地数据
```js
cols.show_with_data({
rows: [
{id: 1, name: "Item 1"},
{id: 2, name: "Item 2"}
]
});
```
---
## 注意事项
1. **性能优化**:只保留可视区域附近的页面,其他页面可手动卸载。
2. **内存管理**:长时间运行应用应注意 `cache_limit` 设置,避免内存泄漏。
3. **事件绑定**:确保 `handle_click` 使用 `.bind(this, w)` 正确绑定上下文。
4. **CSS 样式**
- `.selected_record`:用于标记选中项,请在 CSS 中定义高亮样式。
- `.filler`:应用于 `container`,可能影响背景或间距。
---
## 注册信息
```js
bricks.Factory.register('Cols', bricks.Cols);
```
可在模板中通过 `<widget type="Cols" ...>` 方式声明使用。
---
## 版本信息
- **作者**Bricks Framework Team
- **最后更新**:根据代码推断为现代异步 JS 架构ES6+
- **兼容性**:需支持 Promise、async/await、Custom Elements
---
## 相关组件
| 组件 | 作用 |
|------|------|
| `bricks.PageDataLoader` | 提供分页数据加载能力 |
| `bricks.VScrollPanel` | 提供滚动检测与阈值事件 |
| `bricks.DynamicColumn` | 实现响应式多列布局 |
| `bricks.widgetBuild` | 动态构建子组件的核心函数 |
---
✅ **文档完成度**:完整覆盖功能、接口、流程与使用方式。
🔧 **待修复问题**`show_with_data` 方法中对 `load_first_page` 的调用缺少 `this.` 上下文。