当前位置: 首页 > article >正文

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

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

效果图如上所示:

下面直接上代码:

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

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

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

<template #code="{ record }">
  <div class="item" :data-id="record.id">{{ record.code }}</div>
</template>

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

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的文件,内容如下:

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',
      });
    }
  };
}


http://www.kler.cn/a/401661.html

相关文章:

  • 14. 乘法口诀挑战赛
  • https(day30)
  • 【东莞石碣】戴尔R740服务器维修raid硬盘问题
  • 小试牛刀-Anchor安装和基础测试
  • ([LeetCode仓颉解题报告] 661. 图片平滑器
  • fpga 同步fifo
  • 探索PyMuPDF:Python中的强大PDF处理库
  • 结构体位段+联合和枚举
  • Object.prototype.hasOwnProperty.call(item, key) 作用与用途
  • 2.5D视觉——Aruco码定位检测
  • 前端软件开发质量管控之应用质量 - 关于E2E测试的对象目的及不同方案特性对比(一)
  • ifuse不能挂载App Store下载的包ERROR: InstallationLookupFailed
  • 有关django、python版本、sqlite3版本冲突问题
  • Brave127编译指南 Linux篇-环境配置(五)
  • Python+7z.exe实现自动化压缩与解压
  • 【代码随想录|回溯算法排列问题】
  • 微信小程序-prettier 格式化
  • java实现贪心算法
  • SAM-Med2D 训练完成后boxes_prompt没有生成mask的问题
  • 首次实现!在Docker容器中运行macOS项目,自动化下载与Web体验
  • 高效整合:汤臣倍健营销云数据集成到金蝶云星辰V2解析
  • 鸿蒙NEXT开发案例:计数器
  • SIMCom芯讯通A7680C在线升级:FTP升级成功;http升级腾讯云对象储存的文件失败;http升级私有服务器的文件成功
  • K8s 概念知识梳理
  • 如何修复苹果手机上的绿屏 - 快速简便的解决方案
  • .NET 9 的新增功能