mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-29 08:58:22 +08:00
fix(table): 卡片勾选收敛至勾位图标并消除勾选重渲闪烁(pro#4)
- 委托收敛勾位判定+快速路径 class 回显 - 勾位光标样式 - usercard/goodscard 勾位适配 - 两个技能文档契约同步
This commit is contained in:
@@ -775,11 +775,11 @@ layoutDefault: true, // 旧协议"自动判断",视
|
||||
|
||||
- 双端自动注入后 PC 端同样有视图切换按钮与卡片形态,端差异只体现在缺省形态上:PC 缺省 `table`,手机缺省 `card`(记忆与按端 layoutDefault 的优先级更高,见 11.2 解析链)
|
||||
- 手机端判定 `ua.checkMobile()`(`admin-utils.js` 转发,实现位于 `public/static/common/js/app.js`):UA 关键字(Android/iPhone/iPad 等)或 `window.screen` 宽 < 600 且高 < 800。判的是物理屏幕指标,**浏览器开发者工具仅改视口宽度不会触发**;设备仿真验证手机默认形态时,必须同时覆写 UA 或仿真 screen 尺寸,仅设 viewport 无效
|
||||
- 卡片形态能力边界:工具栏(刷新/新增/批量删除/导出)与搜索区两形态共用、照常可用;行选中、豁免与 `_disabled` 等模板侧语义由卡片模板契约定义(见 11.4)
|
||||
- 卡片形态能力边界:工具栏(刷新/新增/批量删除/导出)与搜索区两形态共用、照常可用;行选中、豁免与 `_disabled` 等模板侧语义由卡片模板契约定义(见 11.4);`_cells` 隐藏列(col.hide)不产出对应键,模板按原始字段直取即可
|
||||
|
||||
### 11.4 自定义模板指引
|
||||
|
||||
自定义卡片/模板形态的创作不在本技能展开,统一由 [ulthon-card-template](./ulthon-card-template/SKILL.md) 技能承接:渲染上下文契约(`_cells`/`_operatHtml`/`_checked`/`_disabled`、上下文冻结、列表上下文命名)、模板节点位置硬约束、行选中委托与豁免名单、取值通道三规则、usercardTpl/goodscardTpl 范例走读、实战配方、设计模式库、模板作者坑与验收 checklist。本技能只负责机制如何把模板跑起来;两个官方范例的 render 配置块(layoutList 三形态、layoutDefault 对象式与字符串式)见第十章引用表末行,可作机制示范直接对照。
|
||||
自定义卡片/模板形态的创作不在本技能展开,统一由 [ulthon-card-template](./ulthon-card-template/SKILL.md) 技能承接:渲染上下文契约(`_cells`/`_operatHtml`/`_checked`/`_disabled`、上下文冻结、列表上下文命名)、模板节点位置硬约束、行选中委托与豁免名单(勾位契约:点行内 `.ua-data-card-check` 勾位元素切换勾选,勾位元素须在行内,行根元素仍需携带 `data-table-id` + `data-id` 两属性)、取值通道三规则、usercardTpl/goodscardTpl 范例走读、实战配方、设计模式库、模板作者坑与验收 checklist。本技能只负责机制如何把模板跑起来;两个官方范例的 render 配置块(layoutList 三形态、layoutDefault 对象式与字符串式)见第十章引用表末行,可作机制示范直接对照。
|
||||
|
||||
## 相关技能
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "ulthon-card-template"
|
||||
description: "自定义卡片/模板形态创作指南:面向想让列表页变好看、为自己的列表页定制专属卡片形态的下游开发者。涵盖适用判断(内置 card 兜底 vs 定制时机、锁定纯表格)、五级模板协议选型建议(官方范例为何都选 tplVueId)、渲染上下文契约(_cells/_operatHtml/_checked/_disabled 与上下文冻结、模板节点容器外硬约束、行选中委托与豁免名单)、以商品卡为蓝本的 step-by-step 配方、设计模式库(头部三件套/图面悬浮开关/价格层级/状态徽标/底部分隔/图片降级/响应式/统一设计语言)、取值通道三规则、坑与红线、验收 checklist。需要定制卡片/自定义卡片模板/卡片模板/商品卡/名片/自定义形态/layoutList 自定义条目/tplVueId,或想让列表变好看、排查自定义模板不渲染/点卡片误勾选/模板内开关失效时调用。多形态机制(受控数据流、五级协议引擎、双端注入、layoutDefault 三层链)见 ulthon-admin-table 技能第十一章,本技能定位是动手创作,不复述机制。"
|
||||
description: "自定义卡片/模板形态创作指南:面向想让列表页变好看、为自己的列表页定制专属卡片形态的下游开发者。涵盖适用判断(内置 card 兜底 vs 定制时机、锁定纯表格)、五级模板协议选型建议(官方范例为何都选 tplVueId)、渲染上下文契约(_cells/_operatHtml/_checked/_disabled 与上下文冻结、模板节点容器外硬约束、行选中委托与豁免名单)、以商品卡为蓝本的 step-by-step 配方、设计模式库(头部三件套/图面悬浮开关/价格层级/状态徽标/底部分隔/图片降级/响应式/统一设计语言)、取值通道三规则、坑与红线、验收 checklist。需要定制卡片/自定义卡片模板/卡片模板/商品卡/名片/自定义形态/layoutList 自定义条目/tplVueId,或想让列表变好看、排查自定义模板不渲染/点勾位图标不切换勾选/模板内开关失效时调用。多形态机制(受控数据流、五级协议引擎、双端注入、layoutDefault 三层链)见 ulthon-admin-table 技能第十一章,本技能定位是动手创作,不复述机制。"
|
||||
---
|
||||
|
||||
# 自定义卡片模板创作指南(ulthon-card-template)
|
||||
@@ -50,7 +50,7 @@ Vue 形态的 `v-for="d in rows"` 里的 `d`:
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `...row` | 行原始字段全部可用(username、title、price、create_time 等) |
|
||||
| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段** |
|
||||
| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段**;隐藏列(col.hide)不产出对应键 |
|
||||
| `_operatHtml` | 操作列渲染产物(编辑/删除等按钮 HTML,已按 `data-auth-*` 裁剪权限) |
|
||||
| `_checked` | 该行是否选中(store 选中集合) |
|
||||
| `_disabled` | 该行是否禁选 |
|
||||
@@ -77,7 +77,7 @@ Vue 形态的 `v-for="d in rows"` 里的 `d`:
|
||||
|
||||
### 3.5 行选中委托与豁免名单
|
||||
|
||||
行根元素携带 `data-table-id` + `data-id` 两属性即获得统一行选中委托,点卡片任意空白处切换勾选,零 JS。选中态经 `:class` 高亮回显,禁选行整元素不可勾选:
|
||||
点行内 `.ua-data-card-check` 勾位元素切换勾选,零 JS;行根元素仍需携带 `data-table-id` + `data-id` 两属性(委托按行根属性定位行),且勾位元素必须写在行内(委托按该类判定点击意图,行内没有勾位元素则该行无法勾选)。选中态经 `:class` 高亮回显,禁选行整元素不可勾选:
|
||||
|
||||
```html
|
||||
<!-- 出处:extend/base/admin/view/mall/goods/index.html(卡片根元素,usercardTpl 同构) -->
|
||||
@@ -136,7 +136,7 @@ layoutList: ['table', {name: 'mycard', title: '自定义卡', tplLayId: '#myCard
|
||||
<img v-if="d.logo" :src="d.logo" :alt="d.title" class="goodscard-img"
|
||||
@error="$event.target.style.display = 'none'">
|
||||
<div class="goodscard-status" v-html="d._cells.status"></div>
|
||||
<i v-if="d._checked" class="layui-icon layui-icon-ok-circle goodscard-check"></i>
|
||||
<i class="layui-icon layui-icon-ok-circle goodscard-check ua-data-card-check"></i>
|
||||
</div>
|
||||
<!-- 主体与底部区块完整结构见源文件 goodscard-body 与 goodscard-footer -->
|
||||
</div>
|
||||
@@ -279,7 +279,7 @@ layoutDefault: 'goodscard',
|
||||
|
||||
- 操作按钮配置对象自 commit 53ee2e3 起有拷贝保护(渲染函数对配置只读):自定义按钮的 class/method 不会被渲染过程污染,形态反复切换后按钮样式与 URL 拼接保持稳定。这是已修复的历史坑:修复前的版本存在"切换形态后按钮 class 丢失、URL 滚雪球"的缺陷,老版本升级后若仍见此症状先确认包含 53ee2e3。
|
||||
- 形态切换零请求,但 switch 开关切换不是:点击开关会触发 modify 提交加一次列表重查(各 1 个 XHR),这是框架标准链路,验收时勿与"切换零请求"混淆。
|
||||
- 卡片字段清单是 render 注册时的 cols 快照,搜索列面板运行时隐藏的列不会从卡片消失(两套状态解耦),属已知边界,已立议题跟踪,模板侧无需规避。
|
||||
- 卡片字段清单实时跟随列显隐:列筛选面板隐藏/恢复列后,卡片形态自动重渲(colToggled 监听 + store 当页数据零请求重渲),隐藏列不产出 `_cells` 对应键,模板侧无需规避。
|
||||
|
||||
## 八、验收 checklist
|
||||
|
||||
@@ -288,9 +288,9 @@ layoutDefault: 'goodscard',
|
||||
- [ ] **三形态循环零网络请求**:表格、自定义模板、内置 card 来回切,XHR 计数不变
|
||||
- [ ] **F5 记忆保持**:通过视图下拉切到自定义形态后刷新,形态保持(说明下拉写入的记忆被正确读取)
|
||||
- [ ] **手机单列不崩**:390 宽视口下网格单列、无横向滚动(端判定与仿真要点见 ulthon-admin-table 第十一章 11.3)
|
||||
- [ ] **开关可切且不触发勾选**:点卡片内 switch,POST modify 200,该卡片不出现选中态(无 `ua-data-card-checked` 类、无勾位图标),豁免名单生效
|
||||
- [ ] **开关可切且不触发勾选**:点卡片内 switch,POST modify 200,该卡片不出现选中态(无 `ua-data-card-checked` 类、勾位图标保持灰色未选中态),豁免名单生效
|
||||
- [ ] **console 零新增错误**:数据固有 404(如测试图片)可豁免,模板相关零报错;模板渲染失败时框架会自动回退表格(机制见 ulthon-admin-table 第十一章 11.2),回退本身也是排查信号
|
||||
- [ ] **交互豁免有效**:点操作按钮(编辑/删除等)打开预期行为且不勾选卡片;点卡片空白处正常切换勾选
|
||||
- [ ] **交互豁免有效**:点操作按钮(编辑/删除等)打开预期行为且不勾选卡片;点勾位图标正常切换勾选,点卡片正文空白处不触发勾选
|
||||
- [ ] **(如有图片字段)404 降级**:无图与加载失败都显示占位,卡片高度不塌
|
||||
|
||||
验证工具建议:命令行接口冒烟用 [ulthon-tools-http-call](../ulthon-tools-http-call/SKILL.md);页面断言(形态、XHR、豁免)用浏览器实测,具体断言选择器与仿真要点见 [ulthon-page-qa](../ulthon-page-qa/SKILL.md)。
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
上下文契约(admin-table.js buildLayoutContext):
|
||||
- rows:行上下文数组,d 与表格行数据同构(含原始字段 + _cells/_operatHtml/_checked/_disabled)
|
||||
- list:列表上下文 {tableId, page, count, checkedAll}(Vue 形态不叫 _list)
|
||||
- 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击卡片
|
||||
切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显
|
||||
- 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击勾位
|
||||
图标切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显
|
||||
- _cells/_operatHtml 含渲染产物 HTML,必须用 v-html 输出;纯文本字段用
|
||||
{{ }} 原生插值(自动转义);处理函数内不得修改渲染上下文数据(冻结契约)
|
||||
- 事件无需自行绑定:操作按钮与 switch 经页面级委托和 form 事件天然生效
|
||||
@@ -40,13 +40,13 @@
|
||||
:class="{'ua-data-card-checked': d._checked, 'ua-data-card-disabled': d._disabled}">
|
||||
<!-- 图区:4:3 商品大图(撑满裁切不变形、圆角随卡片),无图或 404 时
|
||||
降级为占位图标;右上角悬浮状态开关(半透明白底小容器),
|
||||
左上角勾位图标按行选中态显示 -->
|
||||
左上角勾位图标常显(.ua-data-card-check:未选中灰可点、选中变绿) -->
|
||||
<div class="goodscard-cover">
|
||||
<span class="goodscard-img-empty" title="未设置图片"><i class="layui-icon layui-icon-picture"></i></span>
|
||||
<img v-if="d.logo" :src="d.logo" :alt="d.title" class="goodscard-img"
|
||||
@error="$event.target.style.display = 'none'">
|
||||
<div class="goodscard-status" v-html="d._cells.status"></div>
|
||||
<i v-if="d._checked" class="layui-icon layui-icon-ok-circle goodscard-check"></i>
|
||||
<i class="layui-icon layui-icon-ok-circle goodscard-check ua-data-card-check"></i>
|
||||
</div>
|
||||
<!-- 主体:名称(600 字重、最多两行截断)+ 分类徽标与销量同排 + 价格
|
||||
层级(折扣价红大字、市场价灰删除线)+ 库存徽标(stock<20 红
|
||||
@@ -144,7 +144,7 @@
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
color: #1e9fff;
|
||||
margin-left: 0;
|
||||
font-size: 22px;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
上下文契约(admin-table.js buildLayoutContext):
|
||||
- rows:行上下文数组,d 与表格行数据同构(含原始字段 + _cells/_operatHtml/_checked/_disabled)
|
||||
- list:列表上下文 {tableId, page, count, checkedAll}(Vue 形态不叫 _list)
|
||||
- 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击卡片
|
||||
切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显
|
||||
- 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击勾位
|
||||
图标切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显
|
||||
- _cells/_operatHtml 含渲染产物 HTML,必须用 v-html 输出;纯文本字段用
|
||||
{{ }} 原生插值(自动转义,与 laytpl 的 {{- }} 不同)
|
||||
- 事件无需自行绑定:操作按钮与 switch 经页面级委托和 form 事件天然生效
|
||||
@@ -45,6 +45,7 @@
|
||||
<span class="usercard-account" :title="d.username">{{ d.username }}</span>
|
||||
</div>
|
||||
<div class="usercard-status" v-html="d._cells.status"></div>
|
||||
<div class="ua-data-card-check"><i class="layui-icon layui-icon-ok-circle"></i></div>
|
||||
</div>
|
||||
<!-- 主体:紧凑小字段两列排布(手机无值显示 —,登录次数为 pill 徽标),
|
||||
备注有值才渲染、单行省略;均为纯文本原始字段插值 -->
|
||||
|
||||
@@ -753,7 +753,7 @@ table样式
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.ua-data-card:hover {
|
||||
@@ -797,6 +797,10 @@ table样式
|
||||
color: #d2d2d2;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ua-data-card-check:hover {
|
||||
color: rgb(22, 183, 119);
|
||||
}
|
||||
|
||||
.ua-data-card-checked .ua-data-card-check {
|
||||
|
||||
@@ -768,7 +768,7 @@ table样式
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
transition: border-color .2s, box-shadow .2s;
|
||||
|
||||
&:hover {
|
||||
@@ -815,6 +815,11 @@ table样式
|
||||
color: #d2d2d2;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: rgb(22, 183, 119);
|
||||
}
|
||||
}
|
||||
|
||||
.ua-data-card-checked .ua-data-card-check {
|
||||
|
||||
@@ -155,12 +155,14 @@
|
||||
|
||||
// 统一行选中委托(任务 18):模板渲染容器内凡带 data-table-id + data-id 属性
|
||||
// 的行元素——内置 card 的 .ua-data-card 与自定义 laytpl/Vue 模板的卡片/勾位
|
||||
// 元素——点击即切换选中,全部走本委托,无任何形态专用事件。模板作者契约:
|
||||
// 给行根元素(或勾位元素)加这两属性即获得点选交互,无需页面级监听。
|
||||
// 元素——仅当点击落在行内 .ua-data-card-check 勾位元素内才切换选中,全部走
|
||||
// 本委托,无任何形态专用事件。模板作者契约:给行根元素(或勾位元素)加这两
|
||||
// 属性、勾位区域挂 .ua-data-card-check 类即获得点选交互,无需页面级监听。
|
||||
// 交互元素(按钮/表单控件/layui 美化层)豁免不触发勾选;禁用行
|
||||
// (ua-data-card-disabled 标记或行 LAY_DISABLED)整元素不可勾选。选择态落
|
||||
// store(与引擎勾选同一事实源,批量删除经 ua.table.checkStatus 分发即取到),
|
||||
// 随后重渲模板管线回显勾位标记。
|
||||
// 随后走快速路径按模式只改勾位卡片 class 回显(radio 替换 / checkbox 切换),
|
||||
// 目标卡元素找不到时兜底整容器重渲模板管线回显勾位标记。
|
||||
$(document).on('click', '[data-table-id][data-id]', function (e) {
|
||||
var $card = $(this);
|
||||
var tableId = $card.attr('data-table-id');
|
||||
@@ -171,6 +173,10 @@
|
||||
if ($card.hasClass('ua-data-card-disabled')) {
|
||||
return;
|
||||
}
|
||||
// 仅勾位点击生效:点卡片正文不触发勾选(点正文零开销)
|
||||
if ($(e.target).closest('.ua-data-card-check').length === 0) {
|
||||
return;
|
||||
}
|
||||
if ($(e.target).closest('a,button,input,select,textarea,label,.layui-form-switch,.layui-form-checkbox,.layui-form-radio').length) {
|
||||
return;
|
||||
}
|
||||
@@ -189,8 +195,27 @@
|
||||
if (!row || row.LAY_DISABLED) {
|
||||
return;
|
||||
}
|
||||
// 快速路径(pro#4):不做整容器重渲,仅按模式调整勾位卡片 class——
|
||||
// radio 替换(清旧卡、点新卡,重复点同一卡净效果保持选中)、checkbox
|
||||
// 切换(含再点取消);DOM 不重建,含图卡片不闪。自定义模板未按契约
|
||||
// 输出勾位元素时兜底整容器重渲,不丢功能。
|
||||
var prevRadioId = (state.selectMode === 'radio' && state.selectedIds && state.selectedIds.length)
|
||||
? state.selectedIds[0]
|
||||
: null;
|
||||
window.UA_TABLE_STORE.selection.set(tableId, row);
|
||||
var $target = $('#ua-layout-' + tableId).find('[data-id="' + rowId + '"]');
|
||||
if ($target.length === 0) {
|
||||
ua.table.renderLayoutForm(tableId);
|
||||
return;
|
||||
}
|
||||
if (state.selectMode === 'radio') {
|
||||
if (prevRadioId !== null && String(prevRadioId) !== String(rowId)) {
|
||||
$('#ua-layout-' + tableId).find('[data-id="' + prevRadioId + '"]').removeClass('ua-data-card-checked');
|
||||
}
|
||||
$target.addClass('ua-data-card-checked');
|
||||
} else {
|
||||
$target.toggleClass('ua-data-card-checked');
|
||||
}
|
||||
});
|
||||
|
||||
// (b) 模板引擎优先级解析:tplFunction > tplLay > tplVue > tplLayId > tplVueId,
|
||||
|
||||
Reference in New Issue
Block a user