vuex2实现时间列表选择器

news2024/11/24 0:53:40

目录

一、效果展示

二、代码分析

2.1、区域确定与坐标获取

2.2、单个点击与一次性点击

一、效果展示

 

  主要借助自定义指令实现。在表格的"td们"上面进行移动框选,有一次性框选和单个框选,去掉自定义指令里的clearTargetNodes()会连续td,连续框选后会获取对应的值,可以再进行组装。

二、代码分析

<template>
  <div>
    <table border="1" v-cellSelect="weekdayTimeData">
      <tr>
        <th rowspan="2">星期 / 时间</th>
        <th colspan="12">00:00 - 12:00</th>
        <th colspan="12">12:00 - 24:00</th>
      </tr>
      <tr>
        <th v-for="n in 24" :key="n">{{ n - 1 }}</th>
      </tr>
      <tr v-for="n in 7" :key="n" :data-weekday="n - 1">
        <th class="weekday-title">{{ weekdayTitle[n - 1] }}</th>
        <td v-for="m in 24" :key="m" :data-time="m - 1"></td>
      </tr>
    </table>
  </div>
</template>
<script>
export default {
  directives: {
    cellSelect: {
      bind(el, bindings) {
        el.addEventListener("mousedown", handleMouseDown, false);
        function handleMouseDown(e) {
          const tar = e.target;
          const tagName = tar.tagName.toLowerCase();
          const els = this;
          clearTargetNodes(els); //防止单个点击时"td"们连在一起。不加该函数,点击的"td"们会连在一起
          if (tagName === "td") {
            els.start = tar;
            const rowIndex = Number(els.start.parentNode.dataset.weekday);
            const columnIndex = Number(els.start.dataset.time);
            // ===========拿到移动开始时的最终坐标
            setWeekdayTimeData(els, rowIndex, columnIndex);
            addTargetNode(els, tar); //情况一:单个点击移动框选
            els.addEventListener("mousemove", handleMouseMove, false);
            els.addEventListener("mouseup", handleMouseUp, false);
          }
        }
        function handleMouseMove(e) {
          const tar = e.target;
          const tagName = tar.tagName.toLowerCase();
          const els = this;
          if (tagName === "td") {
            const startTarget = els.start;
            const endTarget = tar;
            const startRow = Number(startTarget.parentNode.dataset.weekday);
            const startColumn = Number(startTarget.dataset.time);
            const endRow = Number(endTarget.parentNode.dataset.weekday);
            const endColumn = Number(endTarget.dataset.time);
            // ===========拿到移动停止时的最终坐标
            const currentTargetNodes = getTargetNodes(
              els,
              startRow,
              startColumn,
              endRow,
              endColumn
            );
            // ============拿到起始到结束的所有td数组
            getTargetNodeDiff(els, els.targetNodes, currentTargetNodes);
          }
        }
        function getTargetNodes(els, startRow, startColumn, endRow, endColumn) {
          const { allRows } = els;
          const startR = startRow > endRow ? endRow : startRow;
          const startC = startColumn > endColumn ? endColumn : startColumn;
          const endR = startRow > endRow ? startRow : endRow;
          const endC = startColumn > endColumn ? startColumn : endColumn;
          const targetNodes = new Set(); //防止来回移动,造成冗余数据
          allRows.forEach((tr, rowIndex) => {
            if (rowIndex >= startR && rowIndex <= endR) {
              [...tr.querySelectorAll("td")].forEach((td, columnIndex) => {
                if (columnIndex >= startC && columnIndex <= endC) {
                  targetNodes.add(td);
                  setWeekdayTimeData(els, rowIndex, columnIndex);
                }
              });
            }
          });
          return targetNodes;
        }
        function getAllRows(el) {
          const oAllRows = el.querySelectorAll("tr"); //[tr, tr, tr, tr, tr, tr, tr, tr, tr]
          return [...oAllRows].reduce((prev, tr) => {
            if (tr.dataset.weekday) {
              prev.push(tr);
            }
            return prev;
          }, []);
        }
        function handleMouseUp() {
          const els = this;
          els.removeEventListener("mousemove", handleMouseMove, false);
          els.removeEventListener("mouseup", handleMouseUp, false);
        }
        el.allRows = getAllRows(el); //[tr, tr, tr, tr, tr, tr, tr],原本有9个,只取出带":data-weekday"的tr
        el.targetNodes = new Set();
        el.weekdayTimeData = bindings.value;
        //情况二:"一气呵成"点击移动框选
        function getTargetNodeDiff(els, targetNodes, currentTargetNodes) {
          // currentTargetNodes里面有,而targetNodes没有,就要增加
          currentTargetNodes.forEach((td) => {
            !targetNodes.has(td) && addTargetNode(els, td);
          });
          // targetNodes里面有,而currentTargetNodes没有,就要减少
          targetNodes.forEach((td) => {
            !currentTargetNodes.has(td) && removeTargetNode(els, td);
          });
        }
        function addTargetNode(el, target) {
          //框选完继续扩大面积
          el.targetNodes.add(target);
          target.classList.add("target");
        }
        function removeTargetNode(el, target) {
          //框选完缩小了面积
          el.targetNodes.delete(target);
          target.classList.remove("target");
        }
        function clearTargetNodes(el) {
          el.targetNodes.forEach((target) => {
            target.classList.remove("target");
          });
          el.targetNodes = new Set();
          el.weekdayTimeData = [];
        }
        function setWeekdayTimeData(el, weekday, time) {
          console.log(weekday, time, "el, weekday, time", el.weekdayTimeData);
          //结果:  [ {3: {0, 1, 2, 3}},{4:{0, 1, 2, 3}}]
          //参考: {0:[0,1,2,3]}===>星期一:00:00,01:00,02:00,03:00
          el.weekdayTimeData[weekday]
            ? el.weekdayTimeData[weekday].add(time)
            : (el.weekdayTimeData[weekday] = new Set([time]));
        }
      },
    },
  },
  data() {
    return {
      weekdayTimeData: [],
      weekdayTitle: [
        "星期一",
        "星期二",
        "星期三",
        "星期四",
        "星期五",
        "星期六",
        "星期日",
      ],
    };
  },
};
</script>
<style lang='less' scoped>
table {
  border-collapse: collapse;
  .weekday-title {
    width: 100px;
  }
  tr {
    height: 50px;
  }
  td {
    width: 50px;
    &.target {
      background-color: aqua;
    }
  }
}
</style>

