Touch & Drag 事件
Touch 事件
TouchEvent 是一类描述手指在触摸平面(如触摸屏、触摸板等)的状态变化的事件。TouchList 对象代表多个触点的一个列表。每个 Touch 对象代表一个触点,每个触点都由其位置、大小、形状、压力大小和目标 element 描述。
触摸事件类型
主要有以下几种:
- touchstart - 当用户在触摸平面上放置了一个触点时触发
- touchmove - 当用户在触摸平面上移动触点时触发
- touchend - 当一个触点被用户从触摸平面上移除时触发
- touchcancel - 当触点由于某些原因被中断时触发,如由于某个事件取消了触摸或触点个数超过了设备支持的个数
document.addEventListener('touchstart', touchEvent ,false);
TouchList
每个触摸事件被触发后,会生成一个 event 对象,event 对象里额外包括以下三个触摸列表:
- touches - 包含了所有当前接触触摸平面的触点的 Touch 对象
- targetTouches - 是包含了如下触点的 Touch 对象:触摸起始于当前事件的目标 element 上,并且仍然没有离开触摸平面的触点
- changedTouches - 包含了代表所有从上一次触摸事件到此次事件过程中,状态发生了改变的触点的 Touch 对象
Touch
这些列表里的每次触摸由 Touch 对象组成,Touch 对象里包含着触摸信息,主要属性如下:
{
screenX: 511,
screenY: 400, // 触点相对于屏幕左边沿的Y坐标
clientX: 244.37899780273438,
clientY: 189.3820037841797, // 相对于可视区域
pageX: 244.37,
pageY: 189.37, // 相对于 HTML 文档顶部,当页面有滚动的时候与 clientX=Y 不等
force: 1, // 压力大小,是从0.0(没有压力)到1.0(最大压力)的浮点数
identifier: 1036403715, // 一次触摸动作的唯一标识符
radiusX: 37.565673828125, // 能够包围用户和触摸平面的接触面的最小椭圆的水平轴(X轴)半径
radiusY: 37.565673828125,
rotationAngle: 0, // 它是这样一个角度值:由 radiusX 和 radiusY 描述的正方向的椭圆,需要通过顺时针旋转这个角度值,才能最精确地覆盖住用户和触摸平面的接触面
target: {} // 此次触摸事件的目标 element
}
查看以下 JSFiddle 示例:
Touch 案例
做一个移动端触摸点,仅限于屏幕窗口内移动,也可响应点击事件:
var doc = document;
var screenW = doc.body.clientWidth || screen.width;
var screenH = doc.body.clientHeight || screen.height;
var width = 48;
var isMoved = false;
var backToTop = doc.querySelector('.back-to-top');
backToTop.addEventListener('touchstart', touchstart, false);
backToTop.addEventListener('touchmove', touchmove, false);
backToTop.addEventListener('touchend', touchend, false);
function touchstart(ev) {
isMoved = false;
}
function touchmove(ev) {
isMoved = true;
var event = getEvent(ev);
var coordinateX = event.changedTouches[0].clientX;
var coordinateY = event.changedTouches[0].clientY;
var left = parseFloat(coordinateX) - 20;
var top = parseFloat(coordinateY) - 20;
left = left <= 1.45 ? 1.45 : (left >= screenW - width ? screenW - width : left);
top = top <= 1 ? 1 : (top >= screenH - width ? screenH - width : top);
backToTop.style.left = left + 'px';
backToTop.style.top = top + 'px';
console.log('left: %f, top: %f', left, top);
}
function touchend(ev) {
!isMoved && alert('click');
}
function getEvent(ev) {
return ev ? ev : window.event;
}
Drag 事件
DragEvent 鼠标进行拖拽(drag)和释放(drop),一定要设置可拖拽目标,即设置属性 draggable="true"
。
拖拽事件类型
- 被拖动的源对象可以触发的事件:
- dragstart - 源对象开始被拖动
- drag - 源对象被拖动过程中(鼠标可能在移动也可能未移动)
- dragend - 源对象被拖动结束
- 拖动源对象到目标对象可以触发的事件:
- dragenter - 源对象拖动进入目标对象时触发
- dragover - 源对象拖动经过目标对象时触发
- dragleave - 源对象拖动离开目标对象时触发
- drop - 源对象放置于目标对象上时触发
DataTransfer
拖拽事件周期中会初始化一个 DataTransfer 对象,用于保存拖拽数据和交互信息:
- dropEffect - 拖拽交互类型,通常决定浏览器如何显示鼠标光标并控制拖放操作.常见的取值有 copy、move、link、none
- effectAllowed - 指定允许的交互类型,可以取值: copy、move、link、copyLink、copyMove、limkMove、all、none,默认为 uninitialized(允许所有操作)
- files - 包含 File 对象的 FileList 对象,一般用于从本地向浏览器拖放文件.
- types - 保存 DataTransfer 对象中设置的所有数据类型.
- setData(format, data) - 以键值对设置数据,format 通常为数据格式,如 text、text/html
- getData(format) - 获取设置的对应格式数据,format 与 setData()中一致
- clearData(format) - 清除指定格式的数据
- setDragImage(imgElement, x, y) - 设置自定义图标
draggableElement.addEventListener('dragstart', function (event) {
event.dataTransfer.setData('text', 'Hello World');
}, false);
draggableElement.ondragstart = function(event) {
event.dataTransfer.setData('text', 'Hello World');
}
Drag 案例
做一个 web 端触摸点,仅限于屏幕窗口内移动:
var doc = document;
var screenW = doc.body.clientWidth || screen.width;
var screenH = doc.body.clientHeight || screen.height;
var width = 48;
var offsetX = 0;
var offsetY = 0;
var backToTop = doc.querySelector('.back-to-top');
backToTop.addEventListener('dragstart', ondragstart, false);
backToTop.addEventListener('drag', ondrag, false);
backToTop.addEventListener('dragend', ondragend, false);
function ondragstart(ev) {
var event = getEvent(ev);
offsetX = event.offsetX;
offsetY = event.offsetY;
}
function ondrag(ev) {
var event = getEvent(ev);
var coordinateX = event.clientX;
var coordinateY = event.clientY;
if (coordinateX === 0 && coordinateY === 0) {
return; // 不处理拖动最后一刻X和Y都为0的情形
}
coordinateX -= offsetX;
coordinateY -= offsetY;
coordinateX = coordinateX <= 0 ? 0 : (coordinateX >= screenW - width ? screenW - width : coordinateX);
coordinateY = coordinateY <= 0 ? 0 : (coordinateY >= screenH - width ? screenH - width : coordinateY);
backToTop.style.left = coordinateX + 'px';
backToTop.style.top = coordinateY + 'px';
console.log('left: %f, top: %f', coordinateX, coordinateY);
}
function ondragend(ev) {
console.log('drag end');
}
做一个垃圾回收示例 JSFiddle:
拖拽图片预览 JSFiddle:
事件对象的位置
- pageX = clientX + ScrollLeft(滚动条水平滚动距离)
- pageY = clientY + ScrollTop(滚动条垂直滚动距离)
参考链接
- MDN - TouchEvent
- 移动端 Touch 事件介绍 By kujian
- js 中的 touch 事件及 gesture(手势)事件详解 — 第13.4.9节 By flyingpig2016
- 原生拖拽,拖放事件(drag and drop) By qiu_deqing
- HTML5 – 拖拽 API(含超经典例子) By 冯小东
- 一张图轻松搞懂 javascript event 对象的 clientX、offsetX、screenX、pageX 区别 By ruoyiqing