Angular13双列表穿梭框移动留副本、选中状态及active类问题
Angular13双列表功能改造及异常修复
现有基于Angular13实现的左右双列表已支持项移动、自动去重能力,需完成以下需求并修复异常:
- 列表项从左侧移动至右侧时,左侧保留原项副本,不删除源项
- 点击选中某侧列表项时,仅当前点击侧的项进入选中状态,避免左右两侧同内容项同时被选中
- 修复选中项点击移动按钮完成移动后,原列表项仍残留
active类样式的问题
原有代码核心问题
- 移动逻辑未区分左右移场景,默认所有移动操作都会删除源列表选中项,且左移逻辑目标数组误写为不存在的
dummyArray,功能完全异常 - 选中状态仅对比对象引用,未标记选中项所属列表侧,导致同引用/同内容项在两侧会同步触发选中样式
- 选中切换逻辑冗余错误,存在无意义的列表项插入操作,移动后清空选中数组的逻辑未配合判断规则生效,导致样式残留
改造实现代码
TS逻辑部分
// 类中已有的数据源声明保持原有初始化逻辑即可,仅修改以下方法 agentInView: any[] = []; agentNotinView: any[] = []; // 改造选中项存储结构,同时绑定项对象和所属列表侧 activeItems: {item: any, side: 'left' | 'right'}[] = []; public moveToTheRight(): void { // 右移不删除左侧源项 this.move('agentInView', 'agentNotinView', false); } public moveToTheLeft(): void { // 左移删除右侧源项,修正原有错误的目标数组 this.move('agentNotinView', 'agentInView', true); } /** * 跨列表移动通用方法 * @param from 源列表数据源属性名 * @param to 目标列表数据源属性名 * @param deleteSource 移动后是否删除源列表选中项 */ public move(from: 'agentInView' | 'agentNotinView', to: 'agentInView' | 'agentNotinView', deleteSource: boolean): void { const sourceSide = from === 'agentInView' ? 'left' : 'right'; // 提取当前源列表所有选中项 const selectedItems = this[from].filter(item => this.isInActiveItems(item, sourceSide)); // 去重后推入目标列表 selectedItems.forEach(item => { const isExist = this[to].some(target => target.id === item.id); if (!isExist) this[to].push({...item}); }); // 按需删除源列表选中项 if (deleteSource) { this[from] = this[from].filter(item => !selectedItems.includes(item)); } // 目标列表按id排序 this[to].sort((a, b) => a.id > b.id ? 1 : -1); // 清空所有选中状态,自动移除active样式 this.activeItems = []; } /** * 切换列表项选中状态 * @param eventItem 点击的列表项 * @param side 项所属列表侧 */ public toggleActiveItem(eventItem: any, side: 'left' | 'right'): void { const activeIndex = this.activeItems.findIndex(record => record.item === eventItem && record.side === side); if (activeIndex > -1) { this.activeItems.splice(activeIndex, 1); } else { this.activeItems.push({item: eventItem, side}); } } /** * 判断列表项是否选中 * @param eventItem 待判断项 * @param side 项所属列表侧 */ public isInActiveItems(eventItem: any, side: 'left' | 'right'): boolean { return this.activeItems.some(record => record.item === eventItem && record.side === side); }
HTML模板部分
仅需修改左右两个列表中<li>项的选中判断和点击事件传参,其余页面结构保持不变:
- 左侧
agentInView列表的li标签修改为:
<li class="list-group-item {{ isInActiveItems(child, 'left') ? 'active' : '' }}" (click)="toggleActiveItem(child, 'left')" > {{ child.value }} </li>
- 右侧
agentNotinView列表的li标签修改为:
<li class="list-group-item {{ isInActiveItems(child, 'right') ? 'active' : '' }}" (click)="toggleActiveItem(child, 'right')" > <input type="text" [(ngModel)]="child.value" /> </li>
改造点对应说明
- 左移保留源项:通过
deleteSource参数区分移动场景,右移时仅复制项到右侧、不修改左侧列表,左移时正常删除右侧选中项,同时修复了原有左移目标数组错误的问题 - 单侧选中隔离:选中项存储时绑定所属列表侧标识,选中判断必须同时匹配项对象和所属侧,彻底避免两侧同内容项联动选中
- 样式残留修复:移动完成后直接清空选中列表,配合新的双维度选中判断规则,所有项的
active类会随数据变化自动移除,无残留
内容的提问来源于stack exchange,提问作者Bhrungarajni
相关产品推荐
相关产品推荐

