【Taro小程序】实现小程序的scroll-view下拉刷新趟坑

3,191 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

趟坑经历:

1、直接使用页面的onPullDownRefresh函数——但页面上有scroll-view组件时,事件冲突导致onPulldownRefresh不生效

——onPullDownRefresh在页面上无scroll-view可使用

2、自定义scroll-view的ontouchmove 事件和 touchend事件,在move超过一定距离时设置loading 值为true,塞入loading dom,执行刷新函数。刷新函数数据拿到后,设置loading态为false,dom消失。——问题是ios的scroll-view会存在橡皮筋弹性效果,自动回弹。而塞入dom的渲染来不及,导致出现卡顿效果。即使加动画也不行

——最好就是不要自己定义刷新

3、结合refresherTriggered和ontouchmove ,在move超过一定距离时设置trigged值为true,修改onRefresherRefresh为刷新函数。刷新结束后设置trigged为false。——奇怪的问题是若move的距离恰好在临界值附件,刷新之后设置了trigged为false,但loading态没有取消

4、最后直接用refresherThreshold设置位移值,超过了即onRefresherRefresh执行。

——最后的问题是Taro上没有修改loading态的api,直接修改背景颜色,但是dom不可以。小程序原生开发是可以的

最终代码实现

import React, { useState } from 'react';
import { View, ScrollView } from '@tarojs/components';
// import { AtActivityIndicator } from 'taro-ui'

import './RefreshScrollView.scss';

export default function RefreshScrollView(props) {
const { refresh = null, loadMore = null, classNameAdditional = '' } = props;
const [loading, setLoading] = useState(false);
const onRefresh = () => {
	setLoading(true);
	refresh && refresh(endLoading);
};
const endLoading = () => {
	setTimeout(() => {
		setLoading(false);
	}, 500);
};
const loadRecommend = () => {
	loadMore && loadMore();
};

return (
	<View className="dragUpdataPage">
		<ScrollView
			className={'home__wrap ' + classNameAdditional}
			onScrollToLower={() => loadRecommend()}
			scrollWithAnimation
			refresherEnabled
			refresherTriggered={loading}
			onRefresherRefresh={onRefresh}
			refresherThreshold={45}
			scrollY
		>
			{props.childComponent}
		</ScrollView>
	</View>
);
import React, { useState } from 'react';
import { View, ScrollView } from '@tarojs/components';
// import { AtActivityIndicator } from 'taro-ui'

import './RefreshScrollView.scss';

export default function RefreshScrollView(props) {
const { down = null, loadMore = () => {}, classNameAdditional = '', loadingComponent = null } = props;
//1、用于将下拉高度定义为用户滑动高度的,需求暂时用不上;
// 2 、小于最小高度展示下拉刷新,到达后展示释放刷新,需求也用不上;
const [topClass, setTopClass] = useState('');
const [heightClass, setHeightClass] = useState('');
// const [downText, setDownText] = useState('下拉刷新')
const [scrollY, setScrollY] = useState(true);
const [dragState, setDragState] = useState(0); // 0不做操作 1刷新
const [startP, setStartP] = useState({});

const touchmove = (e) => {
	const move_p = e.touches[0], //移动时的位置
		deviationX = 0.3, //左右偏移量(超过这个偏移量不执行下拉操作)
		deviationY = 56; //拉动长度(低于这个值的时候不执行)

	const start_x = startP.clientX,
		start_y = startP.clientY,
		move_x = move_p.clientX,
		move_y = move_p.clientY;
	const dev = Math.abs(move_x - start_x) / Math.abs(move_y - start_y);
	if (dev < deviationX) {
		//当偏移数值大于设置的偏移数值时则不执行操作
		if (move_y - start_y > 0) {
			//下拉操作
			const pY = Math.abs(move_y - start_y) / 3.5;
			if (pY >= deviationY) {
				down && setDragState(1);
				down && setScrollY(false);
			}
		}
	}
};
const touchEnd = (e) => {
	if (dragState === 1) {
		setHeightClass(' animateHeight ');
		setTopClass(' animateTop ');
		_down();
	}
};
const _down = () => {
	down(reduction);
};
const reduction = () => {
	// 刷新之后重置
	setTimeout(() => {
		setHeightClass(' animateBackHeight ');
		setTopClass(' animateBackTop ');
		setScrollY(true);
		setDragState(0);
	}, 500);
};
const touchStart = (e) => {
	setStartP(e.touches[0]);
};
// console.log(info)
const loadRecommend = () => {
	loadMore();
};
return (
	<View className="dragUpdataPage">
		<View className={'downDragBox ' + heightClass}>{loadingComponent}</View>
		<ScrollView
			className={'home__wrap ' + topClass + classNameAdditional}
			scrollY={scrollY}
			onTouchMove={touchmove}
			onTouchEnd={touchEnd}
			onTouchStart={touchStart}
			onScrollToLower={() => loadRecommend()}
			scrollWithAnimation
		>
			{props.childComponent}
		</ScrollView>
	</View>
);
}