首页 前端知识 element el-table实现可进行横向拖拽滚动

element el-table实现可进行横向拖拽滚动

2024-06-19 23:06:53 前端知识 前端哥 417 588 我要收藏

【问题】表格横向太长,表格横向滚动条位于最底部,需将页面滚动至最底部才可左右拖动表格,用户体验感不好

【需求】基于elment的el-table组件生成的表格,使其可以横向拖拽滚动

【实现】灵感来源于这篇文章【Vue】表格可拖拽滚动,作者已给出原理,感兴趣的可以去了解

实现效果

我用的的录制gif软件,鼠标没有变成抓取手势,实际是可以的

如果没有选中文字的需求,可以在mousemove监听中的 if 判断里加上 e.preventDefault();这样拖动时就会很流畅,不受到选中文字影响。

阻止选中文字效果

找到el-table元素对应的目标元素(VUE3+Element-Plus)

首先给el-table添加ref,并获取元素

<template>
  <el-table :data="tableData" ref="tableRef"></el-table>
</template>
<script lang="ts" setup>
const tableRef = ref(null);
console.log(tableRef);
</script>

我们要找的是包裹table的第一父元素, .el-scrollbar__wrap类名盒子就是我们要找的目标元素

这里解释一下为什么.el-scrollbar__wrap是父盒子:

我们可以看到.el-scrollbar__view盒子里包裹的是table标签,那么.el-scrollbar__view盒子的宽度就是整个表格的宽度,.el-scrollbar__wrap盒子的宽度又是其父元素的宽度,那么 .el-scrollbar__wrap就是.el-scrollbar__view的父盒子,.el-scrollbar__view子盒子宽度有溢出,.el-scrollbar__wrap父盒子则出现滚动条,使得table可以横向滚动

因此我们要找的目标元素就是 .el-scrollbar__wrap

<template>
  <el-table :data="tableData" ref="tableRef"></el-table>
</template>
<script lang="ts" setup>
const tableRef = ref(null);
//获取目标元素
console.log(tableRef.value.$refs.scrollBarRef.wrapRef);
</script>

实现拖拽横向滚动 (通过改变目标元素的scrollLeft值)

需要捕获鼠标事件及拖拽事件并更改目标元素的scrollLeft值则可实现横向滚动

涉及到的事件包括:mousedown,mouseup,mousemove, mouseleave, dragstart,给表格元素添加相应的事件

mousedown

鼠标按下事件,即鼠标按下但未释放的动作

1.可拖拽状态改为允许拖拽。2.记录鼠标位置。3.鼠标样式改为小手。

tableDataRef.value.$el.addEventListener('mousedown', (e: MouseEvent) => {
  // 拿到目标元素
  tableBody = tableDataRef.value.$refs.scrollBarRef.wrapRef;
  // 拖拽状态改为允许拖拽/鼠标样式修改公共方法
  setMouseFlag(true, tableBody);
  // 记录鼠标按下位置
  mouseStart = e.clientX;
  // 记录元素当前scrollLeft值
  startX = tableBody.scrollLeft;
  // 添加 dragstart 事件监听器
  document.addEventListener('dragstart', handleDragStart);
});

mousemove 

鼠标移动事件,即鼠标在元素内移动的动作

1.判断是否可拖拽。2.允许拖拽时记录鼠标移动距离。3.修改目标元素scrollLeft值。

tableDataRef.value.$el.addEventListener('mousemove', (e: MouseEvent) => {
  if (mouseFlag) {
    let offset = e.clientX - mouseStart;
    (tableBody as HTMLElement).scrollLeft = startX - offset;
  }
});

mouseup

鼠标释放事件,即鼠标按下后释放的动作

1.可拖拽状态改为禁止拖拽。2.鼠标样式恢复。

tableDataRef.value.$el.addEventListener('mouseup', () => {
  // console.log('鼠标左键松开++++++++++++');
  setMouseFlag(false, tableBody);
  // 移除 dragstart 事件监听器
  document.removeEventListener('dragstart', handleDragStart);
});

检测到禁止光标手势

监听拖动时,判断是否出现禁止小手标识

如果你选中文字然后点击拖拽时在浏览器中鼠标光标就会变成红色禁止符号

