JavaScript拖动元素在一个范围内移动

news2024/11/22 16:42:25
  • 基于 jQuery
  • 移动范围由 div 搭建(div 模仿表格),卡片的移动不允许超出该范围
  • 移动卡片会有一个淡蓝色卡片的标记出将要放置的位置
  • 有禁止放置标记的位置,不允许卡片放置(会放到前一个可放置的位置)
  • 卡片放置会覆盖单元格中的文字
  • 卡片上的文字会跟随卡片的移动而改变
  • 点击单元格,卡片会移动到该单元格

在这里插入图片描述

  • css 代码

    .week-table {
      width: 660px;
      position: relative;
    }
    
    .week-table .thead-tr,
    .week-table .tbody-tr {
      display: flex;
    }
    
    .week-table .thead-tr div,
    .week-table .tbody-tr div {
      text-align: center;
      flex: 0 0 87px;
      height: 25px;
      border-right: 1px solid #ddd;
      border-top: 1px #ddd dashed;
      line-height: 25px;
      user-select: none;
      position: relative;
    }
    
    .week-table .thead-tr div:last-child,
    .week-table .tbody-tr div:last-child {
      border-right: unset;
    }
    
    .week-table .thead-tr div:first-child,
    .week-table .tbody-tr div:first-child {
      border-left: 1px #ddd dashed;
      flex: 0 0 50px;
    }
    
    .week-table .thead-tr div:last-child,
    .week-table .tbody-tr div:last-child {
      border-right: 1px #ddd dashed;
    }
    
    .week-table .tbody-tr:last-child {
      border-bottom: 1px #ddd dashed;
    }
    
    .week-table .tr div:first-child {
      border-left: 1px #ddd dashed;
    }
    
    .week-table .thead-tr div {
      font-weight: bold;
      background-color: #f5f7fa;
    }
    
    .week-table .tbody-tr div:first-child {
      color: #fff;
    }
    
    .week-table .tbody-tr:nth-child(-n + 6) div:first-child {
      background-color: #3071a9;
    }
    
    .week-table .tbody-tr:nth-child(n + 7) div:first-child {
      background-color: #45b6b0;
    }
    
    .week-table .tbody-tr:nth-child(n + 11) div:first-child {
      background-color: #65c3df;
    }
    
    .week-table .tbody-tr .forbid {
      color: red;
      user-select: none;
      cursor: not-allowed;
    }
    
    .week-table .tbody-tr .card {
      background-color: #3071a9 !important;
      color: #333 !important;
      position: absolute;
      left: 1px;
      top: 1px;
      z-index: 2;
      user-select: none;
      border-radius: 4px;
    }
    
    .week-table .tbody-tr .highlight {
      background-color: #65c3df;
    }
    
  • HTML 代码

      <div class="week-table">
          <div class="thead-tr">
            <div></div>
            <div>星期一</div>
            <div>星期二</div>
            <div>星期三</div>
            <div>星期四</div>
            <div>星期五</div>
            <div>星期六</div>
            <div>星期日</div>
          </div>
          <div class="tbody-tr">
            <div>1</div>
            <div></div>
            <div>
              <span>文字</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div>
              <div class="card" data-x="3" data-y="0" style="height: 72px; width: 84px">星期四 1~3格</div>
            </div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>2</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>3</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>4</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>5</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>6</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>7</div>
            <div><span>文字</span></div>
            <div></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>8</div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>9</div>
            <div><span>文字</span></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>10</div>
            <div><span>文字</span></div>
            <div></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>11</div>
            <div><span>文字</span></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>12</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
        </div>
    
  • JavaScript 代码

    //----------- 点击移动卡片 ------------------
    var $card = $('.week-table .card')
    var $weekTable = $('.week-table')
    var cardVerticalNumber = 3
    var xNumber = 7
    var yNumber = 12
    positionCard($card, $weekTable, cardVerticalNumber, xNumber, yNumber)
    
    function positionCard($card, $weekTable, cardVerticalNumber, xNumber, yNumber) {
      //--------  拖动卡片 --------
      var data = {}
      var tdHeight = 26 // 每一个 div 的高度
      var tdWidth = 88 // 每一个 div 的宽度
      var xNumber = xNumber // X 轴div数量,不含序列
      var yNumber = yNumber // Y轴div数量,不含星期列
      var xMoveMini = Math.floor(tdWidth / 4) // x轴最小移动距离,才开始计算方向
      var yMoveMini = Math.floor(tdHeight / 2) // y轴最小移动距离,才开始计算方向
      var cardHeight = $card.height()
      var cardWidth = $card.width()
      var cardVerticalNumber = cardVerticalNumber // 卡片占据的td数量
      var topLimit = 0 //顶部最大移动距离
      var bottomLimit = yNumber * tdHeight - cardHeight // 底部最大移动距离
      var leftLimit = 0 // 左边最大移动距离
      var rightLimit = xNumber * tdWidth - cardWidth // 右边最大移动距离
      var weekNameZh = ['一', '二', '三', '四', '五', '六', '日']
      $weekTable
        .find('.tbody-tr>div:not(:first-child)')
        .not('[data-forbid="true"]') // 要不要都行,isPutHere 也做了处理
        .on('click', function () {
          var $this = $(this)
          var xIndex = $this.index() - 1
          var yIndex = $this.parent().index() - 1
          var isPut = isPutHere(xIndex, yIndex)
          if (!isPut) return true
          data.newIndexX = xIndex
          data.newIndexY = yIndex
          moveCard(xIndex, yIndex, $this)
        })
    
      $card.mousedown(function (e) {
        var $this = $(this)
        var moveFlag = false // 防止别的事件触发
        data.oldIndexX = Number($this.attr('data-x'))
        data.oldIndexY = Number($this.attr('data-y'))
        data.left = e.pageX
        data.top = e.pageY
        data.sPositionX = data.oldIndexX * tdWidth
        data.sPositionY = data.oldIndexY * tdHeight
        var tempNewLeft = data.left // 上次移动时的位置信息,用于判断移动方向
        var tempNewTop = data.top // 上次移动时的位置信息,用于判断移动方向
        $(document).mousemove(function (e) {
          moveFlag = true
          data.newLeft = e.pageX
          data.newTop = e.pageY
          data.x = data.newLeft - data.left
          data.y = data.newTop - data.top
          data.newPositionX = data.sPositionX + data.x
          data.newPositionY = data.sPositionY + data.y
          var xMove = data.newLeft - tempNewLeft
          var yMove = data.newTop - tempNewTop
    
          // 元素没移动
          if (Math.abs(xMove) === 0 && Math.abs(yMove) === 0) return true
    
          if (data.newPositionX > rightLimit) {
            data.newPositionX = rightLimit
          }
    
          if (data.newPositionX < leftLimit) {
            data.newPositionX = leftLimit
          }
    
          if (data.newPositionY < topLimit) {
            data.newPositionY = topLimit
          }
    
          if (data.newPositionY > bottomLimit) {
            data.newPositionY = bottomLimit
          }
    
          // 当前移动,不超过一定距离不代表要移动
          if (Math.abs(xMove) > xMoveMini) {
            data.newIndexX = Math.ceil(data.x / tdWidth) + data.oldIndexX - 1
    
            // X index 的取值范围
            data.newIndexX = data.newIndexX <= 0 ? 0 : data.newIndexX
            data.newIndexX = data.newIndexX >= xNumber - 1 ? xNumber - 1 : data.newIndexX
          } else {
            data.newIndexX = data.oldIndexX
          }
    
          if (Math.abs(yMove) > yMoveMini) {
            data.newIndexY = Math.ceil(data.y / tdHeight) + data.oldIndexY - 1
    
            // Y index 的取值范围
            data.newIndexY = data.newIndexY <= 0 ? 0 : data.newIndexY
            data.newIndexY = data.newIndexY >= yNumber - cardVerticalNumber ? yNumber - cardVerticalNumber : data.newIndexY
          } else {
            data.newIndexY = data.oldIndexY
          }
    
          // 移动时,给将要移动到的地方一个高亮
          setHighlight(false, data.newIndexX, data.newIndexY)
    
          $card.css({
            left: data.newPositionX - data.sPositionX + 'px',
            top: data.newPositionY - data.sPositionY + 'px'
          })
        })
    
        $(document).mouseup(function (e) {
          if (!moveFlag) return
          moveFlag = false
          $(document).off('mousemove')
          tempNewLeft = data.newLeft
          tempNewTop = data.newTop
    
          setHighlight(true, data.newIndexX, data.newIndexY)
          $card.css({
            top: '1px',
            left: '1px'
          })
    
          // 不允许放置,放到上一个可用的位置
          if (isPutHere(data.newIndexX, data.newIndexY)) {
            moveCard(data.newIndexX, data.newIndexY)
          } else {
            moveCard(data.tempIndexX, data.tempIndexY)
          }
        })
      })
    
      function moveCard(x, y, $target) {
        setCardIndex(x, y)
        setCardInfo(x, y)
        var $parent = $target ? $target : getParent(x, y)
        $parent.append($card)
      }
    
      // 判断是否当前位置是否可放置
      function isPutHere(newX, newY) {
        var isPut = true
        // 当前 Y 轴 加上卡片高度超出Y 轴则直接返回 false
        if (newY + cardVerticalNumber > yNumber) return false
        for (var i = 0; i < cardVerticalNumber; i++) {
          var $parent = getParent(newX, newY + i)
          // 不允许放置的位置,高亮上一个可用的位置
          if ($parent.length <= 0 || isTdForbid($parent)) {
            isPut = false
          }
        }
    
        return isPut
      }
    
      function setHighlight(isRemoveClass, newX, newY) {
        $weekTable.find('.tbody-tr div').removeClass('highlight')
    
        var isPut = isPutHere(newX, newY)
        if (isPut) {
          // 存储上一个可用的位置
          data.tempIndexX = newX
          data.tempIndexY = newY
        }
    
        if (!isRemoveClass) {
          // 判断当前位置是否有禁用的 td
          for (var i = 0; i < cardVerticalNumber; i++) {
            if (isPut) {
              $parent = getParent(newX, newY + i)
            } else {
              $parent = getParent(data.tempIndexX, data.tempIndexY + i)
            }
            $parent.addClass('highlight')
          }
        }
      }
    
      function getParent(x, y) {
        return $weekTable
          .find('.tbody-tr')
          .eq(y)
          .find('>div')
          .eq(x + 1)
      }
    
      function isTdForbid($el) {
        return $el.attr('data-forbid')
      }
    
      function setCardIndex(x, y) {
        $card.attr('data-x', x)
        $card.attr('data-y', y)
      }
    
      function setCardInfo(x, y) {
        var dayName = weekNameZh[x]
        $card.text(`星期${dayName} ${y + 1}~${y + cardVerticalNumber}`)
      }
    }
    

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

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

