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

 

 

<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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue中的数据代理

vue数据代理 Vue实现数据代理的核心----Object.defineProperty(); 数据代理 数据代理的定义是&#xff1a;一个对象操作(读\写)另一个对象中的属性和方法。 // 数据代理&#xff1a;通过一个对象代理对另一个对象中属性的操作&#xff08;读/写&#xff09;let obj { x: 100…

vue element ui web端引入百度地图,并获取经纬度

最近接到一个新需要&#xff0c;要求如下&#xff1a; 当我点击选择地址时&#xff0c;弹出百度地图&#xff0c; 效果如下图&#xff1a; 实现方法&#xff1a; 1、首先要在百度地图开放平台去申请一个账号和key 2、申请好之后&#xff0c;在项目的index.html中引入 3、…

Error: Please select Android SDK解决方案(仅供参考)

一、问题描述 今天开始正式接触项目的工作内容&#xff0c;然后从组里的代码仓库里git clone了一份Android Studio项目下来。下好了以后我使用Android Studio打开这个项目&#xff0c;但在尝试编译运行的时候遇到了很多错误。例如&#xff0c;开发环境界面上边用于编译的小锤子…

五,Eureka 第五章

5.3.2 修改pom添加依赖 <dependencies><!--公共部门--><dependency><groupId>cn.bdqn</groupId><artifactId>springcloud-api-commons</artifactId><version>${project.version}</version></dependency><!--e…

Python电商爬虫保姆级入门教程(纯新手向)

图灵Python课堂 长沙图灵教育于2001年开始进入教育行业&#xff0c;立足泛IT类职业教育&#xff0c;以打造高新技术人才为宗旨&#xff0c;专注于提供多层次、个性化的职业技能培训课程&#xff0c;为各行业培养技术开发、应用和管理等岗位的中高端人才&#xff0c;致力于成为…

Python学习笔记-Django框架基础,APP,数据模型,后台管理,路由

一、Django框架简介 Django框架是Python的常用web框架&#xff0c;遵循 MVC 设计模式的框架&#xff0c;采用了MTV的框架模式&#xff0c;即模型M&#xff0c;视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的&#xff0c;即是CMS&…

双虚拟机实现数据库自动备份

FTP的使用&#xff1a; 1.安装FTP 1、检测系统有没有安装ftp&#xff0c;执行命令&#xff1a; rpm -qa | grep ftp若存在用rpm命令移除后再行安装&#xff0c;执行命令&#xff1a; rpm -e vsftpd-3.0.2-9.e17.x86_642、如果没有安装&#xff0c;则在线安装ftp&#xff0c…

Vue2基础八、插槽

零、文章目录 Vue2基础八、插槽 1、插槽 &#xff08;1&#xff09;默认插槽 作用&#xff1a;让组件内部的一些 结构 支持 自定义需求: 将需要多次显示的对话框, 封装成一个组件问题&#xff1a;组件的内容部分&#xff0c;不希望写死&#xff0c;希望能使用的时候自定义。…

关于anki的一些思考

文章目录 通常情况下选择什么模板制卡&#xff1f;一张填空卡片的填空数量到底要多少才合适&#xff1f; 通常情况下选择什么模板制卡&#xff1f; 通常情况是指知识是以一段文字的形式呈现&#xff0c;而不是这些&#xff1a;单词、选择题、成语等&#xff08;这些都可以定制…

openlayers根据下拉框选项在地图上显示图标

这里是关于一个根据下拉框的选项在地图上显示图标的需求&#xff0c;用的是vueopenlayers 显示效果大概是这样&#xff1a; 选中选项之后会跳转到所点击的城市&#xff0c;并且在地图上显示图标温度&#xff0c;这一块UI没设计我就大概先弄了一下&#xff0c;比较丑。。 首先…

【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动 在【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值一文中介绍了如何利用…

Java使用FFmpeg实现mp4转m3u8

Java使用FFmpeg实现mp4转m3u8 前言FFmpegM3U8 一、需求及思路分析二、安装FFmpeg1.windows下安装FFmpeg2.linux下安装FFmpegUbuntuCentOS 三、代码实现1.引入依赖2.修改配置文件3.工具类4.Controlle调用5.Url转换MultipartFile的工具类 四、播放测试1.html2.nginx配置3.效果展示…

uniapp实现带参数二维码

view <view class"canvas"><!-- 二维码插件 width height设置宽高 --><canvas canvas-id"qrcode" :style"{width: ${qrcodeSize}px, height: ${qrcodeSize}px}" /></view> script import uQRCode from /utils/uqrcod…

LeetCode.189(轮转数组)

对于轮转数组这个题&#xff0c;文章一共提供三种思路&#xff0c;对于每种思路均提供其对应代码的时间、空间复杂度。 目录 1. 创建变量来保存最后一个数&#xff0c;并将其余数组向前挪动一位 &#xff1a; 1.1 原理解析&#xff1a; 1.2 代码实现&#xff1a; 2.创建一个…

Ftp和UDP的区别之如何加速文件传输

FTP&#xff08;文件传输协议&#xff09;是一种传输大文件的老方法&#xff0c;它的速度慢&#xff0c;而且容易受到网络环境的影响。在当今这个文件越来越大&#xff0c;项目交付时间越来越紧&#xff0c;工作分布在全球各地的时代&#xff0c;有没有办法让 FTP 加速呢&#…

重学C++系列之const与static关键字分析

前言 本篇幅讲解关键字const与static&#xff0c;主要围绕在类的范围内叙述&#xff0c;包括作用和使用场景等。 一、const与static的作用 1、const修饰的成员变量&#xff0c;成员变量初始化后不能再修改。 2、const修饰的成员函数&#xff0c;成员函数不可以修改成员变量&am…

数值线性代数:知识框架

记录数值线性代数研究的知识框架。 软件包线性方程组直接法Guass消元法/LU分解、Cholesky分解 LAPACK oneAPI MKL ARPACK Octave 迭代法Jacobi迭代、SOR迭代、共轭梯度法最小二乘特征值/特征向量非对称幂法、QR、Arnoldi分解对称QR、Jacobi、二分法、分治法、SVD 参考资料 G…

PDF添加水印以及防止被删除、防止编辑与打印

方法记录如下&#xff1a; 1、添加水印&#xff1b; 2、打印输出成一个新的pdf&#xff1b; 3、将pdf页面输出成一张张的图片&#xff1a;&#xff08;福昕pdf操作步骤如下&#xff09; 4、将图片组装成一个新的pdf&#xff1a;&#xff08;福昕pdf操作步骤如下&#xff09;…

多线程面试题--使用场景

线程池使用场景&#xff08;CountDownLatch、Future&#xff09; 在使用的时候&#xff0c;首先会给一个初始值&#xff0c;比如图中是3&#xff0c;然后在其他线程中调用countdown&#xff08;&#xff09;方法&#xff0c;当count0则继续执行 多线程使用场景一&#xff08; e…

【Spring Boot】Web开发 — 数据验证

Web开发 — 数据验证 对于应用系统而言&#xff0c;任何客户端传入的数据都不是绝对安全有效的&#xff0c;这就要求我们在服务端接收到数据时也对数据的有效性进行验证&#xff0c;以确保传入的数据安全正确。接下来介绍Spring Boot是如何实现数据验证的。 1.Hibernate Vali…