From 29db20bb9badd14fb0232c238224bf97db1f7fa9 Mon Sep 17 00:00:00 2001 From: avivbiton <39068976+avivbiton@users.noreply.github.com> Date: Mon, 19 Aug 2019 11:46:32 +0300 Subject: [PATCH 1/2] Dragscroll complete refactor Refactor into functional component, using hooks, removed unnecessary binding and event listeners. Added an option to disable on mobile (true by default) --- src/DragScroll.jsx | 129 ++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 83 deletions(-) diff --git a/src/DragScroll.jsx b/src/DragScroll.jsx index dd69be4..40c1f48 100644 --- a/src/DragScroll.jsx +++ b/src/DragScroll.jsx @@ -1,89 +1,52 @@ -/** - * Created by joe on 16/9/2. - */ - -import React from "react"; - -export default class DragScroll extends React.Component { - constructor(props) { - super(props); - this.state = { - data: props.dataSource, - dragging: false - }; - } - - render() { - let sytle = null; - if (this.props.height && this.props.width) { - sytle = {style: {height: this.props.height, width: this.props.width, overflow: 'auto'}}; +import React, { useState, useCallback, useRef, useMemo } from "react"; + +export default function DragScroll({ className, children, mobileDisabled = true }) { + + const [dragging, setDragging] = useState(false); + const [lastPosition, setPosition] = useState({ x: 0, y: 0 }); + const container = useRef(null); + + const isMobile = useMemo(() => { + return isDeviceMobile(); + }, []); + + const mouseUp = useCallback(() => { + if (dragging) { + setDragging(false); + } + }, [dragging]); + + const mouseDown = useCallback(e => { + if (dragging === false) { + setDragging(true); + setPosition({ x: e.clientX, y: e.clientY }); + } + }, [dragging]); + const mouseMove = useCallback(e => { + if (dragging) { + container.current.scrollLeft -= (-lastPosition.x + e.clientX); + container.current.scrollTop -= (-lastPosition.y + e.clientY); + setPosition({ x: e.clientX, y: e.clientY }); + } + }, [container, dragging, lastPosition]); + + if (mobileDisabled && isMobile) { + return
{children}
} - return
- {this.props.children && this.renderChildren(this.props.children)} -
; - } - componentDidMount() { - window.addEventListener('mouseup', this.mouseUpHandle.bind(this)); - window.addEventListener('mousemove', this.mouseMoveHandle.bind(this)); - } - - componentWillUnmount() { - window.removeEventListener('mouseup', this.mouseUpHandle.bind(this)); - window.removeEventListener('mousemove', this.mouseMoveHandle.bind(this)); - } - - mouseUpHandle(e) { - if (this.state.dragging) { - this.state.dragging = false; - this.setState(this.state); - } - } + return ( +
+ {children} +
+ ); - mouseDownHandle(e) { - if (!this.state.dragging) { - this.state.dragging = true; - this.setState(this.state); - this.lastClientX = e.clientX; - this.lastClientY = e.clientY; - e.preventDefault(); - } - } - - mouseMoveHandle(e) { - if (this.state.dragging) { - this.refs.container.scrollLeft -= - (-this.lastClientX + (this.lastClientX = e.clientX)); - this.refs.container.scrollTop -= - (-this.lastClientY + (this.lastClientY = e.clientY)); - } - } +} - renderChildren(dom, type) { - if (this.isArray(dom)) { - return dom.map((item, index) => { - return React.cloneElement(item, { - key: item.key || index, - onMouseUp: this.mouseUpHandle.bind(this), - onMouseDown: this.mouseDownHandle.bind(this) - }); - }); - } else if ('object' == typeof dom) { - return React.cloneElement(dom, { - onMouseUp: this.mouseUpHandle.bind(this), - onMouseDown: this.mouseDownHandle.bind(this) - }); - } - } - isArray(object){ - return object && typeof object==='object' && - typeof object.length==='number' && - typeof object.splice==='function' && - //判断length属性是否是可枚举的 对于数组 将得到false - !(object.propertyIsEnumerable('length')); - } +function isDeviceMobile() { + return window.matchMedia("(max-width: 992px)").matches; } From 48047f0c5f9b83b50eab2025e7cdf84d6e57f6a1 Mon Sep 17 00:00:00 2001 From: Aviv Biton <39068976+avivbiton@users.noreply.github.com> Date: Mon, 19 Aug 2019 16:48:05 +0300 Subject: [PATCH 2/2] Moved mouseUp to window event to fix a bug This fixes the bug that the scrollable will still be considered as "dragging" after you hold the mouse down and it leaves the scrollable area --- src/DragScroll.jsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/DragScroll.jsx b/src/DragScroll.jsx index 40c1f48..422f917 100644 --- a/src/DragScroll.jsx +++ b/src/DragScroll.jsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useRef, useMemo } from "react"; +import React, { useEffect, useState, useCallback, useRef, useMemo } from "react"; export default function DragScroll({ className, children, mobileDisabled = true }) { @@ -22,6 +22,7 @@ export default function DragScroll({ className, children, mobileDisabled = true setPosition({ x: e.clientX, y: e.clientY }); } }, [dragging]); + const mouseMove = useCallback(e => { if (dragging) { container.current.scrollLeft -= (-lastPosition.x + e.clientX); @@ -30,13 +31,20 @@ export default function DragScroll({ className, children, mobileDisabled = true } }, [container, dragging, lastPosition]); + useEffect(() => { + window.addEventListener("mouseup", mouseUp, false); + return () => { + window.removeEventListener("mouseup", mouseUp, false); + } + }, [mouseUp]); + + if (mobileDisabled && isMobile) { return
{children}
} return (