Browse Source

Merge pull request #3853 from RaoHai/anchorLinkFix

Anchor link fix
pull/3888/head
ddcat1115 8 years ago
committed by GitHub
parent
commit
260665d1c2
  1. 32
      components/anchor/AnchorLink.tsx
  2. 12
      components/anchor/anchorHelper.tsx
  3. 21
      components/anchor/index.tsx
  4. 2
      components/anchor/style/index.less

32
components/anchor/AnchorLink.tsx

@ -4,7 +4,7 @@ import AnchorHelper, { scrollTo } from './anchorHelper';
export interface AnchorLinkProps { export interface AnchorLinkProps {
href: string; href: string;
onClick: (href: string) => void; onClick: (href: string, component: Element) => void;
active?: boolean; active?: boolean;
prefixCls?: string; prefixCls?: string;
children?: any; children?: any;
@ -32,6 +32,8 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
anchorHelper: AnchorHelper; anchorHelper: AnchorHelper;
}; };
private _component: Element;
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
} }
@ -42,24 +44,46 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
}; };
} }
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) => { renderAnchorLink = (child) => {
const { href } = child.props; const { href } = child.props;
if (href) { if (href) {
this.context.anchorHelper.addLink(href); this.context.anchorHelper.addLink(href);
return React.cloneElement(child, { return React.cloneElement(child, {
onClick: this.context.anchorHelper.scrollTo, onClick: this.props.onClick,
prefixCls: this.props.prefixCls, prefixCls: this.props.prefixCls,
affix: this.props.affix,
}); });
} }
return child; return child;
} }
refsTo = (component) => {
this._component = component;
}
scrollTo = (e) => { scrollTo = (e) => {
const { onClick, href } = this.props; const { onClick, href } = this.props;
const { anchorHelper } = this.context; const { anchorHelper } = this.context;
e.preventDefault(); e.preventDefault();
if (onClick) { if (onClick) {
onClick(href); onClick(href, this._component);
} else { } else {
e.stopPreventDefault(); e.stopPreventDefault();
const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo; const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo;
@ -78,7 +102,7 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
return ( return (
<div className={cls}> <div className={cls}>
<a <a
ref={(component) => component && active && anchorHelper ? anchorHelper.setActiveAnchor(component) : null} ref={this.refsTo}
className={`${prefixCls}-link-title`} className={`${prefixCls}-link-title`}
onClick={this.scrollTo} onClick={this.scrollTo}
href={href} href={href}

12
components/anchor/anchorHelper.tsx

@ -37,9 +37,9 @@ export function getOffsetTop(element): number {
return rect.top; return rect.top;
} }
export function scrollTo(href, target = getDefaultTarget) { export function scrollTo(href, target = getDefaultTarget, callback = () => {}) {
const scrollTop = getScroll(target(), true); const scrollTop = getScroll(target(), true);
const targetElement = document.querySelector(href); const targetElement = document.getElementById(href.substring(1));
if (!targetElement) { if (!targetElement) {
return; return;
} }
@ -52,6 +52,8 @@ export function scrollTo(href, target = getDefaultTarget) {
window.scrollTo(window.pageXOffset, easeInOutCubic(time, scrollTop, targetScrollTop, 450)); window.scrollTo(window.pageXOffset, easeInOutCubic(time, scrollTop, targetScrollTop, 450));
if (time < 450) { if (time < 450) {
reqAnimFrame(frameFunc); reqAnimFrame(frameFunc);
} else {
callback();
} }
}; };
reqAnimFrame(frameFunc); reqAnimFrame(frameFunc);
@ -86,7 +88,7 @@ class AnchorHelper {
getCurrentAnchor(bounds = 5) { getCurrentAnchor(bounds = 5) {
let activeAnchor = ''; let activeAnchor = '';
this.links.forEach(section => { this.links.forEach(section => {
const target = document.querySelector(section); const target = document.getElementById(section.substring(1));
if (target) { if (target) {
const top = getOffsetTop(target); const top = getOffsetTop(target);
const bottom = top + target.clientHeight; const bottom = top + target.clientHeight;
@ -99,8 +101,8 @@ class AnchorHelper {
return this._activeAnchor; return this._activeAnchor;
} }
scrollTo(href, target = getDefaultTarget) { scrollTo(href, target = getDefaultTarget, callback = () => {}) {
scrollTo(href, target); scrollTo(href, target, callback);
} }
} }

21
components/anchor/index.tsx

@ -34,11 +34,13 @@ export default class Anchor extends React.Component<AnchorProps, any> {
private scrollEvent: any; private scrollEvent: any;
private anchorHelper: AnchorHelper; private anchorHelper: AnchorHelper;
private _avoidInk: boolean;
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
activeAnchor: null, activeAnchor: null,
animated: true,
}; };
this.anchorHelper = new AnchorHelper(); this.anchorHelper = new AnchorHelper();
} }
@ -68,7 +70,9 @@ export default class Anchor extends React.Component<AnchorProps, any> {
} }
componentDidUpdate() { componentDidUpdate() {
this.updateInk(); if (!this._avoidInk) {
this.updateInk();
}
} }
updateInk = () => { updateInk = () => {
@ -78,12 +82,22 @@ export default class Anchor extends React.Component<AnchorProps, any> {
} }
} }
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) => { renderAnchorLink = (child) => {
const { href } = child.props; const { href } = child.props;
if (href) { if (href) {
this.anchorHelper.addLink(href); this.anchorHelper.addLink(href);
return React.cloneElement(child, { return React.cloneElement(child, {
onClick: this.anchorHelper.scrollTo, onClick: this.clickAnchorLink,
prefixCls: this.props.prefixCls, prefixCls: this.props.prefixCls,
bounds: this.props.bounds, bounds: this.props.bounds,
affix: this.props.affix, affix: this.props.affix,
@ -94,9 +108,10 @@ export default class Anchor extends React.Component<AnchorProps, any> {
render() { render() {
const { prefixCls, offsetTop, style, className = '', affix } = this.props; const { prefixCls, offsetTop, style, className = '', affix } = this.props;
const { activeAnchor } = this.state; const { activeAnchor, animated } = this.state;
const inkClass = classNames({ const inkClass = classNames({
[`${prefixCls}-ink-ball`]: true, [`${prefixCls}-ink-ball`]: true,
animated,
visible: !!activeAnchor, visible: !!activeAnchor,
}); });

2
components/anchor/style/index.less

@ -29,8 +29,8 @@
border-radius: 9px; border-radius: 9px;
border: 3px solid @primary-color; border: 3px solid @primary-color;
background-color: white; background-color: white;
transition: top .3s ease-in-out;
left: 50%; left: 50%;
transition: top .3s ease-in-out;
transform: translateX(-50%); transform: translateX(-50%);
&.visible { &.visible {
display: inline-block; display: inline-block;

Loading…
Cancel
Save