指针跟踪是用户界面的一个重要组成部分
Drag & drop, scrolling galleries, measuring touch scroll speed是一些显而易见的实例
在本篇中,将看到如何监听action转换成DOM事件流
然后,我们将看看如何用指针动作跟踪鼠标和触摸动作,然后使用该指针的移动来拖动DOM元素
popmotion提供llisten
action来监听DOM事件
import { listen } from 'popmotion';
它将接受事件名称作为空格分隔的字符串,这意味着您可以使用单个listen
侦听多个事件
listen(document, 'mousedown touchstart')
.start((e) => console.log(e));
由于listen
是一个action
,同样的也同样拥有一些链式方法
例如,下面是如何制作一个只有在有两个以上的触摸时才会触发的TouchMove监听器
listen(document, 'touchmove')
.filter(({ touches }) => touches.length >= 2)
.start((e) => /* This event has more than 2 touches! */);
Pointer
操作提供了一个通用接口,用于与单点鼠标和触摸输入交互(对于多点触摸,multitouch
提供多点操作)
import { pointer } from 'popmotion';
默认情况下,指针将指针的clientX和clientY属性输出为x和y
let pointerTracker;
listen(document, 'mousedown touchstart').start(() => {
pointerTracker = pointer()
.start(({ x, y }) => console.log(x, y));
});
listen(document, 'mouseup touchend').start(() => {
if (pointerTracker) pointerTracker.stop();
})
在大多数情况下,我们实际上希望使用这些移动数据来拖动或滚动
让我们再次使用styler
函数来创建DOM元素接口,以便提供位置数据
关注startTracking
方法,并尝试写一个demo并拖动球<指#a .ball元素>
const ball = document.querySelector('#a .ball');
const ballStyler = styler(ball);
let pointerTracker;
const startTracking = () => {
pointerTracker = pointer()
.start(ballStyler.set);
};
const stopTracking = () => {
if (pointerTracker) pointerTracker.stop();
};
listen(ball, 'mousedown touchstart').start(startTracking);
listen(document, 'mouseup touchend').start(stopTracking);
OK,球可以进行拖动了,但是好像,球移动到了一个奇怪的地方
原因很简单,pinter
输出一个{x,y}
坐标是相对于视窗的
球的{x,y}从0,0开始变换。所以,如果我们把指针的绝对位置直接应用到球上,它就不会移动到我们想要的位置
const ball = document.querySelector('#b .ball');
const ballStyler = styler(ball);
let pointerTracker;
const startTracking = () => {
pointerTracker = pointer({
x: ballStyler.get('x'), // +++++
y: ballStyler.get('y') // ++++
}).start(ballStyler.set);
};
const stopTracking = () => {
if (pointerTracker) pointerTracker.stop();
};
可以直接这样:
pointer().start(({ x }) => ballStyler.set('x', x));
但是,更可重用的方法是使用指针的管道(pipe)方法组成一个新的动作。我们可以提供一个简单的选择器函数,从指针的输出中选择x并返回它
const xPointer = (initialX) => pointer({ x: initialX })
.pipe(({ x }) => x);
现在我们可以使用xPointer
方法了
xPointer(ballStyler.get('x'))
.start(ballStyler.set('x'));
demo:
const ball = document.querySelector('#c .ball');
const ballStyler = styler(ball);
const xPointer = (initialX) => pointer({ x: initialX })
.pipe(({ x }) => x);
let pointerTracker;
const startTracking = () => {
pointerTracker = xPointer(ballStyler.get('x'))
.start(ballStyler.set('x'));
};
const stopTracking = () => {
if (pointerTracker) pointerTracker.stop();
};
listen(ball, 'mousedown touchstart').start(startTracking);
listen(document, 'mouseup touchend').start(stopTracking);
listen
可以将DOM事件转换为值的反应流。对于利用管道和其他可链接的方法,以及使用其他操作进行组合侦听都很有用
pointer
可以绝对输出值,或者,如果我们提供初始坐标,则可以相对地应用它的增量来输出值
最后,我们可以组合新的操作来生成具有新行为( action )的可重用代码,比如单轴拖动
现在我们已经开始拖动工作,在下一篇教程中,我们将学习如何检查被拖动物体的速度,并将其应用于衰变、物理和弹簧动作,以创建自然感觉的相互作用