mobile-more
Version:
基于 antd-mobile v5 扩展移动端 UI 组件
135 lines • 6.09 kB
JavaScript
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
var _excluded = ["items", "renderItems", "tabsProps", "className", "headerStyle", "headerClassName", "contentStyle", "contentClassName"];
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { ceil } from 'ut2';
import { Tabs } from 'antd-mobile';
import { useThrottleFn } from 'rc-hooks';
import { getScrollParent, getScrollTop } from '../../utils/dom';
import classnames from 'classnames';
import { prefixClass } from '../../config';
import "./index.css";
import { getTimestampString } from '../../utils/utils';
var prefixCls = "".concat(prefixClass, "-anchor-tabs");
var BizAnchorTabs = function BizAnchorTabs(_ref) {
var items = _ref.items,
renderItems = _ref.renderItems,
tabsProps = _ref.tabsProps,
className = _ref.className,
headerStyle = _ref.headerStyle,
headerClassName = _ref.headerClassName,
contentStyle = _ref.contentStyle,
contentClassName = _ref.contentClassName,
restProps = _objectWithoutProperties(_ref, _excluded);
// TODO 大版本更新改用 React.useId
var uid = useMemo(function () {
return getTimestampString('__anchor_tabs');
}, []);
var ref = useRef(null);
var tabContainerRef = useRef(null);
var _useState = useState(items[0].key),
_useState2 = _slicedToArray(_useState, 2),
activeKey = _useState2[0],
setActiveKey = _useState2[1];
var _useThrottleFn = useThrottleFn(function () {
var _tabContainerRef$curr;
var currentKey = items[0].key;
var tabContainerRect = (_tabContainerRef$curr = tabContainerRef.current) === null || _tabContainerRef$curr === void 0 ? void 0 : _tabContainerRef$curr.getBoundingClientRect();
var tabTop = tabContainerRect ? tabContainerRect.top + tabContainerRect.height : 0;
var _iterator = _createForOfIteratorHelper(items),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var item = _step.value;
var element = document.getElementById(uid + item.key);
if (!element) continue;
var rect = element.getBoundingClientRect();
if (rect.top <= tabTop) {
currentKey = item.key;
} else {
break;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
setActiveKey(currentKey);
}, 100),
handleScroll = _useThrottleFn.run;
useEffect(function () {
handleScroll();
var scrollContainer = getScrollParent(ref.current);
scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.addEventListener('scroll', handleScroll);
return function () {
scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.removeEventListener('scroll', handleScroll);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
var itemsDom = items.map(function (item) {
var id = uid + item.key;
if (typeof item.content === 'function') {
return /*#__PURE__*/React.createElement(Fragment, {
key: item.key
}, item.content(id));
}
return /*#__PURE__*/React.createElement("div", {
key: item.key,
id: id
}, item.content);
});
var customItemsDom = typeof renderItems === 'function' ? renderItems(itemsDom) : itemsDom;
return /*#__PURE__*/React.createElement("div", _objectSpread(_objectSpread({
className: classnames(prefixCls, className)
}, restProps), {}, {
ref: ref
}), /*#__PURE__*/React.createElement("div", {
className: classnames("".concat(prefixCls, "-header"), headerClassName),
style: headerStyle,
ref: tabContainerRef
}, /*#__PURE__*/React.createElement(Tabs, _objectSpread(_objectSpread({}, tabsProps), {}, {
activeKey: activeKey,
onChange: function onChange(key) {
var _tabsProps$onChange;
var id = uid + key;
var currentContent = document.getElementById(id);
currentContent === null || currentContent === void 0 ? void 0 : currentContent.scrollIntoView();
var scrollContainer = getScrollParent(ref.current);
if (scrollContainer && tabContainerRef.current) {
var tabRect = tabContainerRef.current.getBoundingClientRect();
// scrollIntoView 存在的问题:不一定滚动至顶部,会留有 0.015xxx 左右的误差
var contentRectTop = (currentContent === null || currentContent === void 0 ? void 0 : currentContent.getBoundingClientRect().top) || 0;
var offsetTop = ceil(contentRectTop - tabRect.top);
// 如果已滚动至顶部,不需要再处理减去tab高度
// if (
// getScrollTop(scrollContainer) + getClientHeight(scrollContainer) <
// getScrollHeight(scrollContainer)
// ) {
// 此处使用偏差小于tab高度进行判断
if (offsetTop < tabRect.height) {
// scrollTo 存在的问题:如果滚动不是整数或0.5倍数会有偏差,例如 400.9121 => 400.5
scrollContainer.scrollTo({
top: getScrollTop(scrollContainer) - tabRect.height + offsetTop
});
}
}
tabsProps === null || tabsProps === void 0 ? void 0 : (_tabsProps$onChange = tabsProps.onChange) === null || _tabsProps$onChange === void 0 ? void 0 : _tabsProps$onChange.call(tabsProps, key);
}
}), items.map(function (item) {
return /*#__PURE__*/React.createElement(Tabs.Tab, {
title: item.title,
key: item.key
});
}))), /*#__PURE__*/React.createElement("div", {
className: classnames("".concat(prefixCls, "-content"), contentClassName),
style: contentStyle
}, customItemsDom));
};
/**
* @deprecated 即将废弃,请使用 `BizAnchorTabs` 替代。
*/
export var AnchorTabs = BizAnchorTabs;
export default BizAnchorTabs;