el-table 鼠标滚轮控制横向滚动

650 阅读4分钟

Element UI Table组件扩展:实现鼠标横向滚动和提示功能(欢迎指导)

PixPin_2025-05-22_10-32-34.gif

前言

在使用Element UI的Table组件时,当表格列数较多时,需要通过水平滚动条来查看更多的列数据。为了提升用户体验,我们可以通过扩展Table组件,实现使用鼠标滚轮进行横向滚动的功能,并添加相应的提示信息。本文将详细介绍如何实现这一功能。

功能特点

  • 支持使用鼠标滚轮进行横向滚动(按住Alt键)
  • 自动检测表格是否需要横向滚动
  • 提供可配置的提示信息和位置
  • 支持双击切换滚动方向(垂直/水平)
  • 完全兼容Element UI Table的所有功能和属性

实现原理

1. 组件结构

组件通过扩展Element UI的Table组件实现,主要包含以下核心功能:

  • 监听鼠标滚轮事件,实现横向滚动
  • 自动检测表格滚动条状态
  • 提供可配置的提示信息
  • 支持滚动方向切换

2. 核心代码实现

2.1 组件定义
import { Table } from "element-ui";

export const tableMouseHorizontalWheel = {
    extends: Table,
    data() {
      return {
        tooltipContentList: [],
        tooltipVisible: this.showTooltip,
        scrollDirection: 'vertical', // 默认为垂直滚动
        isScrollingToEdge: false, // 是否滚动到边缘
      };
    },
    props: {
      /** @prop {Boolean} [disableMouseHorizontalWheel=false] - 是否禁用鼠标横向滚动功能 */
      disableMouseHorizontalWheel: {
        type: Boolean,
        default: false,
      },
      /** @prop {Boolean} [hiddenMouseWheel=false] - 是否隐藏鼠标滚动提示 */
      hiddenMouseWheel: {
        type: Boolean,
        default: false,
      },
      /** @prop {Boolean} [showTooltip=false] - 是否显示提示信息 */
      showTooltip: {
        type: Boolean,
        default: false,
      },
      /** @prop {String|Array} [tooltipContent=[]] - 提示信息内容 */
      tooltipContent: {
        type: [String, Array],
        default: () => [],
      },
      /** @prop {Object} [tooltipPosition={ top: "10px", left: "10px" }] - 提示信息位置 */
      tooltipPosition: {
        type: Object,
        default: () => ({
          top: "10px",
          left: "10px",
        })
      },
    }
    // ... 其他代码省略
}
2.2 横向滚动实现
handleWheel(event) {
  const tableBody = this.$el.querySelector(".el-table__body-wrapper");
  // 当表格内容高度小于容器高度时,直接启用横向滚动
  if(tableBody.scrollHeight <= tableBody.clientHeight) {
    event.preventDefault();
    tableBody.scrollLeft += event.deltaY;
    return;
  }
  // 当处于水平滚动模式或按住Alt键时,启用横向滚动
  if (this.scrollDirection === 'horizontal' || event.altKey) {
    event.preventDefault();
    tableBody.scrollLeft += event.deltaY;
  }
}
2.3 滚动条检测
hasScrollbarByMff() {
  const tableBody = this.$el.querySelector(".el-table__body-wrapper");
  // 检测竖向滚动条
  const verticalScrollbarWidth = tableBody.scrollHeight - tableBody.clientHeight;
  // 检测横向滚动条
  const horizontalScrollbarHeight = tableBody.scrollWidth - tableBody.clientWidth;
  
  // 当同时存在横向和纵向滚动条时,显示提示信息
  if (verticalScrollbarWidth > 0 && horizontalScrollbarHeight > 0 && !this.hiddenMouseWheel) {
    this.tooltipContentList.push("按住Alt键可以横向滚动表格");
    this.tooltipVisible = true;
    this.$el.addEventListener("dblclick", this.toggleScrollDirection);
    this.tooltipContentList.push('双击表格任意位置可切换滚动方向');
  } else {
    // 清除提示信息
    this.tooltipContentList = this.tooltipContentList.filter(item => 
      !item.includes('按住Alt键可以横向滚动表格') && 
      !item.includes('双击表格任意位置可切换滚动方向')
    );
    this.tooltipVisible = false;
  }
}
2.4 全部代码
import { Table } from "element-ui";

/**
 * @description 扩展Element UI Table组件,支持鼠标横向滚动和提示功能
 * @extends {Table}
 */