const handleDragStart = (e: DragEvent) => {
  // console.log('禁止光标手势出现');
  // 取消默认的拖动效果
  e.preventDefault();
  setMouseFlag(false, tableBody);
};

 拖拽状态改为允许拖拽/鼠标样式修改公共方法

const setMouseFlag = (flag: boolean, tableBody?: HTMLElement | null) => {
  mouseFlag = flag;
  if (tableBody) {
    tableBody.style.cursor = flag ? 'grab' : 'auto';
  }
};

封装成统一函数dragTable,并将其定义为全局变量

/src/utils/common.ts

//设置el-table可进行鼠标左键按下左右拖动
interface TableDataRef {
  value: {
    $el: HTMLElement;
    $refs: {
      scrollBarRef: {
        wrapRef: HTMLElement;
      };
    };
  };
}

export const dragTable = (tableDataRef: TableDataRef) => {
  let mouseFlag = false,
    mouseStart = 0,
    startX = 0,
    tableBody: HTMLElement | null = null;

  //鼠标按下事件,即鼠标按下但未释放的动作。
  tableDataRef.value.$el.addEventListener('mousedown', (e: MouseEvent) => {
    tableBody = tableDataRef.value.$refs.scrollBarRef.wrapRef;
    setMouseFlag(true, tableBody);
    // mouseFlag = true;
    mouseStart = e.clientX;
    startX = tableBody.scrollLeft;
    // tableBody.style.cursor = 'grab';
    // 添加 dragstart 事件监听器
    document.addEventListener('dragstart', handleDragStart);
  });
  //鼠标释放事件,即鼠标按下后释放的动作。
  tableDataRef.value.$el.addEventListener('mouseup', () => {
    // console.log('鼠标左键松开++++++++++++');
/*     mouseFlag = false;
    (tableBody as HTMLElement).style.cursor = 'auto'; */
    setMouseFlag(false, tableBody);
    // 移除 dragstart 事件监听器
    document.removeEventListener('dragstart', handleDragStart);
  });
  //鼠标移动事件,即鼠标在元素内移动的动作。
  tableDataRef.value.$el.addEventListener('mousemove', (e: MouseEvent) => {
    if (mouseFlag) {
      let offset = e.clientX - mouseStart;
      (tableBody as HTMLElement).scrollLeft = startX - offset;
    }
  });
  //鼠标离开事件,即鼠标移动到元素外触发这个事件。
  tableDataRef.value.$el.addEventListener('mouseleave', (e: MouseEvent) => {
    handleDragStart((e as any))
  });
  // 检测到禁止光标手势
  const handleDragStart = (e: DragEvent) => {
    // console.log('禁止光标手势出现');
    // 取消默认的拖动效果
    e.preventDefault();
    setMouseFlag(false, tableBody);
  };

  const setMouseFlag = (flag: boolean, tableBody?: HTMLElement | null) => {
    mouseFlag = flag;
    if (tableBody) {
      tableBody.style.cursor = flag ? 'grab' : 'auto';
    }
  };
};

 main.ts

import { dragTable } from '@/utils/common';
const app = createApp(App);
// 全局方法挂载
app.config.globalProperties.$dragTable = dragTable;

使用全局变量

<template>
  <el-table :data="tableData" ref="tableRef"></el-table>
</template>
<script lang="ts" setup>
import { ComponentInternalInstance, ref } from 'vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const tableRef = ref(null);
nextTick(() => {
  proxy?.$dragTable(tableRef)
})
</script>

补充(VUE2 + Element)

可参考这篇文章利用 bodyWrapper 实现表格拖动

el-table 中获取 bodyWrapper 的方法

注意:可能存在Element版本差异,建议下面的获取方式都试试

之前获取 bodyWrapper 方法是 

this.$refs.myTable.bodyWrapper

 现在上面这种方法获取不到了,要更改为

this.$refs.myTable.$elTable.bodyWrapper
或
this.$refs.myTable.$refs.table.bodyWrapper
console.log(this.$refs.mytable)

总结 

元素可滚动的前提条件是元素的宽度或高度超出给定区域,且开启了滚动条
拖拽需结合mousedown,mousemove,mouseup,mouseleave,dragstart事件实现
竖向滚动同理,修改ScrollTop值即可

转载请注明出处或者链接地址:https://www.qianduange.cn//article/12871.html
标签
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!