ConfigList 配置列表
介绍
通用列表容器:分页加载、筛选、详情与新增,接口数据内存缓存。
组合使用 config-list、config-form、config-detail、config-footer,覆盖列表、详情、保存等常见 CRUD 场景。
基础用法(#item)
无列表增删动画时,用 #item 即可。列表内部已做 v-for,插槽只负责单行内容;适合筛选、分页、跳转详情等常规场景。
html
<config-list
ref="listRef"
list-key="id"
:api="fetchTaskList"
:params="params"
:immediate="true"
:row-gap="12"
@item-click="handleItemClick"
>
<template #item="{ item, index, checked }">
<view class="task-card">
<view class="title">{{ item.title }}</view>
<view class="desc">{{ item.content || '暂无描述' }}</view>
</view>
</template>
</config-list>插槽参数:
| 参数 | 说明 |
|---|---|
item | 当前行数据 |
index | 下标 |
checked | 当前行是否选中(配合 v-model:checked) |
TIP
#item 与 #content 二选一。传入 #content 后不再渲染内置 #item 列表。
列表动画(#content)
需要增删动画时,不要往 #item 里塞 transition-group,改用 #content,在页面侧自行接入 TransitionGroup + TransitionCollapse。
为什么不内置 transition-group
微信小程序对「自定义组件内 v-for + 作用域插槽」支持不完整。若在列表组件内部用 #item 再包动画:
- 作用域插槽会编译成
item-0、item-1… 按下标命名 - 列表前插 / 删除时下标变化,再叠加离场占位,容易出现
More than one slot named "item-0"、空高度占位等异常 - H5 往往正常,小程序复现,属于端能力差异,不是业务数据写错
因此:#item 只做静态行渲染;动画结构放到页面,让 v-for 落在页面节点上。
正确写法
#content 提供数据源;页面维护本地 values,v-for 遍历 values(不要遍历 data):
html
<config-list
ref="listRef"
list-key="id"
:api="fetchTaskList"
:params="params"
:immediate="true"
:row-gap="12"
:back-top="true"
>
<template #content="{ data, getKey }">
<vd-transition-group
v-if="data.length"
v-model="values"
:data="data"
:data-key="getKey"
name="enter-right"
:duration="{ enter: 400, leave: 600 }"
:delay="{ enter: 100, leave: 100 }"
>
<vd-transition-collapse
v-for="item in values"
:key="getKey(item)"
:item-key="getKey(item)"
custom-class="task-card"
content-class="task-content"
@click="handleItemClick(item)"
>
<view class="task-head">
<view class="title">{{ item.title }}</view>
<!-- ... -->
</view>
<view class="task-desc">{{ item.content || '暂无描述' }}</view>
<view class="task-footer" @click.stop>
<!-- 删除等操作 -->
</view>
</vd-transition-collapse>
</vd-transition-group>
</template>
</config-list>ts
const values = ref<any[]>([]);
// 筛选 / 重载前清空 values,避免旧离场项残留
function handleSearch() {
values.value = [];
listRef.value?.reloadData();
}
// 从详情返回时刷新已加载区间
onReshow(() => {
listRef.value?.refreshData();
});样式上建议:custom-class 放卡片外壳(背景、圆角、阴影),content-class 放内容区内边距,避免折叠测高把 padding 算乱。
#content 常用参数:
| 参数 | 说明 |
|---|---|
data | 列表数据源(完整数据,不含离场占位) |
total | 总数 |
checked | 已选中项 |
getKey | 按 list-key 取唯一标识 |
isChecked | 判断某项是否选中 |
注意事项
- 有动画时用
#content;无动画时用#item,二者不要混用。 v-for必须遍历values:data是完整数据源,values才含离场项;遍历data时删除没有离场动画。item-key/:key用稳定唯一标识(如id),与list-key/data-key一致,不要用index。- 增删改走列表接口数据:
reloadData/refreshData/refreshItem更新data;由transition-group同步values。 - 筛选、强制重载前先
values = [],再reloadData(),避免上一批离场项残留。 - 跨端:H5 上「
#item+ transition-group」偶发可用,小程序仍可能异常,动画请统一走#content。
错误示范
不要在 #item 里包 transition-group
html
<!-- ❌ 错误:组件内作用域插槽 + 动画,小程序增删易异常 -->
<config-list :api="fetchTaskList">
<template #item="{ item }">
<vd-transition-collapse :item-key="item.id">
...
</vd-transition-collapse>
</template>
</config-list>html
<!-- ✅ 无动画:用 #item -->
<config-list :api="fetchTaskList">
<template #item="{ item }">
<view class="task-card">{{ item.title }}</view>
</template>
</config-list>
<!-- ✅ 有动画:用 #content,在页面 v-for values -->不要对 data 做 v-for
html
<!-- ❌ 错误:离场项只存在于 values -->
<vd-transition-group v-model="values" :data="data" data-key="id">
<vd-transition-collapse
v-for="item in data"
:key="item.id"
:item-key="item.id"
/>
</vd-transition-group>html
<!-- ✅ 正确 -->
<vd-transition-collapse
v-for="item in values"
:key="item.id"
:item-key="item.id"
/>不要用 index 当 key
html
<!-- ❌ 错误:前插/删除后节点复用错乱 -->
<vd-transition-collapse
v-for="(item, index) in values"
:key="index"
:item-key="index"
/>筛选时不要忘记清空 values
ts
// ❌ 错误:只 reload,旧 values 可能残留离场项
function handleSearch() {
listRef.value?.reloadData();
}
// ✅ 正确
function handleSearch() {
values.value = [];
listRef.value?.reloadData();
}