vue 封装一个鼠标拖动选择时间段功能

news2024/11/17 5:32:03

 

 

<template>
  <div class="timeRange">
    <div class="calendar">
      <table>
        <thead>
          <tr>
            <th rowspan="6" class="weekRow"><b>周/时间</b></th>
            <th colspan="24"><b>00:00 - 12:00</b></th>
            <th colspan="24"><b>12:00 - 24:00</b></th>
          </tr>
          <tr>
            <td colspan="2" v-for="index in 24" :key="index">{{ index - 1 }}</td>
          </tr>
        </thead>
        <tbody @mousemove.prevent="handleMouseMove">
          <tr v-for="(item, index) in weekDate" :key="index">
            <td>{{ item }}</td>
            <td class="calendar-atom-time" v-for="i in 48" :key="index + '-' + i"
                :class="{ 'active': selectCells[`${index}_${i}`] }" @mousedown.prevent="handleMouseDown(index, i, $event)"
                @mouseup.prevent="handleMouseUp(index, i)">
            </td>
          </tr>
          <div id="box" v-show="moveStartEvent"></div>
        </tbody>
      </table>
      <div class="table-core">
        <div class="clearfix">
          <span class="pull-left tip-text">可拖动鼠标选择时间段</span>
          <button class="clearBtn" @click="handleClear">清除所有</button>
        </div>
        <ul>
          <li v-for="(item, index) in selectDate" :key="index" v-if="item.data && item.data.length">
            <label>{{ item.label }}</label>
            <span v-for="o in item.data" :key="o">{{ o[0] }}~{{ o[1] }}</span>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'timeRange',
  data () {
    return {
      // 表列
      weekDate: ['一', '二', '三', '四', '五', '六', '日'],
      // 所选格子
      selectCells: {},
      // 所选时间数据(做提交时使用)
      selectDate: {},
      // 记录鼠标位置
      moveStartEvent: false,
      moveStartColumn: 0, // 列
      moveStarRow: 0, // 行
      moveStartX: 0,
      moveStartY: 0
    }
  },
  created () {

  },
  mounted () {

  },
  methods: {
    // 初始
    init (data) {
      if (data && data instanceof Object) {
        this.selectCells = data
      } else {
        this.selectCells = {}
      }
      this.getSelectDate()
    },

    // 按下
    handleMouseDown (column, row, e) {
      this.moveStartEvent = true
      this.moveStartColumn = column
      this.moveStarRow = row
      this.moveStartX = e.layerX
      this.moveStartY = e.layerY
    },

    // 松开
    handleMouseUp (column, row) {
      if (this.moveStartEvent) {
        this.moveStartEvent = false
        const X = row - this.moveStarRow
        const Y = column - this.moveStartColumn
        const checked = !this.selectCells[`${column}_${row}`]

        if (X > -1 && Y > -1) {
          const obj = this.clone(this.selectCells)
          for (let i = this.moveStartColumn; i <= column; i++) {
            for (let j = this.moveStarRow; j <= row; j++) {
              var key = `${i}_${j}`
              if (checked) {
                obj[key] = checked
              } else if (obj[key]) {
                delete obj[key]
              }
            }
          }

          this.selectCells = obj
          this.$forceUpdate()
          this.getSelectDate()
        }
      }
      this.moveStartDay = 0
      this.moveStarTime = 0
    },

    // 滑动中
    handleMouseMove (e) {
      if (this.moveStartEvent) {
        const dom = this.$el.querySelector('#box')
        const X = e.layerX - this.moveStartX
        const Y = e.layerY - this.moveStartY
        if (X >= 0 && Y >= 0) {
          dom.style.left = this.moveStartX + 'px'
          dom.style.top = this.moveStartY + 'px'
          dom.style.width = X + 'px'
          dom.style.height = Y + 'px'
        }
      }
    },

    // 组合时间数据
    getSelectDate () {
      const arr = []
      this.weekDate.forEach((item, index) => {
        arr.push({
          label: item,
          data: []
        })
        for (var i = 1; i <= 48; i++) {
          var o = this.selectCells[`${index}_${i}`]
          if (o) {
            var endTime = i / 2
            var startTime = endTime - 0.5
            if (startTime < 10) {
              startTime = '0' + startTime
            }
            if (endTime < 10) {
              endTime = '0' + endTime
            }
            startTime += ''
            endTime += ''
            if (startTime.indexOf('.5') > -1) {
              startTime = startTime.replace('.5', ':30')
            } else {
              endTime = endTime.replace('.5', ':30')
            }
            if (startTime.indexOf(':30') < 0) {
              startTime += ':00'
            } else {
              endTime += ':00'
            }
            arr[index].data.push([startTime, endTime])
          }
        }
      })
      arr.forEach(item => {
        for (var i = 0; i < item.data.length; i++) {
          var o = item.data
          if (o[i + 1] && o[i][1] === o[i + 1][0]) {
            o[i + 1][0] = o[i][0]
            item.data.splice(i, 1)
            i--
          }
        }
      })
      this.selectDate = arr
    },

    // 清除选择
    handleClear () {
      this.selectCells = {}
      this.getSelectDate()
      this.$forceUpdate()
    },

    // 获取数据
    getData () {
      return this.selectDate
    }

  }
}
</script>