export const tableMouseHorizontalWheel = {
    extends: Table,
    data() {
      return {
        tooltipContentList: [],
        tooltipVisible: this.showTooltip,
        scrollDirection: 'vertical', // 默认为垂直滚动
        isScrollingToEdge: false, // 是否滚动到边缘
      };
    },
    props: {
      /** @prop {Boolean} [disableMouseHorizontalWheel=false] - 是否禁用鼠标横向滚动功能 */
      disableMouseHorizontalWheel: {
        type: Boolean,
        default: false,
      },
      /** @prop {Boolean} [hiddenMouseWheel=false] - 是否隐藏鼠标滚动提示 */
      hiddenMouseWheel: {
        type: Boolean,
        default: false,
      },
      /** @prop {Boolean} [showTooltip=false] - 是否显示提示信息 */
      showTooltip: {
        type: Boolean,
        default: false,
      },
      /** @prop {String|Array} [tooltipContent=[]] - 提示信息内容 */
      tooltipContent: {
        type: [String, Array],
        default: () => [],
      },
      /** @prop {Object} [tooltipPosition={ top: "10px", left: "10px" }] - 提示信息位置 */
      tooltipPosition: {
        type: Object,
        default: () => ({
          top: "10px",
          left: "10px",
        })
      },
    },
    created() {
      // 初始化提示信息列表
      if (Array.isArray(this.tooltipContent)) {
        this.tooltipContentList.push(...this.tooltipContent);
      } else {
        this.tooltipContentList.push(this.tooltipContent);
      }
    },
  
    mounted() {
      const newHasScrollbarByMff = _.debounce(this.hasScrollbarByMff, 10);
      // 监听this.$el元素变化
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.type === "childList") {
            newHasScrollbarByMff();
          }
        });
      });
      observer.observe(this.$el, {
        childList: true,
        subtree: true,
      });
  
      if (!this.disableMouseHorizontalWheel) {
        this.$el.addEventListener("wheel", this.handleWheel);
        
      }
    },
    beforeDestroy() {
      if (!this.disableMouseHorizontalWheel) {
        this.$el.removeEventListener("wheel", this.handleWheel);
      }
    },
    methods: {
      /**
       * @description 处理鼠标滚轮事件,实现横向滚动
       * @param {WheelEvent} event - 鼠标滚轮事件对象
       */
      handleWheel(event) {
        const tableBody = this.$el.querySelector(".el-table__body-wrapper");
        // tableBody.scrollHeight <= tableBody.clientHeight
        if(tableBody.scrollHeight <= tableBody.clientHeight) {
          event.preventDefault();
          tableBody.scrollLeft += event.deltaY;
          return;
        }
        if (this.scrollDirection === 'horizontal' || event.altKey) {
          event.preventDefault();
          tableBody.scrollLeft += event.deltaY;
        }
      },
      /**
       * @description 检测表格是否同时存在横向和纵向滚动条,并显示提示信息
       */
      /**
       * @description 切换滚动方向
       */
      toggleScrollDirection() {
        this.scrollDirection = this.scrollDirection === 'vertical' ? 'horizontal' : 'vertical';
        this.tooltipContentList = this.tooltipContentList.filter(item => !item.includes('当前滚动方向'));
        this.tooltipContentList.push(`当前滚动方向: ${this.scrollDirection === 'vertical' ? '垂直' : '水平'}`);
        // 消息提醒
        this.$message({
          message: `当前表格滚动方向已切换为: ${this.scrollDirection ==='vertical'? '垂直' : '水平'}`,
          type: 'info',
          duration: 1000, 
        })
      },

      /**
       * @description 显示边缘视觉反馈
       * @param {HTMLElement} element - 需要添加视觉反馈的元素
       */
      showEdgeFeedback(element) {
        if (!this.isScrollingToEdge) {
          this.isScrollingToEdge = true;
          element.style.transition = 'background-color 0.3s';
          element.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
          
          setTimeout(() => {
            element.style.backgroundColor = '';
            setTimeout(() => {
              element.style.transition = '';
              this.isScrollingToEdge = false;
            }, 300);
          }, 300);
        }
      },

      hasScrollbarByMff() {
        console.log(123);
        
        const tableBody = this.$el.querySelector(".el-table__body-wrapper");
        // 是否有竖向滚动条
        const verticalScrollbarWidth =
          tableBody.scrollHeight - tableBody.clientHeight;
        console.log(tableBody.scrollHeight, tableBody.clientHeight,'1231321321',verticalScrollbarWidth);
        
        // 是否有横向滚动条
        const horizontalScrollbarHeight =
          tableBody.scrollWidth - tableBody.clientWidth;
          console.log(tableBody.scrollWidth, tableBody.clientWidth,'1231321321',horizontalScrollbarHeight);
          
      
        
        // 如果有横向滚动条和竖向滚动条 hiddenMouseWheel 为false时 tooltipVisible 为true
        if (
          verticalScrollbarWidth > 0 &&
          horizontalScrollbarHeight > 0 &&
          !this.hiddenMouseWheel
        ) {
          this.tooltipContentList.push("按住Alt键可以横向滚动表格");
          this.tooltipVisible = true;
          this.$el.addEventListener("dblclick", this.toggleScrollDirection);
          this.tooltipContentList.push('双击表格任意位置可切换滚动方向')
        }else{
          this.tooltipContentList = this.tooltipContentList.filter(item =>!item.includes('按住Alt键可以横向滚动表格'));
          this.tooltipContentList = this.tooltipContentList.filter(item =>!item.includes('双击表格任意位置可切换滚动方向'));
          this.tooltipVisible = false; 
          console.log(1231321);
        }
        
      },
    },
    render(h) {
      const table = this.$options.extends.render.call(this, h);
      return (
        <div
          style={{
            position: "relative",
          }}
        >
          <el-tooltip
            placement="top"
            style={{
              position: "absolute",
              ...(this.tooltipPosition.top && { top: this.tooltipPosition.top }),
              ...(this.tooltipPosition.left && { left: this.tooltipPosition.left }),
              ...(this.tooltipPosition.bottom && { bottom: this.tooltipPosition.bottom }),
              ...(this.tooltipPosition.right && { right: this.tooltipPosition.right }),
              zIndex: 11,
              display: this.tooltipVisible ? "block" : "none",
            }}
          >
            <div slot="content">
              {this.tooltipContentList.map((item, index) => {
                return (
                  <div key={index} style={{ marginBottom: "4px" }}>
                    <span>{index + 1}.</span> {item}
                  </div>
                );
              })}
            </div>
            <i
              class="el-icon-info"
              style={{
                cursor: "pointer",
                display: this.tooltipVisible ? "block" : "none",
              }}
            ></i>
          </el-tooltip>
          {table}
        </div>
      );
    },
  }

