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',
      });
    }
  };
}
相关推荐
球球和皮皮36 分钟前
Babylon.js学习之路《四、Babylon.js 中的相机(Camera)与视角控制》
javascript·3d·前端框架·babylon.js
一只努力学习的Cat.1 小时前
C++:二叉搜索树
开发语言·c++
<但凡.1 小时前
C++修炼:多态
开发语言·c++·算法
我爱写代码?1 小时前
Spark 集群配置、启动与监控指南
大数据·开发语言·jvm·spark·mapreduce
买了一束花1 小时前
数据预处理之数据平滑处理详解
开发语言·人工智能·算法·matlab
秭霏鱼2 小时前
Python+大模型 day01
开发语言·python
破晓的历程2 小时前
Qt之Qfile类
开发语言·qt
郭尘帅6662 小时前
vue3基础学习(上) [简单标签] (vscode)
前端·vue.js·学习
纸包鱼最好吃2 小时前
java基础-package关键字、MVC、import关键字
java·开发语言·mvc
njsgcs2 小时前
opencascade.js stp vite webpack 调试笔记
开发语言·前端·javascript