diff --git a/components/anchor/AnchorLink.tsx b/components/anchor/AnchorLink.tsx index 0a65380ed5..7b5cf3b803 100644 --- a/components/anchor/AnchorLink.tsx +++ b/components/anchor/AnchorLink.tsx @@ -28,6 +28,8 @@ export default class AnchorLink extends React.Component { prefixCls: 'ant-anchor', }; + private _component: Element; + context: { anchorHelper: AnchorHelper; }; @@ -40,6 +42,23 @@ export default class AnchorLink extends React.Component { return { anchorHelper: this.context.anchorHelper, }; + } + + setActiveAnchor() { + const { bounds, href, affix } = this.props; + const { anchorHelper } = this.context; + const active = affix && anchorHelper && anchorHelper.getCurrentAnchor(bounds) === href; + if (active && anchorHelper) { + anchorHelper.setActiveAnchor(this._component); + } + } + + componentDidMount() { + this.setActiveAnchor(); + } + + componentDidUpdate() { + this.setActiveAnchor(); } renderAnchorLink = (child) => { @@ -47,19 +66,24 @@ export default class AnchorLink extends React.Component { if (href) { this.context.anchorHelper.addLink(href); return React.cloneElement(child, { - onClick: this.context.anchorHelper.scrollTo, + onClick: this.props.onClick, prefixCls: this.props.prefixCls, + affix: this.props.affix, }); } return child; } + refsTo = (component) => { + this._component = component; + } + scrollTo = (e) => { const { onClick, href } = this.props; const { anchorHelper } = this.context; e.preventDefault(); if (onClick) { - onClick(href); + onClick(href, this._component); } else { e.stopPreventDefault(); const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo; @@ -78,7 +102,7 @@ export default class AnchorLink extends React.Component { return (
component && active && anchorHelper ? anchorHelper.setActiveAnchor(component) : null} + ref={this.refsTo} className={`${prefixCls}-link-title`} onClick={this.scrollTo} href={href} diff --git a/components/anchor/anchorHelper.tsx b/components/anchor/anchorHelper.tsx index 0dcf732bb3..39cb8c9bec 100644 --- a/components/anchor/anchorHelper.tsx +++ b/components/anchor/anchorHelper.tsx @@ -37,9 +37,9 @@ export function getOffsetTop(element): number { return rect.top; } -export function scrollTo(href, target = getDefaultTarget) { +export function scrollTo(href, target = getDefaultTarget, callback) { const scrollTop = getScroll(target(), true); - const targetElement = document.querySelector(href); + const targetElement = document.getElementById(href.substring(1)); if (!targetElement) { return; } @@ -52,6 +52,8 @@ export function scrollTo(href, target = getDefaultTarget) { window.scrollTo(window.pageXOffset, easeInOutCubic(time, scrollTop, targetScrollTop, 450)); if (time < 450) { reqAnimFrame(frameFunc); + } else { + callback(); } }; reqAnimFrame(frameFunc); @@ -86,7 +88,7 @@ class AnchorHelper { getCurrentAnchor(bounds = 5) { let activeAnchor = ''; this.links.forEach(section => { - const target = document.querySelector(section); + const target = document.getElementById(section.substring(1)); if (target) { const top = getOffsetTop(target); const bottom = top + target.clientHeight; @@ -99,8 +101,8 @@ class AnchorHelper { return this._activeAnchor; } - scrollTo(href, target = getDefaultTarget) { - scrollTo(href, target); + scrollTo(href, target = getDefaultTarget, callback = () => {}) { + scrollTo(href, target, callback); } } diff --git a/components/anchor/index.tsx b/components/anchor/index.tsx index 2f0de969c2..4bd6369b6f 100644 --- a/components/anchor/index.tsx +++ b/components/anchor/index.tsx @@ -34,11 +34,13 @@ export default class Anchor extends React.Component { private scrollEvent: any; private anchorHelper: AnchorHelper; + private _avoidInk: boolean; constructor(props) { super(props); this.state = { activeAnchor: null, + animated: true, }; this.anchorHelper = new AnchorHelper(); } @@ -68,7 +70,9 @@ export default class Anchor extends React.Component { } componentDidUpdate() { - this.updateInk(); + if (!this._avoidInk) { + this.updateInk(); + } } updateInk = () => { @@ -78,12 +82,22 @@ export default class Anchor extends React.Component { } } + clickAnchorLink = (href, component) => { + this.refs.ink.style.transition = 'top 0.01s ease-in-out'; + this._avoidInk = true; + this.refs.ink.style.top = `${component.offsetTop + component.clientHeight / 2 - 4.5}px`; + this.anchorHelper.scrollTo(href, getDefaultTarget, () => { + this.refs.ink.style.transition = 'top 0.3s ease-in-out'; + this._avoidInk = false; + }); + } + renderAnchorLink = (child) => { const { href } = child.props; if (href) { this.anchorHelper.addLink(href); return React.cloneElement(child, { - onClick: this.anchorHelper.scrollTo, + onClick: this.clickAnchorLink, prefixCls: this.props.prefixCls, bounds: this.props.bounds, affix: this.props.affix, @@ -94,9 +108,10 @@ export default class Anchor extends React.Component { render() { const { prefixCls, offsetTop, style, className = '', affix } = this.props; - const { activeAnchor } = this.state; + const { activeAnchor, animated } = this.state; const inkClass = classNames({ [`${prefixCls}-ink-ball`]: true, + animated, visible: !!activeAnchor, }); diff --git a/components/anchor/style/index.less b/components/anchor/style/index.less index 36b84a4295..841ad5b2b3 100644 --- a/components/anchor/style/index.less +++ b/components/anchor/style/index.less @@ -29,8 +29,8 @@ border-radius: 9px; border: 3px solid @primary-color; background-color: white; - transition: top .3s ease-in-out; left: 50%; + transition: top .3s ease-in-out; transform: translateX(-50%); &.visible { display: inline-block;