使用示例

1. 注册组件

import Vue from "vue";
import { tableMouseHorizontalWheel } from "@/components/EllTable/index";
Vue.component("ell-table", tableMouseHorizontalWheel);

2. 基础用法

<template>
  <div>
    <ell-table :data="tableData" border style="width: 100%" height="400">
      <el-table-column
        prop="date"
        label="日期"
        width="180"
        fixed="left"
      ></el-table-column>
      <el-table-column label="合并列" width="660">
        <el-table-column prop="name" label="姓名" width="180"></el-table-column>
        <el-table-column
          prop="nickname"
          label="昵称"
          width="180"
        ></el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="300"
        ></el-table-column>
      </el-table-column>
      <!-- 更多列配置 -->
    </ell-table>
  </div>
</template>

配置说明

参数说明类型默认值
disableMouseHorizontalWheel是否禁用鼠标横向滚动功能Booleanfalse
hiddenMouseWheel是否隐藏鼠标滚动提示Booleanfalse
showTooltip是否显示提示信息Booleanfalse
tooltipContent提示信息内容String/Array[]
tooltipPosition提示信息位置Object{ top: "10px", left: "10px" }

注意事项

  1. 组件会自动检测表格是否同时存在横向和纵向滚动条,如果存在则显示提示信息
  2. 可以通过disableMouseHorizontalWheel属性禁用鼠标横向滚动功能
  3. 提示信息位置可以通过tooltipPosition属性灵活配置
  4. 双击表格可以切换滚动方向(垂直/水平)
  5. 按住Alt键可以临时启用横向滚动
  6. 组件完全兼容Element UI Table的所有功能,可以正常使用Table组件的所有属性和方法

总结

通过扩展Element UI的Table组件,我们实现了一个更加便捷的表格组件,支持鼠标横向滚动和智能提示功能。这个组件不仅提升了用户体验,还保持了与原有Table组件的完全兼容性。在实际项目中,这个组件可以有效提升表格数据的浏览效率,特别是在处理大量列数据时。