<style lang="less" scoped>
.timeRange {
  user-select: none;
  position: relative;
  padding: 10px 0;

  .calendar {
    display: inline-block;
  }

  table {
    width: 100%;
    border-radius: 4px;
    border-spacing: 0;
    table-layout: fixed;
    border-collapse: collapse;

    thead {

      th,
      td {
        height: 30px;
      }

      th {
        padding: 5px 0;

      }

      .weekRow {
        width: 100px;
        min-width: 100px;
        padding: 20px 0
      }
    }

    td,
    th {
      outline: 0;
      border: 1px solid #E3E3E3;
      font-size: 12px;
      text-align: center;
      min-width: 11px;
      line-height: 1.6em;
      min-width: 24px;
    }

    tbody {
      position: relative;
      overflow: hidden;

      td {
        height: 20px !important;
      }
    }

    td.active {
      background: #F60457;
    }
  }

  .table-core {
    line-height: 2.4em;
    border: 1px solid #E3E3E3;
    border-top: 0;
    overflow: hidden;
    padding: 10px;

    .clearfix {
      color: #8A8A8A;
      text-align: left;
      height: 22px;
      line-height: 22px;
      margin: 8px 0;
      display: flex;
      font-size: 12px;

      .clearBtn {
        cursor: pointer;
        color: #5775F9;
        font-size: 14px;
        margin-left: auto;
      }
    }

    ul {
      li {
        line-height: 22px;
        margin-bottom: 5px;

        label {
          display: inline-block;
          min-width: 60px;
          color: #8A8A8A;
          text-align: left;
        }

        span {
          font-size: 12px;

          &::after {
            content: "、"
          }

          &:last-child::after {
            display: none;
          }
        }
      }
    }
  }

  #box {
    background: rgba(241, 1, 85, 0.4);
    pointer-events: none;
    position: absolute;
    top: 0;
    left: 0;
  }
}
</style>

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

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

相关文章

docker容器引擎(三)

docker 一、Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器 二、容器互联&#xff08;使用centos镜像&#xff09;三、docker镜像的创建创建镜像的方法DockerfileDocker 镜像结构的分层Dockerfile 操作常用的指令&#xff1a; 四、Dockerfile 案例 一、Docker 的…

Java从入门到精通(一)

Java从入门到精通&#xff08;一&#xff09; 前言 温故而知新&#xff0c;闲着没事干&#xff0c;准备将Java编程语言的知识点从头梳理一遍&#xff0c;整理成笔记&#xff0c;逐篇发布。 部分图片素材来源与B站“黑马程序员”的课程。 一 Java背景 Java是1995年 由Sun公司…

error CS0246: 未能找到类型或命名空间名“Newtonsoft”(是否缺少 using 指令或程序集引用?)

error CS0246: 未能找到类型或命名空间名“Newtonsoft”(是否缺少 using 指令或程序集引用?) 如图&#xff0c;明明已经引用了命名空间&#xff0c;可以点击生成报错。找了很长时间的原因&#xff0c;最后终于解决了问题。 原因是Newtonsoft这个dll文件只支持.net 4.5框架&…

互联网搜索的学习笔记

1. 参考资料 《Internet Search Tips》《Google Search Operators: The Complete List (42 Advanced Operators)》 2. 预备知识 2.1 查询语法 2.1.1 -&#xff1a;排除符 用于排除指定关键字。例如&#xff0c;如果想搜索“苹果”但不想看到“苹果手机”的结果&#xff0c;…

【Spring】IOC的原理

一、 IOC 的概念 Spring 的 IOC &#xff0c;即控制反转&#xff0c;所谓控制反转 —— 本来管理业务对象&#xff08;bean&#xff09;的操作是由我们程序员去做的&#xff0c;但是有了 Spring 核心容器后&#xff0c;这些 Bean 对象的创建和管理交给我们Spring容器去做了&am…

疫苗生产精细困难,有了物联网网关,让生产 更轻松

疫苗生产背景 生产出现的问题 项目工期十分紧张 无法及时获知产线生产进度&#xff0c;不易进行计划调整 无法准确的安排现场生产计划 产品线数量多&#xff0c;纸质记录及流程近10万页 设备采集数量庞大&#xff0c;超过40000点 设备管理不明确、报修维修等无法及时通知…

QPoint、QLine、QSize、QRect