2.1、区域确定与坐标获取

(1)给表格绑定自定义指令拿到它本身,按下时取到所有的td(框选总面积),见handleMouseDown()函数。

(2)防止单个点击时"td"们连在一起。不加该函数,点击的"td"们会连在一起,见clearTargetNodes()函数

(3)拿到移动开始时的最终坐标:rowIndex、columnIndex;

    拿到移动停止时的最终坐标:startRow、startColumn、endRow、endColumn

(4)拿到起始到结束的所有td数组,见getTargetNodes()函数,防止来回移动,造成冗余数据,原本有9个,只取出带":data-weekday"的tr

2.2、单个点击与一次性点击

情况一:单个点击移动框选

在handleMouseDown时,直接调用addTargetNode()函数

情况二:"一气呵成"点击移动框选

getTargetNodeDiff这个比较函数,就是要比较在原有框选区域上要扩大/缩小:

currentTargetNodes里面有,而targetNodes没有,就要增加==》框选完继续扩大面积addTargetNode()

targetNodes里面有,而currentTargetNodes没有,就要减少==》框选完缩小了面积removeTargetNode()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/703258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hudi学习5:Hudi的helloworld-编译源码

hudi是使用java代码编写的 部署hudi 1. 下载源码 Download | Apache Hudi https://dlcdn.apache.org/hudi/0.13.1/hudi-0.13.1.src.tgz 2.编译 安装maven 首先要先有JDK java8以上 配置镜像源 执行编译 测试

Yolov5小目标性能提升方案介绍

目录 1.小目标检测介绍 1.1 小目标定义 1.2 难点 2.小目标难点解决方案 2.1注意力提升小目标检测精度 2.1.1 上下文信息CAM 2.1.2 ConvNeXt 2.1.3 ECVBlock 2.1.4 多头上下文集成&#xff08;Context Aggregation&#xff09;的广义构建模块 2.2 多头检测头 2.3 loss优化…

spring 在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

spring 在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

Go语言net模块TCP和UDP编程实践

任何一种语言TCP和UDP网络编程总是必须的&#xff0c;接下来就将go语言中使用net标准库进行TCP和UDP编程进行梳理总结。 目录 1.代码结构 2.TCP通信 3.UDP通信 4.TCP模拟HTTP协议通信 5.利用TCP扫描那些端口被占用 1.代码结构 2.TCP通信 server.go package mainimport …

【正点原子STM32连载】 第四十八章 内存管理实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第四…

全志V3S嵌入式驱动开发(spi-nand image制作)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 上一篇文章,我们说到了spi-nor image的制作和输入。相比较spi-nor,spi-nand虽然在稳定性上面差一点,但是价格上面有很大的优势。举例来说,一般32M的spi-nor大约在6-7元左右,但…

Springboot链接Redis实现AOP防止重复提交

目录 安装redis Springboot链接Redis 1.创建springboot项目 如果spring boot启动报Error creating bean with name redisUtil/redisTemplate 2.新建application.yml配置 3.redis配置类-直接用 4.redis工具类-直接用 5.写Controller测试 6.启动、测试 整合AOP&#xff…

内网横线移动—WmiSmbCrackMapExecProxyChainsImpacket

