vxe-table 行 Hover 联动高亮
近期需求是双表格联动高亮:
- 鼠标移入左侧表格某一行时,右侧对应行同步高亮;
- 鼠标移入右侧表格某一行时,左侧对应行也同步高亮。
实现思路
项目使用 vxe-table。在当前场景下,采用原生事件监听 tr 的 mouseenter/mouseleave 更直接可控:
- 给目标表格行绑定移入/移出事件;
- 在回调中拿到当前行索引;
- 根据映射关系找到另一侧需要联动的行索引;
- 对目标行批量设置/清除高亮样式。
为避免重复绑定导致事件叠加,使用 WeakMap 保存并复用事件处理函数引用。
ts
import { isArray, isFunction, isString } from "lodash-es";
type Tr = HTMLTableRowElement;
type TrList = NodeListOf<Tr>;
type EventType = "mouseenter" | "mouseleave";
type TrEventCallBack = (ops: Omit<IItemTrFunCbParams, "callback">) => void;
interface ITrMouseEnterParams {
/** 表格tr选择器 */
selector: string;
/** 回调函数 */
callback?: TrEventCallBack;
}
interface IItemTrFunCbParams {
/** 鼠标事件对象或事件目标元素 */
row: MouseEvent | { target: Tr };
/** 行索引 */
rowIndex: number;
/** 事件类型 */
eventType: EventType;
/** 回调函数 */
callback?: TrEventCallBack;
}
interface IFindTableTrParams {
/** 表格tr选择器 */
selector: string;
/** 行索引数组 */
indexes: number[];
/** 事件类型 */
eventType: EventType;
}
// 使用 WeakMap 存储每个元素的事件处理函数引用
const eventHandlersMap = new WeakMap<
Tr,
{
mouseenter: (e: MouseEvent) => void;
mouseleave: (e: MouseEvent) => void;
}
>();
class HoverTableUtil {
static trColor = "#ff880019";
/**
* 查找表格tr元素并绑定鼠标移入移出事件
* @param param0 查找表格tr参数
* @returns 无返回值
*/
findTableTr({ selector, indexes, eventType }: IFindTableTrParams) {
if (!selector || !isString(selector)) return;
if (!isArray(indexes)) return;
for (let i = 0; i < indexes.length; i++) {
const item = indexes[i];
const tr = document.querySelectorAll(selector)[item] as Tr;
if (!tr) continue;
HoverTableUtil.itemTrFunCb({
row: { target: tr },
rowIndex: i,
eventType,
});
}
}
/**
* 表格 tr 鼠标事件回调函数
* @param param0 表格 tr 鼠标事件参数
* @returns 无返回值
*/
static itemTrFunCb({ row, rowIndex, eventType, callback }: IItemTrFunCbParams) {
if (!row) return;
const target = row.target as Tr;
target.style.backgroundColor = eventType === "mouseenter" ? HoverTableUtil.trColor : "";
if (isFunction(callback)) callback({ row, rowIndex, eventType });
}
/**
* 表格 tr 鼠标移入移出事件绑定
* @param param0 表格 tr 鼠标事件参数
* @returns 无返回值
*/
trMouseEnter({ selector, callback }: ITrMouseEnterParams) {
if (!selector || !isString(selector)) return;
const trList: TrList = document.querySelectorAll(selector);
for (let i = 0; i < trList.length; i++) {
const item = trList[i];
const existingHandlers = eventHandlersMap.get(item);
if (existingHandlers) {
item.removeEventListener("mouseenter", existingHandlers.mouseenter);
item.removeEventListener("mouseleave", existingHandlers.mouseleave);
eventHandlersMap.delete(item);
}
// 创建新的事件处理函数
const mouseenterHandler = (row: MouseEvent) => {
HoverTableUtil.itemTrFunCb({
row,
rowIndex: i,
eventType: "mouseenter",
callback,
});
};
const mouseleaveHandler = (row: MouseEvent) => {
HoverTableUtil.itemTrFunCb({
row,
rowIndex: i,
eventType: "mouseleave",
callback,
});
};
// 保存函数引用
eventHandlersMap.set(item, {
mouseenter: mouseenterHandler,
mouseleave: mouseleaveHandler,
});
// 挂载事件
item.addEventListener("mouseenter", mouseenterHandler);
item.addEventListener("mouseleave", mouseleaveHandler);
}
}
}
export const hoverTableUtil = new HoverTableUtil();
使用示例
ts
// 使用demo
watch(
() => data1.value,
(val) => {
hoverTableUtil.trMouseEnter({
selector: ".left-table table tbody tr",
callback: ({ rowIndex, eventType }) => {
hoverTableUtil.findTableTr({
selector: ".right-table table tbody tr",
indexes: [], // 高亮的索引合集
eventType,
});
},
});
},
);
watch(
() => data2.value,
(val) => {
hoverTableUtil.trMouseEnter({
selector: ".right-table table tbody tr",
callback: ({ rowIndex, eventType }) => {
hoverTableUtil.findTableTr({
selector: ".left-table table tbody tr",
indexes: [], // 高亮的索引合集
eventType,
});
},
});
},
);
注意事项
watch重新触发时会重复绑定事件,已通过WeakMap + removeEventListener做清理。indexes建议由业务层提前计算好(如主键映射),避免在 hover 回调里做重计算。- 高亮样式建议统一为 class 控制,复杂场景可替换直接写
style的方式。
相关文章
GridView 宫格加载渲染优化
系统首页 GridView 宫格模块接口耗时不高,但首次进入总耗时接近 22s。复盘耗时分层定位过程、代码层面的瓶颈(约 2000 行、100 个 tab 重复节点)、优化手段与最终指标对比。
执行价格弹窗:表头 / 表体合并与可配置表格
业务需要在「执行价格」类弹窗中展示多块价格配置(基础、颜色、规格、行业等)。每块区域具备:
内部插件 / 工具库开发实践
在企业前端项目中,utils、hooks、libs 这类通用能力通常分散在多个仓库,常见问题包括:
新商家系统性能优化实践
商家系统新版本上线后,团队持续针对构建效率与用户体验做了一轮系统性优化。本文记录核心方案与落地结果,供后续版本复用。
老系统升级与兼容改造实践
公司原有业务系统采用 Node + jQuery 架构,长期运行后暴露出典型遗留系统问题:
键盘弹起导致底部被顶起问题(H5 适配)
在移动端 H5 页面中,当用户聚焦 input、textarea 等可编辑元素、软键盘弹出时,常见表现包括:
Series
team documents
21 / 22