Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { useRef, useEffect, useState } from 'react';
- class PullRefresh {
- constructor(opt) {
- this.options = opt;
- this.startPoint = null;
- this.pending = false;
- const { $scroll } = this.options;
- $scroll.addEventListener('touchmove', this.touchmove.bind(this));
- $scroll.addEventListener('touchend', this.touchend.bind(this));
- }
- getScrollPosition() {
- return this.options.$scroll.getClientsRect[0];
- }
- getSlidePosition() {
- return this.options.$slide.getClientsRect[0];
- }
- getDistance() {
- let { paddingTop, paddingBottom, borderTopWidth, borderBottomWidth } = window.getComputedStyle(this.options.$scroll);
- paddingTop = +paddingTop.replace('px', '');
- paddingBottom = +paddingBottom.replace('px', '');
- borderTopWidth = +borderTopWidth.replace('px', '');
- borderBottomWidth = +borderBottomWidth.replace('px', '');
- return (
- this.options.$scroll.scrollTop +
- (this.options.$scroll.offsetHeight - paddingTop - paddingBottom - borderTopWidth - borderBottomWidth) -
- this.options.$slide.offsetHeight
- );
- }
- atBottom() {
- const atBottom = this.getDistance() >= 0;
- return atBottom;
- }
- touchmove(e) {
- if (this.pending) return;
- if (this.options.disable()) return;
- const { clientY, clientX } = e.changedTouches[0];
- if (!this.startPoint) {
- if (this.atBottom()) {
- // 刚好在边界处,往下滑动,此时scroll和slide底部在同一处,但响应touchmove之后,scroll会滚动,导致渲染之后scroll和slide的底部之间存在距离
- // e.preventDefault()
- this.startPoint = { x: clientX, y: clientY };
- this.options.onMoveStart && this.options.onMoveStart();
- }
- return;
- }
- if (clientY > this.startPoint.y) {
- // 下移滚动
- this.options.$slide.style.transform = `translate3d(${0}px,${0}px,${0}px)`;
- }
- if (clientY < this.startPoint.y) {
- // 上拉刷新
- // e.preventDefault()
- console.log('上拉刷新');
- let offsetY = clientY - this.startPoint.y;
- if (offsetY < -50) offsetY = -50;
- this.options.$slide.style.transition = 'none';
- this.options.$slide.style.transform = `translate3d(${0}px,${offsetY}px,${0}px)`;
- }
- }
- touchend(e) {
- if (!this.startPoint) return;
- const { clientY } = e.changedTouches[0];
- this.options.$slide.style.transition = 'transform 300ms linear';
- this.options.$slide.style.transform = `translate3d(${0}px,${0}px,${0}px)`;
- this.options.onMoveEnd && this.options.onMoveEnd();
- if (clientY - this.startPoint.y < -50) {
- this.pending = true;
- this.options.onPull(() => {
- this.pending = false;
- });
- }
- this.startPoint = null;
- }
- }
- export default function Group() {
- let unlock = () => {};
- return props => {
- const $scroll = useRef(null);
- const $slide = useRef(null);
- // const [loading, setLoading] = useState(false);
- const [isShowTip, setShowTip] = useState(false);
- const [scrollHeight, _setScrollHeight] = useState(getScrollHeight());
- const [instance, setInstance] = useState(null);
- // const cb = () => {};
- function getScrollHeight() {
- return window.innerHeight - (50 * window.innerWidth) / 375;
- }
- function setScrollHeight() {
- _setScrollHeight(getScrollHeight());
- }
- useEffect(() => {
- window.addEventListener('resize', setScrollHeight);
- return () => {
- window.removeEventListener('resize', setScrollHeight);
- };
- }, []);
- // function stopPropagation(e) {
- // e.stopPropagation();
- // }
- // useEffect(() => {
- // $scroll.current.addEventListener('touchstart', stopPropagation);
- // $scroll.current.addEventListener('touchmove', stopPropagation);
- // return () => {
- // $scroll.current.removeEventListener('touchstart', stopPropagation);
- // $scroll.current.removeEventListener('touchmove', stopPropagation);
- // };
- // }, [$scroll]);
- useEffect(() => {
- const options = {
- $scroll: $scroll.current,
- $slide: $slide.current,
- disable() {
- return props.disable || props.loadOver || props.loading;
- },
- onMoveStart() {
- setShowTip(true);
- },
- onMoveEnd() {
- setShowTip(false);
- },
- onPull(cb) {
- unlock = cb;
- props.onPull();
- },
- };
- if (instance) {
- Object.assign(instance.options, options);
- return;
- }
- setInstance(new PullRefresh(options));
- }, [$scroll.current, $slide.current, props.onPull, props.disable, props.loading, props.loadOver]);
- useEffect(() => {
- if (props.loading) {
- instance.options.$scroll.scrollTop -= instance.getDistance();
- } else {
- unlock();
- }
- }, [props.loading]);
- return (
- <div
- className="scroll"
- ref={$scroll}
- style={{ overflowX: 'hidden', overflowY: 'scroll', height: scrollHeight, WebkitOverflowScrolling: 'touch' }}>
- <div
- className="slide"
- ref={$slide}
- style={{
- display: 'inline-block',
- width: '100%',
- verticalAlign: 'middle',
- }}>
- {props.children}
- {isShowTip ? props.tipNode : null}
- {props.loading ? props.loadingNode : null}
- {props.loadOver ? props.loadOverNode : null}
- </div>
- </div>
- );
- };
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement