React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果的示例代碼
React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果
import React, { useRef, useState, useEffect } from 'react'; import styles from './index.less'; import classnames from 'classnames'; function AnchorTabber(props) { const root = useRef(null); const header = useRef(null); const { attrbute = 'data-anchor', offsetY = 60, list = [], initialKey = list[0]?.key, children, } = props; const [state, setState] = useState({ activeKey: initialKey, }); const [key2Bottom, setKey2Bottom] = useState({ key2Bottom: {}, }); /** @type { HTMLDivElement } */ const scrollElement = document.querySelector('#root').firstChild; function scrollTo(key) { // if(!scrollElement) { // scrollElement = document.querySelector('#root').firstChild; // } const attribute = attrbute; /** @type { HTMLDivElement } */ const targetEl = root.current?.querySelector(`[${attribute}=${key}]`); if (targetEl) { const clientRect = targetEl.getBoundingClientRect(); const top = scrollElement.scrollTop + clientRect.top - offsetY; scrollElement.scrollTo({ top, behavior: 'smooth', }); // targetEl.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } function updateElementsPosition() { const elements = document.querySelectorAll(`[${attrbute}]`); Array.from(elements).forEach(element => { const targetAttr = element.getAttribute(`${attrbute}`); const clientRect = element.getBoundingClientRect(); const bottom = clientRect.top + scrollElement.scrollTop; key2Bottom[targetAttr] = bottom; }); setKey2Bottom(key2Bottom); } function handleScroll() { const top = scrollElement.scrollTop + offsetY; // eslint-disable-next-line no-unused-vars const target = Object.entries(key2Bottom) .sort(([, v1], [, v2]) => v2 - v1) .find(([, v]) => v <= top); if (target) { setState({ activeKey: target[0], }); } } useEffect(() => { updateElementsPosition(); // document.addEventListener('touchstart', updateElementsPosition); scrollElement.addEventListener('scroll', handleScroll); return () => { // document.removeEventListener('touchstart', updateElementsPosition); scrollElement.removeEventListener('scroll', handleScroll); }; }); function handleItemClick(tabber) { scrollTo(tabber.key); } function render() { let { activeKey } = state; if(typeof(activeKey) === "undefined") { activeKey = initialKey } return ( <div className={styles.mAnchorTabber}> <div className={styles.header} ref={header}> {list?.map(tabber => ( <div className={classnames(styles.item, { [styles.active]: activeKey === tabber.key })} onClick={() => handleItemClick(tabber)} > {tabber.name} </div> ))} </div> <div className={styles.container} ref={root}> {children} </div> </div> ); } return render(); } export default AnchorTabber;
對應(yīng)樣式(less)
.mAnchorTabber { .header { display: flex; align-items: center; position: sticky; top: 0; height: .len(46) []; box-sizing: border-box; box-shadow: 0 .len(2) [] .len(2) [] .len(1) [] #c4c4c4; background-color: @basecolor; .item { height: 100%; flex-grow: 1; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-weight: 400; font-size: @font-size-base-normal; line-height: .len(20) []; &.active { background-color: @bgc-product-detail; color: @basecolor; } } } }
.len(46) []這個改成對應(yīng) px單位即可,本單位是為了移動端適配轉(zhuǎn)換
測試test
對應(yīng)測試文件
import React from 'react'; import { connect } from 'dva'; import AnchorTabber from '@/components/m/AnchorTabber'; @connect(({ common }) => ({ common, })) class ApplicationsRecord extends React.Component { constructor(props) { super(props); this.state = { list: [ { name: 'test1', key: 'test1', }, { name: 'test2', key: 'test2', }, { name: 'test3', key: 'test3', }, ], }; } render() { const { list } = this.state; const index2Attr = { 0: 'test1', 100: 'test2', 200: 'test3', }; return ( <AnchorTabber list={list}> <ul className="list"> {new Array(1000).fill(null).map((_item, index) => ( <li data-anchor={index2Attr[index]}>{index}</li> ))} </ul> </AnchorTabber> ); } } export default ApplicationsRecord;
到此這篇關(guān)于React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果的示例代碼的文章就介紹到這了,更多相關(guān)React錨點跳轉(zhuǎn)組件附帶吸頂效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React實現(xiàn)導(dǎo)入導(dǎo)出Excel文件
本文主要介紹了React實現(xiàn)導(dǎo)入導(dǎo)出Excel文件,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07react+ts實現(xiàn)簡單jira項目的最佳實踐記錄
這篇文章主要介紹了react+ts實現(xiàn)簡單jira項目,本文通過圖文實例相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07利用React-router+Webpack快速構(gòu)建react程序
目前 React、Webpack 等技術(shù)如火如荼,你是不是還在愁苦如何把這些雜亂的知識怎么學(xué)習(xí)一下,開啟一段新的前端開發(fā)之路呢?那么這篇將給大家運用示例代碼詳細的介紹使用React-router和Webpack如何快速構(gòu)建一個react程序,感興趣的朋友們下面來一起看看吧。2016-10-10解決React報錯Cannot assign to 'current'
這篇文章主要為大家介紹了React報錯Cannot assign to 'current' because it is a read-only property的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12封裝一個最簡單ErrorBoundary組件處理react異常
這篇文章主要介紹了一個處理react異常的ErrorBoundary組件,簡單實用,代碼詳細,對這個組件感興趣的朋友可以參考下2021-04-04React實現(xiàn)一個倒計時hook組件實戰(zhàn)示例
這篇文章主要為大家介紹了React實現(xiàn)一個倒計時hook組件,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02