在网页应用中,拖拽操作就是用户在某个dom元素上面按下去,然后拖动,最后松开鼠标的这一个过程。这个过程是重复的,拖拽涉及的事件有 mousedown,mousemove,mouseup,所以实现拖拽要控制好这几个事件的处理
传统方式实现拖拽
在mousedown时,用一个变量标识现在进入拖拽状态,然后监听mousemove和mouseup事件,mousemove事件来引发dom移动,mouseup事件或者mouseout事件来改变状态变量标识现在离开拖拽状态。
函数响应式编程
函数响应式编程的思路基本相同,但是实现方法完全不同。
首先我们获取mousedown数据流
const box = document.querySelector('#box')
const mouseDown$ = Rx.Observable.fromEvent(box, 'mousedown')
获取mouseup数据流和mouseout数据流并合并
const mourseUp$ = Rx.Observable.fromEvent(box, 'mouseup')
const mouseOut$ = Rx.Observable.fromEvent(box, 'mouseout')
const stop$ = mouseOut$.merge(mourseUp$)
获取mousemove数据流
const mouseMove$ = Rx.Observable.fromEvent(box,'mousemove')
现在我们根据这几个流来实现拖拽流,mouseDown流发生数据时,mousemove流生效触发事件,直到stop流发生数据时,mousemove流关闭不触发事件。用到concatMap,takeUntil方法的组合
const drag$ = mouseDown$.concatMap(startEvent => {
const startLeft = box.offsetLeft
const startTop= box.offsetTop
return mouseMove$.takeUntil(stop$).map(moveEvent => {
return {
x:moveEvent.x - startEvent.x + startLeft,
y:moveEvent.y - startEvent.y + startTop
}
})
})
有了这个拖拽流,最后只要订阅这个流即可实现拖拽功能
drag$.subscribe(event => {
box.style.left = event.x + 'px'
box.style.top = event.y + 'px'
})
拖拽这个功能如果用函数响应式编程的方式实现,代码量很少。而且不需要一个状态变量来标识现在是否为拖拽状态。实现方法与传统面向过程的实现方法完全不同。面向过程编程的核心在于如何通过一系列过程来实现我们想要的结果,而函数响应式编程的核心在于思考哪些场景下,我们想要的结果会自动发生。
完整代码《深入浅出RxJS》
<!DOCTYPE html>
<html lang="en">
<body>
<div id="box" style=" position: absolute;width:100px;height: 100px; background-color: aquamarine;"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
<script>
const box = document.querySelector('#box')
const mouseDown$ = Rx.Observable.fromEvent(box, 'mousedown')
const mourseUp$ = Rx.Observable.fromEvent(box, 'mouseup')
const mouseOut$ = Rx.Observable.fromEvent(box, 'mouseout')
const mouseMove$ = Rx.Observable.fromEvent(box,'mousemove')
const stop$ = mouseOut$.merge(mourseUp$)
const drag$ = mouseDown$.concatMap(startEvent => {
const startLeft = box.offsetLeft
const startTop= box.offsetTop
return mouseMove$.takeUntil(stop$).map(moveEvent => {
return {
x:moveEvent.x - startEvent.x + startLeft,
y:moveEvent.y - startEvent.y + startTop
}
})
})
drag$.subscribe(event => {
box.style.left = event.x + 'px'
box.style.top = event.y + 'px'
})
</script>
</body>
</html>
网友评论