html5 drag 拖放原理

浏览器坐标系

浏览器中大概有以下几个坐标系:

  • screenX, screenY,以显示器(屏幕)为坐标系的坐标
  • clientX, clientY(简写是 x,y),以浏览器窗口(可视区域)为坐标系的坐标
  • pageX, pageY,以文档窗口(可滚动)为坐标系的坐标
  • offsetX, offsetY,以元素为坐标系的坐标
  • layerX, layerY,返回点击的目标对象相对于当前层的坐标

screenX, screenY

clientX, clientY

这两个值是指可视区域,并且从可视区域的左上角开始计算距离。就算页面存在滚动,也不管。那么谁管呢,pageX, pageY 管!如果页面不存在滚动,client 和 page 的值是一样的。如果垂直方向上存在滚动,那么有以下公式:

js 复制代码
pageY = scrollTop + clientY

offsetX, offsetY

如果点击粉色快,则 offsetX, offsetY 是以自己本身左上顶角为原点坐标计算当前值。

layerX, layerY

  • 返回相对点击的元素相对于其父级元素(有定位属性)的坐标
  • 如果点击的元素以及父级元素都没有定位属性,那就返回相对于body标签的坐标
  • 如果点击的元素自身有定位属性返回的就是相对于自身的坐标

拖放与坐标系之间有什么关系呢,因为以前是通过这些坐标系进行模拟拖放的,但是现在 Html5 中已经有了相应的拖放 api 了,变的十分方便了。

drag 事件

问?将大象装进冰箱需要几步?

  • 首先你得有大象和冰箱
  • 再者执行装这个操作

如果我们将此问题类比与拖放事件,那么拖放事件也得经过两个步骤:

  • 大象------被拖放的元素,将想要拖放的元素的 draggable 设为 truedraggable="true"。这样才能将元素进行拖放。另外 imga 标签默认允许拖放。
  • 冰箱------目标元素并执行装这个操作------编写拖放有关的代码。

执行装这个操作可以细分为:

  • 大象开始拖放
  • 大象拖放中
  • 大象开始进入冰箱
  • 大象完全进入冰箱,还翻了个身
  • 大象从冰箱出来了
  • 大象被放进了冰箱
  • 关门

那么用拖放有关的 api 描述则为:

  • 大象开始拖放------dragstart
  • 大象拖放中------drag
  • 大象开始进入冰箱------dragenter
  • 大象完全进入冰箱,还翻了个身------dragover
  • 大象从冰箱出来了------dragleave
  • 大象被放进了冰箱------drop
  • 关门------dragend

那么动作的发生一定和主体有关,那么这些 api 的主体就不是一样的。

我们将大象称为 drag 元素,冰箱称为 drop 元素

  • drag 元素------dragstart------开始拖放操作
  • drag 元素------drag------拖放过程中
  • drop 元素------dragenter------被拖放的元素进入目标元素范围(更精确的是鼠标进入)
  • drop 元素------dragover------被拖放的元素在目标元素内移动
  • drop 元素------dragleave------被拖放的元素离开目标元素范围
  • drop 元素------drop------被拖放的元素放在目标元素范围
  • drag 元素------dragend------拖放操作结束

案例

代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>drag</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-boxss;
        }

        .link {
            display: block;
            margin: 20px auto;
            width: 40px;
            height: 20px;
            text-align: center;
            color: #fff;
            background-color: pink;
        }
        .box {
            margin: 20px auto;
            width: 100px;
            height: 100px;
            border: 1px solid;
        }
        .text {
            text-align: center;
            font-size: 30px;
        }
    </style>
    <body>
        <a class="link" href="https://juejin.cn/" draggable="true">掘金</a>

        <div class="box"></div>
    </body>

    <script>
        let source = document.querySelector('.link')

        let target = document.querySelector('.box')

        source.addEventListener('dragstart', event => {
            event.dataTransfer.setData('text/plain', event.target.className)
        })

        target.addEventListener('dragover', event => {
            // 浏览器默认是不允许拖放,要阻止默认事件
            event.preventDefault()
        })

        target.addEventListener('drop', event => {
            // 阻止默认事件
            event.preventDefault()
            const className = event.dataTransfer.getData('text/plain')
            target.appendChild(document.querySelector(`.${className}`))
        })
    </script>
</html>

整体思路就是:

  • dragstart 时,保存一些数据到 dataTransfer,使用的是 setData
  • drop 时,获取保存的数据,得到元素,插入到目标元素中。

这里面出现了一些新的属性:

  • dataTransfer:对象用于保存拖动并放下过程中的数据,它可以保存一项或多项数据,这些数据项可以是一种或者多种数据类型
  • dataTransfer.setData(format, data) 方法用来设置拖放操作的数据和类型。设置的类型 format要与保存时 getData 一致,不然取不到值的。

要特别注意的是:

  • 浏览器默认不允许拖放,因此在目标元素上要在 dragover 时,阻止这一特性,只能在这个周期。

dataTransfer.dropEffect,dataTransfer.effectAllowed

  • dropEffect:属性控制在拖放操作中给用户的反馈(copy、move、link、none)。项目可能禁止拖放
  • effectAllowed:属性指定拖放操作所允许的一个效果

这两个属性如果要设置的话,需要注意一下,可能会导致无法拖放。 设置为 none 时,也无法拖放。

dataTransfer 更详细的信息

相关推荐
undefined&&懒洋洋13 分钟前
Web和UE5像素流送、通信教程
前端·ue5
大前端爱好者2 小时前
React 19 新特性详解
前端
随云6322 小时前
WebGL编程指南之着色器语言GLSL ES(入门GLSL ES这篇就够了)
前端·webgl
随云6322 小时前
WebGL编程指南之进入三维世界
前端·webgl
寻找09之夏3 小时前
【Vue3实战】:用导航守卫拦截未保存的编辑,提升用户体验
前端·vue.js
多多米10054 小时前
初学Vue(2)
前端·javascript·vue.js
柏箱4 小时前
PHP基本语法总结
开发语言·前端·html·php
新缸中之脑4 小时前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz8564 小时前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习4 小时前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript