import * as React from 'react'; import { Props, State } from './type'; import { Container, NavBox, NavBoxPlace, NavItems, NavItem, ContentItem, ContentItemEditTip, ListMode } from './index.style'; import linearScrollTo from '../utils/linearScrollTo'; export class Tab extends React.Component { static defaultProps = new Props(); state = new State(); private containerNode: HTMLElement; private navBoxNode: HTMLElement; private contentItemNodes: { [propsName: string]: HTMLElement } = {}; handleNavItemClick(index: number) { if (this.props.tabType === 1) { this.scrollToView(index); } else { this.setState({ selectedIndex: index }); } } handleScroll = () => { if (this.props.tabFixed) { const containerRect = this.containerNode.getBoundingClientRect(); const containerHeight = containerRect.bottom - containerRect.top; const navBoxReact = this.navBoxNode.getBoundingClientRect(); const navBoxHeight = navBoxReact.bottom - navBoxReact.top; if (containerRect.top <= 0) { // to fixed if (containerRect.bottom <= navBoxHeight) { // 不超出 容器总高度 this.navBoxNode.style.position = 'absolute'; this.navBoxNode.style.top = containerHeight - navBoxHeight + 'px'; } else { this.navBoxNode.style.position = 'fixed'; this.navBoxNode.style.top = '0px'; } } else { // not fixed this.navBoxNode.style.position = 'absolute'; this.navBoxNode.style.top = '0px'; } } this.changeSelectedByPosition(); } changeSelectedByPosition() { if (this.props.tabType === 1) { const navBoxReact = this.navBoxNode.getBoundingClientRect(); const navBoxHeight = navBoxReact.bottom - navBoxReact.top; let currentOffset = -Infinity; let currentIndex: null | number = null; Object.keys(this.contentItemNodes).forEach((itemIndex) => { const itemNode = this.contentItemNodes[itemIndex]; if (itemNode) { const itemRect = itemNode.getBoundingClientRect(); const offset = itemRect.top - navBoxHeight; if ( offset <= 0 && offset > currentOffset ) { currentOffset = offset; currentIndex = +itemIndex; } } }) if ( typeof currentIndex === 'number' && this.state.selectedIndex !== currentIndex ) { this.setState({ selectedIndex: currentIndex }) } } } changeSelectedByHash() { const { instanceKey, autoScrollToView } = this.props; const hash = window.location.href; const activeIndexReg = new RegExp(`${instanceKey}-(\\d+)`); const regResult = activeIndexReg.exec(hash); if (regResult) { const targetSelectedIndex = +regResult[1]; if (this.contentItemNodes[targetSelectedIndex]) { this.setState({ selectedIndex: targetSelectedIndex }, () => { if (autoScrollToView) { this.scrollToView(targetSelectedIndex); } }) } } } scrollToView(index: number, options?: { animation: number }) { const node = this.contentItemNodes[index]; let animation = 400; if (options && typeof options.animation === 'number') { animation = options.animation; } if (node) { const navBoxReact = this.navBoxNode.getBoundingClientRect(); const nodeRect = node.getBoundingClientRect(); const targetY = Math.ceil(window.pageYOffset + nodeRect.top - (navBoxReact.bottom - navBoxReact.top)); if (animation) { linearScrollTo( targetY, animation ) } else { window.scrollTo(0, targetY); } } } componentDidMount() { window.addEventListener('scroll', this.handleScroll); // 默认进行一次校准 this.handleScroll(); this.changeSelectedByHash(); } componentWillUnmount() { window.removeEventListener('scroll', this.handleScroll); } public render() { const { selectedIndex } = this.state; const { listStyle, marginColor, marginLR, backgroudColor, instanceKey, isEdit, style, type, tabType, marginTop, tabs, children, tabColor, tabHeight } = this.props; // console.log('tab图高度',tabHeight,'tab图宽度',tabs[0].focusImage?.width) // 点击和未点击状态图片大小要一模一样,目前所有宽高取决于第一张点击状态Tab图的宽高 return ( { this.containerNode = container; }} className={listStyle ? 'list' : ''} marginColor={marginColor} > { this.navBoxNode = navBox; }} tabHeight={tabHeight} tabColor={tabColor} style={{ width: style.width }} > { tabs.map((tab, index) => ( this.handleNavItemClick(index)} > { type !== 4 && {tab.name} } { type === 4 && } )) } { (!Array.isArray(children)) ? children : children.map((child, index) => { const tabName = tabs[index] && tabs[index].name; const selected = index === selectedIndex; return ( { this.contentItemNodes[index] = element; }} key={index} isEdit={isEdit} tabType={tabType} selected={selected} > {(isEdit || selected) && child} { isEdit && ( 编辑Tab: {tabName || '未命名'} ) } ) }) } ) } }