拖拽API入门(记录一次学习)

199 阅读2分钟

拖放事件

​ HTML5新增加了draggle属性,可以允许我们直接对元素进行拖拽的操作。对于被拖拽元素,其触发的事件依次为dragstartdragdragend;当被拖拽元素被放置到一个有效目标时,会依次触发dragenterdragoverdragleave(或者drop)三个事件。

​ 另外,当元素被拖拽时,会有一个透明的副本跟随光标移动

自定义放置目标

​ 把被拖动元素放置到一个有效目标时,dragenterdragoverdragleave(或者drop)三个事件是默认禁用的,必须要阻止默认事件。

<div>
    <!-- 被拖动元素 -->
	<div className="dragBox" draggable="true">
		拖动盒子
	</div>
    <!-- 放置目标 -->
	<div className="dragTarget"></div>
</div>
dragTarget.addEventListener("dragenter", (e) => {
	e.preventDefault();
});
dragTarget.addEventListener("dragover", (e) => {
	e.preventDefault();
});
dragTarget.addEventListener("drop", (e) => {
	e.preventDefault();
});

dataTransfer对象

​ 单纯的拖拽并无异议,dataTransfer对象可以承载被拖拽对象想要传递的数据,核心方法为:setData(key,value)getData(key)

  • 对于被拖拽对象:
dragBox.addEventListener("dragstart", (e) => {
	e.dataTransfer.effectAllowed = "move";
	e.dataTransfer.setData("data", "this is demo text");	// set方法设置传递的键值对
});
  • 对于放置目标:
dragTarget.addEventListener("dragenter", (e) => {
	e.preventDefault();
});
dragTarget.addEventListener("dragover", (e) => {
	e.preventDefault();
});
dragTarget.addEventListener("drop", (e) => {
	e.preventDefault();
	console.log(e.dataTransfer.getData("data"));	// get方法获取key对应的value
});

​ 注意,dataTransfer对象能传递的只有字符串类型的数据

dropEffecteffectAllowed

​ 可以通过dataTransfer对象下的dropEffect属性和effectAllowed属性来约定哪些操作可以实现,哪些操作会被禁用,具体情况如下:

  • 对于被拖动对象:

    //	在dragstart事件发生的时候,设置effectAllowed属性,常用值包括none(禁止任何行为)、link(允许link对应的dropEffect)、move(允许move对应的dropEffect)、copy(允许copy对应的dropEffect)、all(允许任何dropEffect)
    dragBox.addEventListener("dragstart", (e) => {
    	e.dataTransfer.effectAllowed = "link";
    	e.dataTransfer.setData("data", '{ "name": "liao" }');
    });
    
  • 对于目标对象:

    //	在drop事件发生的时候,设置dropEffect属性,常用值包括none(禁止任何行为)、link(被拖动元素移动到放置目标后会跳转链接)、move(应该把被拖动元素移动到放置目标)、copy(应该把被拖动元素放置到放置目标)
    dragTarget.addEventListener("dragenter", (e) => {
        e.preventDefault();
    });
    dragTarget.addEventListener("dragover", (e) => {
        e.preventDefault();
    });
    dragTarget.addEventListener("drop", (e) => {
        e.preventDefault();
        e.dataTransfer.dropEffect = "link";
        dragTarget.appendChild(dragBox);
        console.log(e.dataTransfer.getData("data"));
    });
    

    ​ 设置这两个属性只能更改光标的样式,真正实现操作还需要开发者自己完成

原生js封装拖拽

// 防抖函数,避免拖拽时不间断触发
function dbounce(fn, delay) {
  let timer = null;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn, delay);
  };
}

let dragger1 = document.getElementsByClassName("draggable")[0];
// 拖拽函数
let demo = dbounce(() => {
  console.log("draging!");
}, 1000);
// 封装拖拽函数,可以应用于多个对象
function DragDrop(ev) {
  let dragging = null,
    drager = new EventTarget(),
    diffX = 0,
    diffY = 0;
  function handleEvent(event) {
    //获取事件和目标
    let target = event.target;
    //确定事件类型
    switch (event.type) {
      case "mousedown":
        if (target.className.indexOf("draggable") > -1) {
          dragging = target;
          diffX = event.clientX - target.offsetLeft;
          diffY = event.clientY - target.offsetTop;
          console.log("drag start!");
        }
        break;
      case "mousemove":
        if (dragging !== null) {
          //指定位置
          dragging.style.left = event.clientX - diffX + "px";
          dragging.style.top = event.clientY - diffY + "px";
          demo();
        }
        break;
      case "mouseup":
        console.log("drag end!");
        dragging = null;
        break;
      default:
        break;
    }
  }

  drager.enable = function () {
    ev.addEventListener("mousedown", handleEvent);
    ev.addEventListener("mousemove", handleEvent);
    ev.addEventListener("mouseup", handleEvent);
  };

  drager.disable = function () {
    ev.removeEventListener("mousedown", handleEvent);
    ev.removeEventListener("mousemove", handleEvent);
    ev.removeEventListener("mouseup", handleEvent);
  };

  return drager;
}

let drager1 = DragDrop(dragger1);
drager1.enable();