我正在构建一个音频播放控件,让用户可以在音频文件中来回滚动。它需要处理触摸和鼠标事件。我应该如何使用被动事件流来管理事件呢?
以下是我希望如何构建它的粗略概念。
<div id="timeline">
<span id="scrubber"></span>
</div>
然后,使用Bacon.js创建事件流
var mousedowns = $('#timeline').asEventStream('mousedown');
var touchstarts = $('#timeline').asEventStream('touchstart');
var starts = Bacon.mergeAll(mousedowns, touchstarts);
var mousemoves = $('#timeline').asEventStream('mousemove');
var touchmoves = $('#timeline').asEventStream('touchmove');
var moves = Bacon.mergeAll(mousemoves, touchmoves);
var mouseups = $('#timeline').asEventStream('mouseup');
var touchends = $('#timeline').asEventStream('touchend');
var ends = Bacon.mergeAll(mouseups, touchends);
starts.onValue(function () {
var repositionScrubber = moves.onValue(function (ev) {
$('#scrubber').moveTo(ev.offsetX);
});
ends.onValue(function () {
repositionScrubber.stop();
});
});
我确定这是各种各样的错误,但我真的很擅长处理带有可观察流的事件,而且我还不知道它有什么好的烹饪书。任何帮助将不胜感激!
答案 0 :(得分:15)
这基本上是规范的drag and drop recipe。
RxJS中的最小工作示例是这样的:
var $timeline = $('#timeline');
var $scrubber = $('#scrubber');
var mouseDown = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mousedown'),
Rx.Observable.fromEvent($timeline, 'touchstart'));
var mouseUp = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mouseup'),
Rx.Observable.fromEvent($timeline, 'touchend'));
var mouseMove = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mousemove'),
Rx.Observable.fromEvent($timeline, 'touchmove'));
var subscription = mouseDown.flatMapLatest(function(md) {
// calculate offsets when mouse down
var startX = md.offsetX;
return mouseMove.takeUntil(mouseUp)
.map(function(mm) {
mm.preventDefault();
return {
left: mm.clientX - startX,
};
});
})
.subscribe(function(e) {
$scrubber.css(e);
});
var $timeline = $('#timeline');
var $scrubber = $('#scrubber');
var mouseDown = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mousedown'),
Rx.Observable.fromEvent($timeline, 'touchstart'));
var mouseUp = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mouseup'),
Rx.Observable.fromEvent($timeline, 'touchend'));
var mouseMove = Rx.Observable.merge(
Rx.Observable.fromEvent($timeline, 'mousemove'),
Rx.Observable.fromEvent($timeline, 'touchmove'));
var subscription = mouseDown.flatMapLatest(function(md) {
// calculate offsets when mouse down
var startX = md.offsetX;
return mouseMove.takeUntil(mouseUp)
.map(function(mm) {
mm.preventDefault();
return {
left: mm.clientX - startX,
};
});
})
.subscribe(function(e) {
$scrubber.css(e);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.3/rx.all.js"></script>
<div id="timeline" style="height: 100px; width: 100px; background: yellow; position: absolute;">
<span id="scrubber" style="height: 20px; width: 30px; background: green; position: relative;">Foo</span>
</div>
答案 1 :(得分:1)
var mousemove = Rx.Observable.merge(
Rx.Observable.fromEvent(document, 'mousemove')
.map((e) => { e.preventDefault(); return e; }),
Rx.Observable.fromEvent(document, 'touchmove'))
.map((e) => e.touches[0]),
mouseup = Rx.Observable.merge(
Rx.Observable.fromEvent(dragTarget, 'mouseup'),
Rx.Observable.fromEvent(dragTarget, 'touchend')),
mousedown = Rx.Observable.merge(
Rx.Observable.fromEvent(dragTarget, 'mousedown'),
Rx.Observable.fromEvent(dragTarget, 'touchstart')
.map((e) => {
var rect = e.target.getBoundingClientRect();
e.offsetX = e.touches[0].pageX - rect.left;
e.offsetY = e.touches[0].pageY - rect.top;
return e;
}));
mousedown
.flatMap((start) => mousemove
.map((mm) =>({
left: mm.clientX - start.offsetX,
top: mm.clientY - start.offsetY
}))
.takeUntil(mouseup))
.subscribe(function (pos) {
dragTarget.style.top = pos.top + 'px';
dragTarget.style.left = pos.left + 'px';
});