相关文章

TSS半导体放电管八大属性总结

​之前在写关于GDT放电管与TSS放电管之间的差异时&#xff0c;其实有谈到TSS&#xff08;固体放电管&#xff09;它拥有的一些特性&#xff0c;今天优恩小编还是想重复一下&#xff0c;希望更多小伙伴能够记住。 TSS&#xff0c;有人叫它固体放电管、也有人叫它半导体放电管&am…

智能交通车路协同系统的应用场景和发展趋势

随着城市化进程的加速和汽车保有量的增加&#xff0c;城市交通拥堵、交通事故等问题日益突出。为了解决这些问题&#xff0c;智能交通车路协同系统应运而生。智能交通车路协同系统是一种基于车载终端、路侧设备和交通管理中心等多个组成部分构成的智能交通系统&#xff0c;可以…

io之netty

写在前面 netty当前是网络io框架的事实标准&#xff0c;基于nio实现&#xff0c;框架的作者是韩国一位姓李的朋友&#xff0c;开始我们这位行李的韩国朋友开发一个io框架mina&#xff0c;但后来其离职&#xff0c;mina也就和其没有关系了&#xff0c;所以后来其改进了mina的不…

Maxcompute数据上云一致性比对

我写过很多如何去对数、如何批量对数的技术文档&#xff0c;最近项目遇到这个问题&#xff0c;我才发现在官方博客上还没有发布过这个课题的文章。这就像灯下黑&#xff0c;太长用到的知识点&#xff0c;反而没有意识到其重要性。 注&#xff1a;这里对数的场景就是指在阿里云…