内网横线移动—Wmi&Smb&CrackMapExec&ProxyChains&Impacket 1. 前置环境准备2. wmic介绍2.1. wmic操作演示2.1.1. 受控主机上线2.1.1.1. 内网存活探测2.1.1.2. 密码抓取 2.1.2. 横向移动2.1.2.1. 上传文件2.1.2.2. 文件上传目标主机2.1.2.3. 执行木马 2.2. wmi…

JAVA 安全-JWT 安全及预编译 CASE 注入等(40)

在各种语言脚本的环境下&#xff0c;也会产生一些新的漏洞&#xff0c;如果是java又能产生那些漏洞&#xff0c;思维导图里面常规漏洞之前都有&#xff1b; java的访问控制&#xff0c;jwt令牌&#xff08;php几乎没有&#xff09;组件安全&#xff0c;这些都是java特有的 #综…

C#核心知识回顾——3.继承构造、拆装箱、多态

1.继承中的构造函数&#xff1a; 特点&#xff1a; 当申明一个子类对象时 先执行父类的构造函数&#xff0c;再执行子类的构造函数注意&#xff01;&#xff01;&#xff1a; 1.父类的无参构造很重要 2.子类可以通过base关键字代表父类调用父类构造 public class Mot…

【单片机】STM32单片机,定时器的输入捕获,基于捕获的频率计,STM32F103

文章目录 简单介绍外部计数频率计TIM5 频率计 简单介绍 下面的定时器都具有输入捕获能力&#xff1a; 外部计数频率计 查看另一篇文章&#xff1a;https://qq742971636.blog.csdn.net/article/details/131471539 外部计数频率计的缺点&#xff1a;需要两个定时器配合&#x…

控制 显示、隐藏

1、使用 v-if < v-if"isShow"></> data(){ return:{ isShow:false } } if (concepts && concepts.length >0){ this.isShow nv.concepts.includes(snap) } 确认 数组中有某个 字段&#xff0c;用includes 有&…

Qt QGraphics导入背景图并绘制图形,画布移动、缩放、图形旋转等

前言 之前写过一篇博文《Qt鼠标拖动绘制基本几何图形》 &#xff0c;这是介绍使用QGraphic中利用鼠标事件实现基本几何图形的绘制&#xff0c;支持直线、矩形、圆形、椭圆&#xff0c;本次是在此基础上进行扩展&#xff0c;实现背景图导入&#xff0c;并在图片上进行几何图形绘…

现货白银行情实时行情与展望

现货白银作为低门槛、高收益的贵金属投资工具&#xff0c;因为交易时间自且没有涨跌幅限制而大受全球投资者追捧&#xff0c;它每天的实时行情走势中充满机会&#xff0c;投资者可结合技术和基本面分析手段&#xff0c;预测其未来的价格走势&#xff0c;在市场的波动中把握住获…

Go编写流量代理工具

目录 这是一个演示主要分为俩包&#xff1a;流程&#xff1a;逻辑&#xff1a;(端口随意&#xff0c;本地ssh为例)用法&#xff1a;文件地址&#xff1a;代码如下&#xff1a; 这是一个演示 代理本地HTTP服务 代理局域网SSH服务 其他的TCP服务没测试了 主要分为俩包&#x…

什么是DevOps? 什么是DORA?

1. 前言 对于搞云原生应用的同学&#xff0c;对于DevOps和DORA应该都不陌生。但对于传统应用程序开发的同学&#xff0c;经常被DevOps, Microservice, CICD, DORA这些新颖的名词搞得晕头转向。那么到底什么是DevOps? 什么是DORA呢&#xff1f; 2. 解析 2.1 DevOps DevOps并…

群晖NAS搭建WebDV服务手机ES文件浏览器远程访问

文章目录 1. 安装启用WebDAV2. 安装cpolar3. 配置公网访问地址4. 公网测试连接5. 固定连接公网地址 转载自cpolar极点云文章&#xff1a;群晖NAS搭建WebDAV服务手机ES文件浏览器远程访问 有时候我们想通过移动设备访问群晖NAS 中的文件,以满足特殊需求,我们在群辉中开启WebDav服…

支持刷机(OpenWrt)的路由器大全

2023年上半年最热门的刷机路由器当然是360T7、小米WR30U这两款&#xff0c;主要是性价比高&#xff0c;闲鱼100多搞定&#xff0c;支持刷OpenWrt、支持WiFi6&#xff0c;采用MTK798X系列处理器&#xff0c;性能强&#xff0c;轻松跑满千兆&#xff0c;如果你想追新&#xff0c;…

SpringMVC基础知识

一、SpringMVC 1. Spring与Web环境集成 1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的&#xff0c;但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件…

云捷|打破应用孤岛加速企业数字化转型

CBG云服务BU X 神州数码云基地 一、引言 从流程信息化到整体的数字化转型&#xff0c;对企业而言是一场深刻的升级再造。企业在决心开启数字化转型之路后&#xff0c;有近5成民营企业数字化转型采用标准化工具&#xff1b;关于“贵公司未来将在工作中增加哪些数字应用的使用…