crossvent:封装跨平台事件绑定的库
跨平台的触摸事件
利用crossvent封装绑定跨平台拖拽事件的方法touchy,以便支持移动端和pc端
根据环境获取的触摸事件名,用懒加载的方式替换掉touchy函数,之后绑定事件不需要再判断
import { add as addEvent } from 'crossvent';
let touchy = function (el, type, fn) {
const touch = {
mouseup: 'touchend',
mousedown: 'touchstart',
mousemove: 'touchmove'
};
const pointers = {
mouseup: 'pointerup',
mousedown: 'pointerdown',
mousemove: 'pointermove'
};
const microsoft = {
mouseup: 'MSPointerUp',
mousedown: 'MSPointerDown',
mousemove: 'MSPointerMove'
};
if (window.navigator.pointerEnabled) {
touchy = function (el, type, fn) {
addEvent(el, pointers[type], fn);
};
} else if (window.navigator.msPointerEnabled) {
touchy = function (el, type, fn) {
addEvent(el, microsoft[type], fn);
};
} else {
touchy = function (el, type, fn) {
addEvent(el, touch[type], fn);
addEvent(el, type, fn);
};
}
touchy(el, type, fn);
};
初始化事件
const documentElement = document.documentElement;
function draggable (dom) {
initEvents();
function initEvents () {
touchy(dom, 'mousedown', mousedown);
touchy(documentElement, 'mousemove', mousemove);
touchy(documentElement, 'mouseup', mouseup);
}
//...
}
这里在documentElement上绑定mousemove和mouseup事件,是因为避免渲染速度低于拖拽速度,导致鼠标超出拖拽范围而无法拖拽和释放
这里提一下绑定事件时有一个passive选项,具体可以查看 使用 passive 改善的滚屏性能,可以设置为false,使事件回调可以使用e.preventDefault禁用默认的行为
mousedown
function mousedown (e) {
active = true;
e = getEventHost(e);
_moveX = e.clientX;
_moveY = e.clientY;
}
在documentElement上绑定mousemove和mouseup事件,所以需要标记是否是处于拖拽状态,然后mousemove和mouseup中判断如果不是拖拽状态则跳出函数。
为了适配移动端(touchEvent没有clientX、clientY、x、y),引出了getEventHost
function getEventHost (e) {
if (e.targetTouches && e.targetTouches.length) {
return e.targetTouches[0];
}
if (e.changedTouches && e.changedTouches.length) {
return e.changedTouches[0];
}
return e;
}
我们看看touch、targetTouches、changedTouches的定义
- touches: 当前屏幕上所有触摸点的列表
- targetTouches: 当前对象上所有触摸点的列表
- changedTouches: 涉及当前(引发)事件的触摸点的列表
mousemove
这里实现的是可拖拽范围为document的可视区域
function mousemove (e) {
if (!active) { // 如果不是出于拖拽状态直接放回
return;
}
e = getEventHost(e);
const { x, y, height, width } = dom.getBoundingClientRect();
const curLeft = x + e.clientX - _moveX;
const curTop = y + e.clientY - _moveY;
dom.style.left = `${clamp(curLeft, 0, documentElement.clientWidth - width - 1)}px`;
dom.style.top = `${clamp(curTop, 0, documentElement.clientHeight - height)}px`;
_moveX = e.clientX;
_moveY = e.clientY;
}
// 将value限制在[min, max]之间
function clamp (value, min, max) {
return Math.min(Math.max(value, min), max);
}
mouseup
function mouseup () {
active = false;
}
总结
我们可以自定义mousemove的行为,但整体的框架不会变