@fruits-chain/react-native-xiaoshu
Version:
🌈 React Native UI library
102 lines (99 loc) • 3.38 kB
JavaScript
import React, { memo, useMemo, useRef } from 'react';
import { View, ScrollView } from 'react-native';
import { usePersistFn, useDifferentState, useUpdateEffect } from "../hooks/index.js";
import TabBar from "../tab-bar/index.js";
import { ElevatorContextProvider, useElevator } from "./context.js";
import STYLES from "./style.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const ElevatorNavInner = ({
triggerOffset = 100,
tabBarHeight = 40,
scrollComponent = ScrollView,
children,
onScroll,
onMomentumScrollEnd,
...restProps
}) => {
const ScrollComponent = scrollComponent;
const {
registerScroll,
elevator
} = useElevator();
const ScrollViewRef = useRef();
const ScrollTop = useRef(0);
const [showNav, setShowNav] = useDifferentState(false);
const [tabBarValue, setTabBarValue] = useDifferentState(undefined);
const tabBarOptions = useMemo(() => elevator.map(item => ({
value: item.label,
label: item.label
})), [elevator]);
const tabBarKey = useMemo(() => JSON.stringify(tabBarOptions), [tabBarOptions]);
const ActionChangeTabBarValue = useRef(false);
const initTabBar = usePersistFn(y => {
const _showNav = y >= triggerOffset - tabBarHeight;
// 滚动距离增加 tabBarHeight,UI 上已经滚动过去了
// TODO 从体验上看,top 过了内容高度的三之一就算滚到了
const overElevators = elevator.filter(item => item.top <= y + tabBarHeight);
const _tabBarValue = overElevators[overElevators.length - 1]?.label;
setShowNav(_showNav);
if (_showNav && _tabBarValue && !ActionChangeTabBarValue.current) {
setTabBarValue(_tabBarValue);
}
});
useUpdateEffect(() => {
// 当布局变化时重新定位
initTabBar(ScrollTop.current);
}, [tabBarOptions]);
// TODO 修复类型报错
registerScroll(ScrollViewRef);
const onScrollPersist = usePersistFn(e => {
onScroll?.(e);
ScrollTop.current = e.nativeEvent.contentOffset.y;
initTabBar(ScrollTop.current);
});
const onChangeTabBar = usePersistFn(v => {
setTabBarValue(v);
ActionChangeTabBarValue.current = true;
ScrollViewRef.current?.scrollTo({
y: elevator.filter(item => item.label === v)[0].top,
animated: true
});
});
const onMomentumScrollEndPersist = usePersistFn(e => {
onMomentumScrollEnd?.(e);
ActionChangeTabBarValue.current = false;
});
return /*#__PURE__*/_jsxs(View, {
style: STYLES.wrapper,
collapsable: false,
children: [showNav && tabBarValue ? /*#__PURE__*/_jsx(View, {
style: STYLES.nav,
children: /*#__PURE__*/_jsx(TabBar, {
indicator: true,
safeAreaInsetBottom: false,
value: tabBarValue,
onChange: onChangeTabBar,
options: tabBarOptions
}, tabBarKey)
}) : null, /*#__PURE__*/_jsx(ScrollComponent, {
scrollEventThrottle: 16,
bounces: false,
...restProps,
// TODO 修复类型报错
ref: ScrollViewRef,
onScroll: onScrollPersist,
onMomentumScrollEnd: onMomentumScrollEndPersist,
children: children
})]
});
};
const ElevatorNav = props => {
return /*#__PURE__*/_jsx(ElevatorContextProvider, {
children: /*#__PURE__*/_jsx(ElevatorNavInner, {
...props
})
});
};
export default /*#__PURE__*/memo(ElevatorNav);
//# sourceMappingURL=elevator-nav.js.map
;