docker 装机/卸载 Mysql

1、首先&#xff0c;需要安装Docker。可以使用以下命令安装&#xff1a; > yum install docker 2、安装完成后&#xff0c;启动Docker服务&#xff1a; > systemctl start docker3、CentOS7环境下的Docker使用 docker快速部署mysql数据库并初始化 docker快速部署mysq…

Power BI API调用注意事项 (By Power Automate)

注&#xff1a;本文最初发布于https://d-bi.gitee.io和medium, 2023年6月迁移至CSDN 前述 本站关于实现Power BI REST API的博文已有许多&#xff0c;包括&#xff1a; Power BI REST API有多强大&#xff1f;PBI开发者必读Power BI REST API实战教程&#xff1a;PowerQuery为…

基于SSM的便利店系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 基于SSH的便利店系统是…

Java中方法的重载与重写

文章目录 前言方法重载方法重写 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 方法的重载与重写容易混&#xff0c;所以单独拿出来比较 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 方法重载 在同一个类中&#xff0c;允…

springcloud-alibaba (06)RocketMQ控制台安装与启动

RocketMQ控制台 ✨让你的消息传输更高效✨ 如果你是一名开发者&#xff0c;或者是对消息传输有需求的企业用户&#xff0c;那么你肯定不陌生于 RocketMQ&#xff0c;它是一个高可用、高可靠、高性能、分布式消息中间件。但是有时候&#xff0c;在 Windows 上安装和启动 Rocke…

