今天来实现下抖音顶部Tab栏点击时自动滚动到中间的效果。掘友们有更好的实现方法欢迎指教~~
前置知识
getBoundingClientRect
Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口(可以理解为可见区域,不包含滚动导致的不可见区域)的位置。
如果你需要获得边界矩形相对于整个网页左上角的位置,则可以将当前的滚动位置(可通过 window.scrollX 和 window.scrollY 获得)添加到 top 和 left 属性上。获得的边界矩形与当前的滚动位置无关。
scrollLeft
Element.scrollLeft 属性可以读取或设置元素滚动条到元素左边的距离。
注意如果这个元素的内容排列方向(direction)是rtl (right-to-left) ,那么滚动条会位于最右侧(内容开始处),并且scrollLeft值为 0。此时,当你从右到左拖动滚动条时,scrollLeft 会从 0 变为负数。
代码实现
// app.tsx
import { useState } from 'react';
import './App.css';
function App() {
const initialTabs = [];
const [activeKey, setActiveKey] = useState('1');
for (let i = 0; i < 10; i++) {
initialTabs.push({
name: `Tab${i + 1}`,
key: `${i + 1}`,
});
}
const [tabs] = useState(initialTabs);
const onClickTab = (key: string) => {
setActiveKey(key);
const selector = `#tab${key}`;
const element = document.querySelector(selector);
const elementRect = element?.getBoundingClientRect();
const container = document.querySelector('.tab-container');
const containerRect = container?.getBoundingClientRect();
const halfWidth = (containerRect as DOMRect).width / 2;
console.log('halfWidth', halfWidth);
console.log('container', containerRect);
console.log('elementRect', elementRect);
if ((elementRect as DOMRect).left > halfWidth) {
// tab位于屏幕的右半部分,需要向左滚动
const scrollValue =
elementRect!.left - halfWidth + elementRect!.width / 2;
container && (container.scrollLeft += scrollValue);
} else {
// tab位于屏幕的左半部分,需要向左滚动
const scrollValue =
halfWidth - elementRect!.left - elementRect!.width / 2;
container && (container.scrollLeft -= scrollValue);
}
};
return (
<>
<div className="tab-container">
{tabs.map((tab) => (
<div
key={tab.key}
className={`tab-item ${activeKey === tab.key && 'tab-item-active'}`}
id={`tab${tab.key}`}
onClick={() => onClickTab(tab.key)}
>
{tab.name}
</div>
))}
</div>
<div className="main">页面区域</div>
</>
);
}
export default App;
/* app.css*/
* {
box-sizing: border-box;
}
.tab-container {
width: 375px;
display: flex;
max-width: 100vw;
overflow-x: auto;
padding: 10px 20px;
/* 隐藏滚动条 Firefox*/
scrollbar-width: none;
/* 隐藏滚动条 IE 10+*/
-ms-overflow-style: none;
}
/* Chrome、Safari 和 Opera 的滚动条 */
.tab-container::-webkit-scrollbar {
display: none;
}
.tab-item {
margin-right: 3rem;
cursor: pointer;
}
.tab-item-active {
color: red;
}
.tab-item:last-child {
margin-right: 0;
}
.main {
width: 375px;
height: 20rem;
background-color: bisque;
margin-top: 1rem;
}