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 {
href: string;
onClick: (href: string) => void;
onClick: (href: string, component: Element) => void;
active?: boolean;
prefixCls?: string;
children?: any;
@ -32,6 +32,8 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
anchorHelper: AnchorHelper;
};
private _component: Element;
constructor(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) => {
const { href } = child.props;
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<AnchorLinkProps, any> {
return (
<div className={cls}>
<a
ref={(component) => component && active && anchorHelper ? anchorHelper.setActiveAnchor(component) : null}
ref={this.refsTo}
className={`${prefixCls}-link-title`}
onClick={this.scrollTo}
href={href}

12
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);
}
}

21
components/anchor/index.tsx

@ -34,11 +34,13 @@ export default class Anchor extends React.Component<AnchorProps, any> {
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<AnchorProps, any> {
}
componentDidUpdate() {
this.updateInk();
if (!this._avoidInk) {
this.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) => {
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<AnchorProps, any> {
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,
});

2
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;

Loading…
Cancel
Save