vue2+a-table——实现框选选中功能——js技能提升

实现的功能:单个点击勾选数据,用户觉得太麻烦,所以希望可以出一个框选的功能,来实现框住的行都自动勾选。

效果图如上所示:

下面直接上代码:

解决步骤1:给table添加指定id------id="containerId"

解决步骤2:给指定列添加一个固定的className,并绑定id

比如上图中,我并没有每一列都支持框选选中,只有【编号】一列是有效的,所以只要框选的内容包含【编号】一列,则就可以实现功能

js 复制代码
<template #code="{ record }">
  <div class="item" :data-id="record.id">{{ record.code }}</div>
</template>

解决步骤3:在页面mounted函数中添加以下代码:

js 复制代码
this.areaSelector = new AreaSelector({
  element: document.getElementById('containerId'),
  selectableTargetSelector: '.item',
  datasetKeyForSelection: 'id',
  onSelectChange: (arr) => {
    let currentSelectArr = arr.filter(
      (item) => this.selectedKeys.indexOf(item) === -1
    );
    this.selectedKeys = this.selectedKeys.concat(currentSelectArr);//表格选中的数据id集合
    this.$refs.combinedOrderTable.selectedKeys = this.selectedKeys;//给table表格回显选中
  },
});

解决步骤4:写一个类函数------AreaSelector

在项目中新建一个名为dragSelect.js的文件,内容如下:

js 复制代码
export class AreaSelector {
  constructor({
    element,
    selectableTargetSelector,
    datasetKeyForSelection,
    onSelectChange,
  }) {
    this.element = element;
    this.selectableTargetSelector = selectableTargetSelector;
    this.datasetKeyForSelection = datasetKeyForSelection;
    this.onSelectChange = onSelectChange;
    this.selectedIds = [];
    this.#createSelectArea();
    this.#handleMouseDown();
    this.#handleMouseUp();
  }
  #area;
  #startPoint;
  #endPoint;
  #mouseMoveHandler;
  #twoRectsHaveIntersection = (rect1, rect2) => {
    const left1 = rect1.left;
    const left2 = rect2.left;
    const right1 = rect1.left + rect1.width;
    const right2 = rect2.left + rect2.width;
    const top1 = rect1.top;
    const top2 = rect2.top;
    const bottom1 = rect1.top + rect1.height;
    const bottom2 = rect2.top + rect2.height;
    const width1 = rect1.width;
    const width2 = rect2.width;
    const height1 = rect1.height;
    const height2 = rect2.height;
    const noIntersection =
      left2 > right1 ||
      left1 > right2 ||
      bottom1 < top2 ||
      bottom2 < top1 ||
      width1 <= 0 ||
      width2 <= 0 ||
      height1 <= 0 ||
      height2 <= 0;
    return !noIntersection;
  };
  #createSelectArea = () => {
    const area = document.createElement('div');
    this.element.style.position = 'relative';
    area.style.position = 'absolute';
    area.style.zIndex = 15;
    area.style.border = '1px solid #ccc';
    area.style.background = 'rgba(0,119,255,.2)';
    this.element.appendChild(area);
    this.#area = area;
  };
  #selecItems = () => {
    const areaRect = this.#area.getBoundingClientRect();
    const items = document.querySelectorAll(this.selectableTargetSelector);
    let selectionChanged;
    for (const item of items) {
      const itemRect = item.getBoundingClientRect();
      const hasIntersection = this.#twoRectsHaveIntersection(
        areaRect,
        itemRect
      );
      const selected = hasIntersection ? true : false;
      item.dataset.selected = selected;
      const itemId = item.dataset[this.datasetKeyForSelection];
      const index = this.selectedIds.indexOf(itemId);
      if (selected) {
        if (index === -1) {
          this.selectedIds.push(itemId);
          selectionChanged = true;
        }
      } else {
        if (index !== -1) {
          this.selectedIds.splice(index, 1);
          selectionChanged = true;
        }
      }
    }
    if (selectionChanged) {
      this.onSelectChange(this.selectedIds);
    }
  };
  #updateArea = () => {
    const top = Math.min(this.#startPoint.y, this.#endPoint.y);
    const left = Math.min(this.#startPoint.x, this.#endPoint.x);
    const width = Math.abs(this.#startPoint.x - this.#endPoint.x);
    const height = Math.abs(this.#startPoint.y - this.#endPoint.y);
    this.#area.style.top = `${top}px`;
    this.#area.style.left = `${left}px`;
    this.#area.style.width = `${width}px`;
    this.#area.style.height = `${height}px`;
    this.#selecItems();
  };
  #hideArea = () => {
    this.#area.style.display = 'none';
    this.element.style.userSelect = 'all';
  };
  #showArea = () => {
    this.#area.style.display = 'block';
    this.element.style.userSelect = 'none';
  };
  #getRelativePositionInElement = (clientX, clientY) => {
    const { left, top } = this.element.getBoundingClientRect();
    const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = this.element;
    let x = clientX - left + scrollLeft;
    let y = clientY - top + scrollTop;
    if (x < 0) {
      x = 0;
    } else if (x > scrollWidth) {
      x = scrollWidth;
    }
    if (y < 0) {
      y = 0;
    } else if (y > scrollHeight) {
      y = scrollHeight;
    }
    return { x, y };
  };
  #handleMouseDown = () => {
    this.element.addEventListener('mousedown', (e) => {
      if (e.target.nodeName == 'A') {
        window.open(e.target.href, '_blank');
        return;
      }
      const { clientX, clientY } = e;
      this.#startPoint = this.#getRelativePositionInElement(clientX, clientY);
      this.#endPoint = this.#startPoint;
      this.#updateArea();
      this.#showArea();
      this.#handleMouseMove();
    });
  };
  #handleMouseMove = () => {
    this.#mouseMoveHandler = (e) => {
      const { clientX, clientY } = e;
      this.#endPoint = this.#getRelativePositionInElement(clientX, clientY);
      this.#updateArea();
      this.#scrollOnDrag(clientX, clientY);
    };
    window.addEventListener('mousemove', this.#mouseMoveHandler);
  };
  #handleMouseUp = () => {
    window.addEventListener('mouseup', (e) => {
      window.removeEventListener('mousemove', this.#mouseMoveHandler);
      this.#hideArea();
    });
  };
  #scrollOnDrag = (mouseX, mouseY) => {
    const { x, y, width, height } = this.element.getBoundingClientRect();
    let scrollX, scrollY;
    if (mouseX < x) {
      scrollX = mouseX - x;
    } else if (mouseX > x + width) {
      scrollX = mouseX - (x + width);
    }
    if (mouseY < y) {
      scrollY = mouseY - y;
    } else if (mouseY > y + height) {
      scrollY = mouseY - (y + height);
    }
    if (scrollX || scrollY) {
      this.element.scrollBy({
        left: scrollX,
        top: scrollY,
        behavior: 'auto',
      });
    }
  };
}
相关推荐
南东山人3 分钟前
一文说清C++类型转换操作符(cast operator)
开发语言·c++
JavaPub-rodert6 分钟前
Windows系统下载、安装和配置Python环境变量 --- 《跟着小王学Python》
开发语言·windows·python
Asa1213811 分钟前
R绘制像素风图片
开发语言·r语言
Black蜡笔小新14 分钟前
无插件H5播放器EasyPlayer.js网页web无插件播放器选择全屏时,视频区域并没有全屏问题的解决方案
前端·javascript·音视频
ooyyaa656125 分钟前
sslSocketFactory not supported on JDK 9+
java·开发语言
Augenstern、29 分钟前
vue3 element el-table实现表格动态增加/删除/编辑表格行,带有校验规则
前端·javascript·vue.js
沐泽Mu41 分钟前
嵌入式学习-C嘎嘎-Day04
c语言·开发语言·c++·学习
A黄俊辉A43 分钟前
electron安装遇到的问题
前端·javascript·electron
lvbb6643 分钟前
ES6更新的内容中什么是proxy
前端·ecmascript·es6
痕忆丶1 小时前
鸿蒙北向开发 : hdmfs-分布式文件系统
前端