@gizwits/vantui
Version:
机智云组件库
614 lines (600 loc) • 23.9 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
var _excluded = ["minTriggerTopDistance", "headHeight", "successDuration", "animationDuration", "disabled", "pullDistance", "onRefresh", "renderHead", "successText", "children", "loadingText", "loosingText", "pullingText", "onLoad", "onScroll", "scrollTop", "offset", "finishedText", "renderFinished", "renderLoading", "finished", "renderError", "errorText", "total", "current", "pageSize", "emptyDescription", "emptyImage", "upperThreshold", "lowerThreshold", "refresherEnabled", "onScrollToLower", "onScrollToUpper", "scrollY", "className"];
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
import _regeneratorRuntime from "@babel/runtime/regenerator";
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { View, ScrollView, CustomWrapper } from '@tarojs/components';
import { Loading } from './../loading';
import { Empty } from './../empty';
import { useTouch } from './useTouch';
import { scrollOffset, preventDefault, debounce } from './utils';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
/**
* bem helper
* b() // 'button'
* b('text') // 'button__text'
* b({ disabled }) // 'button button--disabled'
* b('text', { disabled }) // 'button__text button__text--disabled'
* b(['disabled', 'primary']) // 'button button--disabled button--primary'
*/
// const [name, bem, t] = createNamespace('pull-refresh')
// const pullRefreshBem = (name?: string) =>
// name ? 'van-pull-refresh__' + name : 'van-pull-refresh'
var bem = function bem(name) {
return name ? 'van-power-scroll-view__' + name : 'van-power-scroll-view';
};
var sleep = function sleep(t) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, t);
});
};
var DEFAULT_HEAD_HEIGHT = 50;
var MIN_TRIGGER_TOP_DISTANCE = 150;
var TEXT_STATUS = ['pulling', 'loosing', 'success'];
// const RenderStatus: React.FC<{}> = (props) => {}
export function PowerScrollView(props) {
var _ref, _props$refresherEnabl2, _props$scrollY2;
var _props$minTriggerTopD = props.minTriggerTopDistance,
minTriggerTopDistance = _props$minTriggerTopD === void 0 ? MIN_TRIGGER_TOP_DISTANCE : _props$minTriggerTopD,
_props$headHeight = props.headHeight,
headHeight = _props$headHeight === void 0 ? DEFAULT_HEAD_HEIGHT : _props$headHeight,
_props$successDuratio = props.successDuration,
successDuration = _props$successDuratio === void 0 ? 500 : _props$successDuratio,
_props$animationDurat = props.animationDuration,
animationDuration = _props$animationDurat === void 0 ? 300 : _props$animationDurat,
disabled = props.disabled,
_props$pullDistance = props.pullDistance,
pullDistance = _props$pullDistance === void 0 ? props.refresherThreshold || props.pullDistance : _props$pullDistance,
onRefresh = props.onRefresh,
renderHead = props.renderHead,
successText = props.successText,
children = props.children,
_props$loadingText = props.loadingText,
loadingText = _props$loadingText === void 0 ? '加载中...' : _props$loadingText,
_props$loosingText = props.loosingText,
loosingText = _props$loosingText === void 0 ? '释放即可刷新...' : _props$loosingText,
_props$pullingText = props.pullingText,
pullingText = _props$pullingText === void 0 ? '下拉即可刷新...' : _props$pullingText,
onLoad = props.onLoad,
onScrollEvent = props.onScroll,
scrollTop = props.scrollTop,
offset = props.offset,
_props$finishedText = props.finishedText,
finishedText = _props$finishedText === void 0 ? '没有更多了' : _props$finishedText,
renderFinished = props.renderFinished,
renderLoading = props.renderLoading,
_finished = props.finished,
renderError = props.renderError,
errorText = props.errorText,
total = props.total,
current = props.current,
_props$pageSize = props.pageSize,
pageSize = _props$pageSize === void 0 ? 20 : _props$pageSize,
emptyDescription = props.emptyDescription,
emptyImage = props.emptyImage,
upperThreshold = props.upperThreshold,
_props$lowerThreshold = props.lowerThreshold,
lowerThreshold = _props$lowerThreshold === void 0 ? props.lowerThreshold || props.offset || 250 : _props$lowerThreshold,
_props$refresherEnabl = props.refresherEnabled,
refresherEnabled = _props$refresherEnabl === void 0 ? (_ref = (_props$refresherEnabl2 = props.refresherEnabled) !== null && _props$refresherEnabl2 !== void 0 ? _props$refresherEnabl2 : props.disabled) !== null && _ref !== void 0 ? _ref : true : _props$refresherEnabl,
_props$onScrollToLowe = props.onScrollToLower,
onScrollToLower = _props$onScrollToLowe === void 0 ? props.onScrollToLower || props.onLoad : _props$onScrollToLowe,
_props$onScrollToUppe = props.onScrollToUpper,
onScrollToUpper = _props$onScrollToUppe === void 0 ? props.onScrollToUpper || props.onRefresh : _props$onScrollToUppe,
_props$scrollY = props.scrollY,
scrollY = _props$scrollY === void 0 ? (_props$scrollY2 = props.scrollY) !== null && _props$scrollY2 !== void 0 ? _props$scrollY2 : true : _props$scrollY,
className = props.className,
rest = _objectWithoutProperties(props, _excluded);
// ==LIST=======================================
// 是否到底了
// const reachDownRef = useRef(false)
// 是否显示 loading
// ts推断
var loadingRef = useRef(false);
// 是否显示 报错
var errorRef = useRef(false);
// 分页
var paginationRef = useRef({
page: 0,
pageSize: pageSize
});
var startTop = useRef(0);
var _useState = useState(_finished || false),
_useState2 = _slicedToArray(_useState, 2),
finished = _useState2[0],
setFinished = _useState2[1];
var count = Array.isArray(children) ? Array.from(children).length : toString.call(children) === '[object Object]' ? 1 : 0;
var currentCount = current !== null && current !== void 0 ? current : count;
var listCount = useRef(0);
useEffect(function () {
var pageSize = paginationRef.current.pageSize;
if (currentCount <= pageSize) {
paginationRef.current.page = 1;
setFinished(false);
}
// 传入finished
if (_finished !== undefined) {
setFinished(_finished);
return;
}
// 都没有传
if (total === undefined) {
var addCount = currentCount - listCount.current;
if (currentCount === 0 || listCount.current !== 0 && addCount > -1 && addCount < paginationRef.current.pageSize) {
setFinished(true);
}
listCount.current = currentCount;
return;
}
// 传入total
if (currentCount >= total) {
setFinished(true);
} else {
setFinished(false);
}
}, [total, currentCount, _finished]);
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
isError = _useState4[0],
setError = _useState4[1];
// 是否滚动最上面了
var reachTopRef = useRef(true);
var _useState5 = useState('normal'),
_useState6 = _slicedToArray(_useState5, 2),
status = _useState6[0],
setState = _useState6[1];
var _useState7 = useState(0),
_useState8 = _slicedToArray(_useState7, 2),
distance = _useState8[0],
setDistance = _useState8[1];
var _useState9 = useState(0),
_useState10 = _slicedToArray(_useState9, 2),
duration = _useState10[0],
setDuration = _useState10[1];
var touch = useTouch();
var headStyle = useMemo(function () {
if (headHeight !== DEFAULT_HEAD_HEIGHT) {
return {
height: "".concat(headHeight, "px")
};
}
return '';
}, [headHeight]);
var getScrollTop = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var _yield$scrollOffset, scrollTop;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return scrollOffset(scrollRef.current);
case 2:
_yield$scrollOffset = _context.sent;
scrollTop = _yield$scrollOffset.scrollTop;
return _context.abrupt("return", scrollTop);
case 5:
case "end":
return _context.stop();
}
}
}, _callee);
})), []);
var isTouchable = useCallback(function () {
return status !== 'loading' && status !== 'success' && refresherEnabled && !loadingRef.current;
}, [refresherEnabled, status]);
var ease = useCallback(function (distance) {
var _pullDistance = +(pullDistance || headHeight);
if (distance > _pullDistance) {
if (distance < _pullDistance * 2) {
distance = _pullDistance + (distance - _pullDistance) / 2;
} else {
distance = _pullDistance * 1.5 + (distance - _pullDistance * 2) / 4;
}
}
return Math.round(distance);
}, [headHeight, pullDistance]);
var setStatus = useCallback(function (distance, isLoading) {
var _pullDistance = +(pullDistance || headHeight);
setDistance(distance);
if (isLoading) {
setState('loading');
loadingRef.current = true;
} else if (distance === 0) {
setState('normal');
} else if (distance < _pullDistance) {
setState('pulling');
} else {
setState('loosing');
}
}, [headHeight, pullDistance]);
var statusText = useMemo(function () {
if (status === 'loading') {
return loadingText;
}
if (status === 'loosing') {
return loosingText;
}
if (status === 'pulling') {
return pullingText;
}
if (status === 'success') {
return successText;
}
return '';
}, [loadingText, loosingText, pullingText, status, successText]);
var renderStatus = useMemo(function () {
var node = renderHead === null || renderHead === void 0 ? void 0 : renderHead({
status: status,
distance: distance
});
if (node) {
return node;
}
if (TEXT_STATUS.includes(status)) {
return /*#__PURE__*/_jsx(View, {
className: bem('text'),
children: statusText
});
}
if (status === 'loading') {
return /*#__PURE__*/_jsx(Loading, {
className: bem('loading'),
children: statusText
});
}
return '';
}, [distance, statusText, status, renderHead]);
var showSuccessTip = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
// state.status = 'success'
setState('success');
_context2.next = 3;
return sleep(+successDuration);
case 3:
case "end":
return _context2.stop();
}
}
}, _callee2);
})), [successDuration]);
// 提前把reachTopRef.current的值 求出来
var debounceScrollOffset = useMemo(function () {
var _getScrollTop = /*#__PURE__*/function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
var _scrollTop;
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return getScrollTop();
case 2:
_scrollTop = _context3.sent;
reachTopRef.current = _scrollTop <= 0;
return _context3.abrupt("return", _scrollTop);
case 5:
case "end":
return _context3.stop();
}
}
}, _callee3);
}));
return function _getScrollTop() {
return _ref4.apply(this, arguments);
};
}();
return debounce(_getScrollTop, 200);
}, [getScrollTop]);
// 如果这是了 scrollTop 要触发ScrollOffset计算
useEffect(function () {
// 立马执行一次
if (scrollTop) {
reachTopRef.current = false;
}
}, [scrollTop]);
var onScroll = useCallback(function (e) {
onScrollEvent === null || onScrollEvent === void 0 ? void 0 : onScrollEvent(e);
// 模拟器 上 滑到顶 e.detail.scrollTop 不等于0, 低端机可能会出现
// reachTopRef.current = e.detail.scrollTop === 0
debounceScrollOffset();
}, [debounceScrollOffset, onScrollEvent]);
// eslint-disable-next-line react-hooks/exhaustive-deps
var checkPosition = useCallback( /*#__PURE__*/function () {
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(event) {
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
// const { scrollTop } = await scrollOffset(scrollRef.current!)
// reachTopRef.current = scrollTop === 0
if (reachTopRef.current) {
setDuration(0);
touch.start(event);
}
case 1:
case "end":
return _context4.stop();
}
}
}, _callee4);
}));
return function (_x) {
return _ref5.apply(this, arguments);
};
}(), [touch]);
var isStartRef = useRef(false);
var onTouchStart = useCallback( /*#__PURE__*/function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(event) {
var data;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
if (!isTouchable()) {
_context5.next = 8;
break;
}
isStartRef.current = false;
_context5.next = 4;
return getScrollTop();
case 4:
data = _context5.sent;
isStartRef.current = true;
startTop.current = data;
checkPosition(event);
case 8:
case "end":
return _context5.stop();
}
}
}, _callee5);
}));
return function (_x2) {
return _ref6.apply(this, arguments);
};
}(), [checkPosition, getScrollTop, isTouchable]);
// list
var onTouchMove = useCallback(function (event) {
if (isTouchable() && startTop.current < minTriggerTopDistance) {
if (!isStartRef.current) {
return;
}
var deltaY = touch.deltaY;
touch.move(event);
if (reachTopRef.current && deltaY.current >= 0 && touch.isVertical()) {
preventDefault(event, true);
setStatus(ease(deltaY.current));
}
}
}, [ease, isTouchable, minTriggerTopDistance, setStatus, touch]);
// list
var doRefresh = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
var event;
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_context6.prev = 0;
errorRef.current = false;
setStatus(+headHeight, true);
setError(false);
paginationRef.current.page = 1;
event = total === undefined ? 0 : paginationRef.current; // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
_context6.next = 8;
return onScrollToUpper === null || onScrollToUpper === void 0 ? void 0 : onScrollToUpper(event);
case 8:
setDuration(+animationDuration);
if (!(successText || renderHead !== null && renderHead !== void 0 && renderHead({
status: 'success',
distance: distance
}))) {
_context6.next = 12;
break;
}
_context6.next = 12;
return showSuccessTip();
case 12:
_context6.prev = 12;
setStatus(0, false);
loadingRef.current = false;
return _context6.finish(12);
case 16:
case "end":
return _context6.stop();
}
}
}, _callee6, null, [[0,, 12, 16]]);
})), [animationDuration, distance, headHeight, onScrollToUpper, renderHead, setStatus, showSuccessTip, successText, total]);
var onTouchEnd = useCallback(function () {
if (reachTopRef.current && touch.deltaY.current && isTouchable()) {
// state.duration = +animationDuration
setDuration(+animationDuration);
if (status === 'loosing') {
doRefresh();
} else {
setStatus(0);
}
} else {
setStatus(0);
}
}, [doRefresh, isTouchable, animationDuration, setStatus, status, touch.deltaY]);
var trackStyle = useMemo(function () {
return {
transitionDuration: "".concat(duration, "ms"),
transform: distance ? "translate3d(0,".concat(distance, "px, 0)") : ''
};
}, [distance, duration]);
var scrollRef = useRef();
// ==LIST=======================================
var isBanLoad = useCallback(function () {
return finished || status !== 'normal' || loadingRef.current || errorRef.current;
}, [finished, status]);
var doLoadMore = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
var event;
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
if (!isBanLoad()) {
_context7.next = 2;
break;
}
return _context7.abrupt("return");
case 2:
_context7.prev = 2;
loadingRef.current = true;
paginationRef.current.page += 1;
event = total === undefined ? currentCount : paginationRef.current; // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
_context7.next = 8;
return onScrollToLower === null || onScrollToLower === void 0 ? void 0 : onScrollToLower(event);
case 8:
_context7.next = 15;
break;
case 10:
_context7.prev = 10;
_context7.t0 = _context7["catch"](2);
paginationRef.current.page -= 1;
errorRef.current = true;
setError(true);
// 这里要主动触发刷新
// throw e
case 15:
_context7.prev = 15;
loadingRef.current = false;
return _context7.finish(15);
case 18:
case "end":
return _context7.stop();
}
}
}, _callee7, null, [[2, 10, 15, 18]]);
})), [currentCount, isBanLoad, onScrollToLower, total]);
// const check = useCallback(async () => {
// if (!immediateCheck || !scrollY || isBanLoad()) return
// const scrollParentRect = await boundingClientRect(scrollRef.current!)
// if (!scrollParentRect?.height) {
// return
// }
// const placeholderRect = await boundingClientRect(placeholder.current!)
// const isReachEdge =
// placeholderRect.bottom - scrollParentRect.bottom <= lowerThreshold
// if (isReachEdge) {
// doLoadMore()
// } else {
// reachDownRef.current = true
// }
// }, [immediateCheck, scrollY, isBanLoad, lowerThreshold, doLoadMore])
// useEffect(() => {
// // finished || status !== 'normal' || loadingRef.current || errorRef.current
// if (reachDownRef.current) return
// check()
// console.log('loadingRef.current', loadingRef.current, '--change---')
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [reachDownRef.current])
// useEffect(() => {
// setTimeout(() => {
// check()
// }, 500)
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [])
// const placeholder = useRef<TaroElement>()
var renderFinishedText = useMemo(function () {
if (finished) {
var text = renderFinished ? renderFinished : finishedText;
if (text) {
return /*#__PURE__*/_jsx(View, {
className: bem('finished-text'),
children: text
});
}
}
return null;
}, [finished, renderFinished, finishedText]);
var renderLoadingText = useMemo(function () {
if (!finished && scrollY) {
return /*#__PURE__*/_jsx(View, {
className: bem('loading'),
children: renderLoading ? renderLoading : /*#__PURE__*/_jsx(Loading, {
className: bem('loading-icon'),
children: loadingText
})
});
}
return null;
}, [finished, loadingText, scrollY, renderLoading]);
var clickErrorTextHandle = useCallback(function () {
setError(false);
errorRef.current = false;
doLoadMore();
// web 很奇怪的问题
}, [doLoadMore]);
var renderErrorText = useMemo(function () {
if (isError) {
var text = renderError ? renderError : errorText;
if (text) {
return /*#__PURE__*/_jsx(View, {
className: bem('error-text'),
onClick: clickErrorTextHandle,
children: text
});
}
}
return null;
}, [clickErrorTextHandle, isError, errorText, renderError]);
// 如果不定高 一直下拉
var ListScrollContent = useMemo(function () {
if (finished && currentCount === 0) {
return /*#__PURE__*/_jsx(Empty, {
description: emptyDescription,
image: emptyImage
});
}
if (isError) {
return renderErrorText;
}
if (finished) {
return renderFinishedText;
}
return renderLoadingText;
}, [finished, currentCount, isError, renderLoadingText, emptyDescription, emptyImage, renderErrorText, renderFinishedText]);
var renderStatusBody = /*#__PURE__*/_jsx(View, {
className: bem('head'),
style: headStyle,
children: renderStatus
});
var headElement = process.env.TARO_ENV === 'weapp' ? /*#__PURE__*/_jsx(CustomWrapper, {
children: renderStatusBody
}) : renderStatusBody;
return /*#__PURE__*/_jsx(ScrollView, _objectSpread(_objectSpread({
ref: scrollRef,
lowerThreshold: lowerThreshold,
onScroll: onScroll,
scrollTop: scrollTop,
onScrollToLower: doLoadMore,
scrollY: scrollY,
className: "".concat(bem(), " ").concat(className || '')
}, rest), {}, {
children: /*#__PURE__*/_jsxs(View, {
className: bem('track'),
style: trackStyle,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
onTouchCancel: onTouchEnd,
onTouchStart: onTouchStart,
children: [headElement, children, ListScrollContent]
})
}));
}
export default PowerScrollView;