Vue3 vxe-table 实现跨固定列区域鼠标框选功能

1. 为什么我们需要跨固定列的鼠标框选?

如果你用过Excel或者WPS表格,肯定对鼠标拖拽选中一片区域的功能不陌生。这个功能在网页表格里,尤其是在处理大量数据时,简直是个“效率神器”。想象一下,你要从一个有几十列、几百行的员工信息表里,批量复制“姓名”和“手机号”这两列固定列的数据,同时还要选中中间“绩效评分”、“出勤天数”这些不固定的列。如果只能一行一行、一列一列点,那估计点完天都黑了。

在Vue3生态里,vxe-table是个功能非常强大的表格组件,它自带了丰富的选择功能,比如单选、多选、行选择、列选择。但是,当表格设置了左右固定列时,原生的区域选择功能就有点“力不从心”了。你会发现,鼠标框选的范围无法跨越固定列和滚动区域之间的“结界”。固定列区域和中间的可滚动区域像是两个独立的表格,鼠标事件被隔开了,这直接导致我们无法实现那种流畅的、从固定列开始一直拖到表格另一端的“大片选择”体验。

我最近在一个后台管理系统的报表模块就遇到了这个痛点。产品经理要求用户能像操作本地Excel一样,用鼠标自由框选表格的任何区域,然后一键导出或批量操作。特别是当左侧固定了“序号”和“关键指标”,右侧固定了“操作”按钮列时,用户的选择操作必须是连贯的。如果实现不了,用户体验就会大打折扣,显得很“割裂”。所以,动手实现一个支持跨固定列区域的鼠标框选功能,就成了一个刚需。这不仅仅是画个框那么简单,它涉及到多个DOM区域的联动、鼠标事件的精准捕获、以及动态范围的计算,是一个挺有意思的前端交互挑战。

2. 核心思路拆解:如何让鼠标事件“穿透”固定列?

在开始写代码之前,我们得先把这件事儿的原理想明白。vxe-table在渲染固定列时,实际上是把表格“拆”成了三个部分:左侧固定列容器、中间主滚动区域容器、右侧固定列容器。每个容器都有自己独立的tbodytable结构。这就带来了第一个问题:鼠标事件是隔离的。你在左边固定列按下鼠标开始拖动,这个mousedown事件只会停留在左边的容器里,鼠标移到中间区域时,左边容器就接收不到mousemove事件了。

所以,我们的核心思路可以概括为 “事件代理,统一计算,分区域渲染”

第一步,事件监听要覆盖所有区域。 我们不能只给中间的主表格区域绑定鼠标事件,必须同时给左侧固定列和右侧固定列的tbody也绑上同样的事件监听器(mousedown, mousemove, mouseup等)。这样,无论用户在哪个区域按下鼠标,我们都能捕获到起点。

第二步,建立一个全局的选区状态管理。 我们需要用几个响应式变量来记录当前是否正在选择(isSelecting)、选择的起始单元格坐标(selectionStart)和结束单元格坐标(selectionEnd)。这个坐标不是像素坐标,而是行列索引(rowIndex, cellIndex)。无论鼠标在哪个子区域移动,我们都用同一套逻辑去更新这个结束坐标。

第三步,动态计算选区框的尺寸和位置。 这是最核心的计算部分。当我们有了起始和结束的行列索引后,我们需要遍历所有列(包括固定列和滚动列)的宽度,以及所有行的高度,来计算出一个覆盖所有三个区域的、虚拟的“选区矩形”。这个矩形的宽度是选中所有列的宽度总和,高度是选中所有行的高度总和。它的定位(top, left, right)则需要根据选中列是偏左还是偏右来分别计算,因为固定列的定位方式是fixedabsolute,它们的坐标系是独立的。

第四步,在三个区域分别渲染选区框。 计算出总的选区范围后,我们需要在左侧固定列容器、中间主容器、右侧固定列容器里,分别创建并放置一个半透明的遮罩层(即选区框)。让这三个框在视觉上看起来是一个完整的、跨越了不同滚动区域的整体。当鼠标移动时,同步更新这三个框的位置和大小。

听起来有点复杂?别担心,我们接下来就一步步用代码把它实现出来。我会把我在实际项目中踩过的坑和优化技巧都分享给你。

3. 环境搭建与基础表格配置

工欲善其事,必先利其器。首先,我们得把项目和基础表格跑起来。我用的环境是 Vue 3.3.4 和 vxe-table 4.5.7,这也是目前比较稳定的一个组合。如果你用的是更新的版本,核心思路应该是一样的,但可能有些API细节需要微调。

先安装依赖:

npm install vue@3.3.4 vxe-table@4.5.7
# 或者
yarn add vue@3.3.4 vxe-table@4.5.7

接下来,我们创建一个Vue组件,先把一个带有左右固定列的基础表格搭起来。这是我们的“画布”。为了模拟真实场景,我设计了一个员工信息表,左侧固定“ID”和“姓名”,中间是“年龄”、“性别”等长文本信息(可横向滚动),右侧固定“岗位”和“地址”。

<template>
  <div>
    <!-- 这三个div是我们的选区框容器,先准备好 -->
    <div class="vxe-table--cell-area" ref="cellAreaRef">
      <span class="vxe-table--cell-main-area"></span>
      <span class="vxe-table--cell-active-area"></span>
    </div>
    <div class="vxe-table--cell-area" ref="leftFixedCellAreaRef">
      <span class="vxe-table--cell-main-area"></span>
      <span class="vxe-table--cell-active-area"></span>
    </div>
    <div class="vxe-table--cell-area" ref="rightFixedCellAreaRef">
      <span class="vxe-table--cell-main-area"></span>
      <span class="vxe-table--cell-active-area"></span>
    </div>

    <!-- vxe-table 主表格 -->
    <vxe-grid
      ref="xGridRef"
      v-bind="gridOptions"
      height="500px"
      @toolbar-button-click="handleToolbarClick"
    ></vxe-grid>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, onMounted, nextTick } from 'vue'
import type { VxeGridProps } from 'vxe-table'

// 表格实例引用
const xGridRef = ref()
// 三个选区框的DOM引用
const cellAreaRef = ref()
const leftFixedCellAreaRef = ref()
const rightFixedCellAreaRef = ref()

// 表格配置项
const gridOptions = reactive<VxeGridProps<any>>({
  toolbarConfig: {
    perfect: true,
    enabled: true,
    size: 'mini',
    buttons: [
      { code: 'getSelectData', name: '获取选中数据', type: 'text' }
    ]
  },
  columnConfig: {
    resizable: true, // 允许调整列宽
    useKey: true // 列拖拽必需
  },
  border: 'full', // 完整边框
  stripe: true, // 斑马纹
  showOverflow: true, // 重要:内容超出时显示,保证布局正确
  rowConfig: {
    isCurrent: true,
    height: 35, // 固定行高,方便计算
    isHover: true
  },
  columns: [
    { width: 100, field: 'id', title: 'ID', fixed: 'left' },
    { width: 100, field: 'name', title: '姓名', fixed: 'left' },
    { width: 400, field: 'age', title: '年龄' },
    { width: 400, field: 'sex', title: '性别' },
    { width: 400, field: 'department', title: '部门' },
    { width: 100, field: 'job', title: '岗位', fixed: 'right' },
    { width: 100, field: 'address', title: '地址', fixed: 'right' }
  ],
  data: [
    // ... 这里放你的测试数据,至少20行以上,才能看到滚动效果
    { id: 1, name: '张三', age: 30, sex: '男', department: '技术部', job: '前端工程师', address: '北京' },
    { id: 2, name: '李四', age: 28, sex: '女', department: '市场部', job: '市场专员', address: '上海' },
    // ... 更多数据
  ]
})

// 工具栏按钮点击事件
const handleToolbarClick = ({ code }) => {
  if (code === 'getSelectData') {
    // 这里先留空,后面我们会实现获取选中数据的逻辑
    console.log('点击了获取数据按钮')
  }
}
</script>

<style lang="less" scoped>
// 先禁用文本选择,避免拖动时选中文字
.vxe-grid {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  
源码直接下载地址: https://pan.quark.cn/s/95437fdf229e Intel I-219V网卡驱动是一款专门为Intel的I-219V千兆以太网控制器而研发的驱动程序,其主要作用在于保障在Ubuntu 16.04操作系统环境下的正常运作以及优化系统性能。Intel I-219V作为一款广泛应用的内置网络接口控制器(NIC),常被集成在台式机及笔记本电脑的主板上,负责提供高速的网络连接服务。Intel公司所提供的e1000e驱动是与此硬件相配套的开源驱动解决方案,其中版本3.3.5.3是专门针对该硬件设备的定制版本。此驱动包含了不可或缺的源代码部分,赋予开发者和系统管理者按照特定需求进行编译和定制的权限,从而能够适应多样化的系统配置或针对特定情形进行问题解决。源代码的可用性同样表明用户有能力依据Linux内核的更新情况来升级驱动,确保与最新技术标准的兼容性。在Ubuntu 16.04系统中成功编译的驱动意味着它已经通过了严苛的测试流程,并能够与该版本的Linux内核实现良好兼容。Ubuntu 16.04,其代号为Xenial Xerus,是一个长期支持(LTS)的版本,因此对于那些追求系统稳定性和安全保障的用户群体而言具有特殊的意义。驱动程序的兼容性保障了I-219V网卡能够在该系统平台上实现无缝运行,提供稳定可靠的网络连接,这既包括局域网(LAN)的连接,也可能涵盖通过Wi-Fi桥接实现的无线网络连接。驱动程序的核心职责涵盖了网络接口的初始化与管理、数据包的接收与发送处理,以及错误检测与纠正功能的执行。在Linux操作系统架构中,驱动通常以模块的形式加载至内核之中,这种设计允许在非必要时期进行卸载操作,以此来有效节省系统资源。e1000e驱...
内容概要:本文围绕基于共识的捆绑算法(CBBA)在多智能体系统中的多任务分配问题展开研究,重点应用于远程太空船交会与维修的相对轨道操作(RPO)规划。通过Matlab代码实现了CBBA算法,系统地解决了多个航天器在复杂空间环境下协同执行多目标任务时的任务分配、路径规划与动态协商问题。研究详细展示了算法在任务分解、竞标机制、共识达成及冲突消解等方面的核心逻辑,验证了其在分布式决策、通信受限条件下的高效性与鲁棒性,并结合航天工程实际背景突出了算法的应用价值。该资源不仅提供完整的仿真代码,还包含详细的流程解析,有助于深入理解多智能体协同机制的设计原理。; 适合人群:具备控制理论、航天器动力学、多智能体系统或分布式优化背景的研究生、科研人员及航空航天领域工程技术人员,熟练掌握Matlab编程者尤佳。; 使用场景及目标:①应用于在轨服务、空间碎片清除、多航天器编队飞行、星座维护等多智能体协同任务的任务分配与规划;②为研究人员提供CBBA算法的实现范例,支撑其开展分布式任务规划算法的改进与扩展研究;③作为教学案例用于高级课程中讲解多智能体协同决策机制。; 阅读建议:建议结合Matlab代码逐模块分析算法实现过程,重点关注任务打包、竞标更新、共识收敛等关键环节,可尝试引入通信延迟、故障容错或障碍规避机制以进一步提升算法实用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值