QPoint、QLine、QSize、QRect QPointQLineQSizeQRect QPoint // 构造函数 // 构造一个坐标原点, 即(0, 0) QPoint::QPoint(); // 参数为 x轴坐标, y轴坐标 QPoint::QPoint(int xpos, int ypos);// 设置x轴坐标 void QPoint::setX(int x); // 设置y轴坐标 void QPoint::setY(in…

Linux操作系统~必考面试题⑦

1、vim 命令 Vim是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 打开文件并跳到第 10 行&#xff1a; vim 10 filename.txt 打开文件跳到第一个匹配的行&#xff1a; vim /search-term filenam…

基于传统网络架构训练图像分类模型(上传到colab中进行运算)

一 部署colab环境 部署colab参考网站 相关文件&#xff1a;提取码&#xff1a;o2gn 在google drive中部署以上涉及的相关文件夹 二 对这个项目的解释 这个项目主要是对5类花的图像进行分类 采用迁移学习的方法&#xff0c;迁移学习resnet网络&#xff0c;利用原来的权重作…

stm32f103VET6和stm32f103c8t6有什么区别?

我来终结下这个问题。 这两款单片机我都用过&#xff0c;其中无际单片机特训营其中一款wifi报警主机项目就是用了stm32f103c8t6。 stm32f103VET6和stm32f103c8t6都是STMicroelectronics公司推出基于ARM Cortex-M3内核的单片机。 它们在硬件规格和性能上存在一些差异&#xff…

SpringSecurity认证授权具体流程步骤(具体实例)

本案例是通过使用SpringSecurity来实现通过读取数据库中的数据&#xff0c;来完成认证授权的案例。 1. 向数据库中添加具体实例 创建出五个表&#xff0c;五个表之间的关系为&#xff1a; sys_user&#xff1a;登录表&#xff0c;用于登陆后查询id sys_user_role&#xff1a;…

Flink集群运行模式--Standalone运行模式

Flink集群运行模式--Standalone运行模式 一、实验目的二、实验内容三、实验原理四、实验环境五、实验步骤5.1 部署模式5.1.1 会话模式&#xff08;Session Mode&#xff09;5.1.2 单作业模式&#xff08;Per-Job Mode&#xff09;5.1.3 应用模式&#xff08;Application Mode&a…

三层交换机实现DHCP功能

典型操作&#xff1a;三层交换机VLAN实现网络 可以实现基本的企业需求 华为的三层交换机实现DHCP功能&#xff0c;需要给vlan划分地址池 1.网络拓扑图 2.三层交换机的配置 //三层交换机的配置 //配置IP地址池&#xff0c;实现DHCP时分配给vlan下的终端 [Huawei]ip pool vl…

玩转smardaten | 零基础构建多维数据可视化大屏(最全攻略)

不要再问睿睿&#xff1a;数据可视化大屏怎么做啦&#xff01; 没学过任何编程代码怎么办&#xff0c;能做吗&#xff1f;根本不是问题&#xff01; 这篇文章手把手教你&#xff0c;全方位攻略smardaten数据可视化大屏&#xff08;搭建无需代码&#xff09;~~ 一、可视化大屏…

TSINGSEE青犀视频汇聚融合平台EasyCVR的中性化版本如何配置?

TSINGSEE青犀视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等&#xff0c;平台融合性强、开放度高、部署轻快&#xff0c;在智慧工地、智慧园区…

tcpdump 抓包记录

查看发往 10.0.2.220 的包 [rootbigdata-storage-05 ~]# tcpdump -i any -nn dst 10.0.2.220 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes 16:40:55.0253…

github token使用方法

git remote set-url origin https://<githubtoken>github.com/<username>/<repositoryname>.git 在私有仓库的HTTPS的url上加入<githubtoken>即为token url&#xff0c;可以免ssh key登录

入局元宇宙,所谓的无限可能到底在哪里?

最近的热点新闻表明&#xff0c;人们似乎认为元宇宙已经走向“死亡”。但实际上&#xff0c;市场应该重新定义对元宇宙的看法&#xff0c;以及正视它最大的机会所在——游戏领域。 1937年5月6日&#xff0c;一架名为兴登堡号的巨大氢能齐柏林飞艇飞临新泽西州曼彻斯特镇上空&a…

Dubbo 指定调用固定ip+port dubbo调用指定服务 dubbo调用不随机 dubbo自定义调用服务 dubbo点对点通信 dubbo指定ip

1. 在写分布式im时nami-im: 分布式im, 集群 zookeeper netty kafka nacos rpc主要为gate&#xff08;长连接服务&#xff09; logic &#xff08;业务&#xff09; lsb &#xff08;负载均衡&#xff09;store&#xff08;存储&#xff09; - Gitee.com&#xff0c;需要指定某一…

本地缓存LoadingCache

引入依赖 <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.1-jre</version> </dependency>主要代…