在前端开发中,丰富的交互体验能够显著提升用户体验。本文将介绍如何基于 Vue 3 实现一个表格交互功能:当鼠标移入表格内时,监听键盘事件,按下字母键可筛选表格中名字首字母匹配的数据,再次按下相同字母键可循环查找下一个匹配项。
实现思路
表格展示与基础配置 :使用 Vue 3 的组合式 API,借助
a-table
组件展示表格数据,配置好表格的列信息、数据源等基础属性。事件监听与移除 :当鼠标移入表格时添加键盘事件监听,移出时移除监听,避免全局监听带来的性能问题和不必要的干扰。
键盘事件处理 :在键盘事件处理函数中,判断按下的是字母键,根据按键字母在表格数据中查找名字首字母匹配的数据,若存在匹配数据,进行相应的选中操作。
匹配数据处理与选中 :将匹配的数据存储起来,方便后续循环查找下一个匹配项。实现选中匹配行的功能,并利用
scrollIntoView
方法平滑滚动到选中行位置。
代码实现
<template>
<div class="info" @mouseenter="mouseEnter" @mouseleave="mouseLeave">
<a-table
:dataSource="dataSource"
:columns="columns"
:pagination="false"
:scroll="{ y: 600 }"
:rowClassName="(record, index) => getRowClassName(record, index)"
ref="tableRef"
/>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import Mock from "../../mock/index";
const dataSource = ref([]);
const columns = reactive([
{
title: "姓名",
dataIndex: "name",
key: "name",
width: 100,
},
{
title: "电话",
dataIndex: "telPhone",
key: "telPhone",
width: 100,
},
{
title: "住址",
dataIndex: "address",
key: "address",
width: 200,
},
]);
const tableRef = ref(null);
const currentyKey = ref();
const curIndex = ref(0);
const isSearching = ref(false);
const matchData = ref([]); // 匹配的数据数组
// 获取行样式
const getRowClassName = (record, index) => {
console.log(index);
return dataSource.value[index]?.isSelected ? "selected-row" : "row-one";
};
const mouseEnter = () => {
document.addEventListener("keydown", handleKeyDown);
};
const mouseLeave = () => {
document.removeEventListener("keydown", handleKeyDown);
};
// 监听键盘事件
const handleKeyDown = (event) => {
const key = event.key.toUpperCase();
if (key.match(/[A-Z]/)) {
if (key === currentyKey.value && isSearching.value) {
nextMatch();
} else {
currentyKey.value = key;
searchByKey(key);
}
}
};
// 查找表格内容
const searchByKey = (key) => {
isSearching.value = true;
matchData.value = [];
curIndex.value = 0;
dataSource.value.forEach((item, index) => {
if (item.name.toUpperCase().startsWith(key)) {
matchData.value.push({ ...item, originalIndex: index });
}
});
if (matchData.value.length > 0) {
selectedRow(0);
}
};
// 选中匹配的项
const selectedRow = (index) => {
if (index >= 0 && index < matchData.value.length) {
const item = matchData.value[index];
dataSource.value.forEach((row) => {
row.isSelected = false;
});
// 选中行
selectRow(item.originalIndex);
curIndex.value = index;
if (tableRef.value) {
const tableBody = tableRef.value?.$el.querySelector(".ant-table-body");
if (tableBody) {
const targetRow = tableBody.querySelectorAll("tr")[item.originalIndex];
if (targetRow) {
// 使用 scrollIntoView 实现平滑滚动
targetRow.scrollIntoView({ behavior: "smooth", block: "center" });
}
}
}
}
};
// 下一个匹配项
const nextMatch = () => {
if (isSearching.value && matchData.value.length > 0) {
//取模运算,确保索引不越界,实现循环效果。
const nextIndex = (curIndex.value + 1) % matchData.value.length;
selectedRow(nextIndex);
}
};
// 选中行的方法
const selectRow = (index) => {
dataSource.value[index].isSelected = true;
};
onMounted(() => {
dataSource.value = Mock.getData().data;
});
</script>
<style lang="less" scoped>
.info {
width: 80%;
height: 600px;
margin: 0 auto;
:deep(.ant-table) {
.selected-row {
.ant-table-cell {
background-color: #4caf50 !important;
color: white !important;
}
}
}
}
</style>
代码解析
表格展示与数据绑定 :通过
a-table
组件展示表格,使用dataSource
绑定表格数据,columns
定义表格列信息,包括列的标题、数据字段、宽度等。事件监听与处理 :在
mouseEnter
和mouseLeave
函数中分别添加和移除键盘事件监听,确保只有当鼠标在表格内时才监听键盘事件。handleKeyDown
函数用于处理键盘按下事件,判断按下的是否为字母键,并根据按键字母进行相应的查找操作。查找与匹配 :
searchByKey
函数根据按键字母在表格数据中查找名字首字母匹配的数据,将其存储在matchData
中,并调用selectedRow
函数选中第一个匹配项。nextMatch
函数用于实现再次按下相同字母键时查找下一个匹配项的功能。选中与滚动 :
selectedRow
函数负责选中匹配的行,并利用scrollIntoView
方法实现平滑滚动到选中行位置,增强用户体验。