生产环境可用的 Seata-go 1.2.0 来啦!!!

文&#xff5c;刘月财&#xff08;GitHub ID&#xff1a;luky116) 360 服务端开发专家 Seata-go 项目负责人 本文 2752 字 阅读 7 分钟 发布概览 Seata-go 1.2.0 版本支持 XA 模式。XA 协议是由 X/Open 组织提出的分布式事务处理规范&#xff0c;其优点是对业务代码无侵入。当前…

小巧长续航的主动降噪耳机,更轻更好用,QCY ArcBuds上手

我平时听歌、玩游戏的时候喜欢戴上一副蓝牙耳机&#xff0c;这种耳机选择很多&#xff0c;这几年进步还很快&#xff0c;市面上有很多价格合理、音质出色的选择。我目前用的是一款QCY ArcBuds&#xff0c;这款耳机支持主动降噪&#xff0c;户外使用体验不错&#xff0c;而且它做…

Dockerfile实现LNMP

systemctl stop firewalld systemctl disable firewalld setenforce 0 docker network create --subnet172.18.0.0/16 --opt "com.docker.network.bridge.name""docker1" mynetwork #部署nginx&#xff08;容器IP 为 172.18.0.10&#xff09; mkdir /o…

一文讲解 基于C++手写Rpc项目

目录 github 预备知识 集群和分布式 单机聊天服务器 集群聊天服务器 分布式聊天服务器 从集群式 到 分布式聊天服务器 看来只有好处 ,但代价是什么? rpc 的 通信原理 remote procedure call 分布式通信 手写的rpc部分 protobuf>json 好处? 介绍protobuf protob…

RabbitMQ - 死信队列

RabbitMQ - 死信队列 死信的概念死信的来源死信实战死信之TTl死信之最大长度死信之消息被拒 死信的概念 先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理 解&#xff0c;一般来说&#xff0c;producer …

【进程间通信:管道】

目录 1 进程间通信介绍 1.1 进程间通信目的 1.2 进程间通信发展 1.3 进程间通信分类 2 管道 2.1 什么是管道 2.2 匿名管道 2.2.1 匿名管道的使用 2.2.2 使用匿名管道创建进程池 2.3 管道读写规则 2.4 匿名管道特点 2.5 命名管道 2.5.1 概念 2.5.2 使用 1 进程间通…

Learning C++ No.28 【C++11语法实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/5/9:25&#xff0c;今天8点45分起床&#xff0c;一种怎么都睡不够的感觉&#xff0c;特别是周末&#xff0c;但是如果按照我以前的睡觉时间来看&#xff0c;妥妥的是多睡了好久好久&#xff0c;并且昨天也睡了一天&#xff0c;哈…

C#,码海拾贝(32)——计算“实对称三对角阵的全部特征值与特征向量的”之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 矩阵类 /// 作者&#xff1a;周长发 /// 改进&#xff1a;深度混淆 /// https://blog.csdn.net/beijinghorn /// </summary> public partial class Matrix {…

第⑩讲:Ceph集群CephFS文件存储核心概念及部署使用

文章目录 1.CephFS文件存储核心概念1.1.CephFS文件存储简介1.2.CephFS文件存储架构1.3.CephFS文件系统的应用场景与特性 2.在Ceph集群中部署MDS组件3.在Ceph集群中创建一个CephFS文件存储系统3.1.为CephFS文件存储系统创建Pool资源池3.2.创建CephFS文件系统3.3.再次观察Ceph集群…

chatgpt赋能python:从后到前查找Python字符串

从后到前查找Python字符串 Python是一种流行的编程语言&#xff0c;广泛用于Web开发、数据科学和算法设计等领域。其中&#xff0c;字符串是Python编程中的重要概念之一&#xff0c;它不仅可以表示文本&#xff0c;还可以进行各种处理。本篇文章将介绍Python字符串从后到前的查…

chatgpt赋能python:Python如何运行最方便

Python 如何运行最方便 Python 是一种高级编程语言&#xff0c;被广泛使用于各类领域。由于其简单易学&#xff0c;可读性高&#xff0c;适用于不同平台的特性&#xff0c;Python 已成为计算领域、Web 开发、数据分析等领域的首选语言之一。如果您正在学习 Python 或需要对其进…