2016-10-28 14:02:55 +08:00
|
|
|
import React from 'react';
|
2016-11-09 14:43:12 +08:00
|
|
|
import classNames from 'classnames';
|
2016-11-03 16:45:13 +08:00
|
|
|
import AnchorHelper, { scrollTo } from './anchorHelper';
|
2016-10-28 14:02:55 +08:00
|
|
|
|
|
|
|
export interface AnchorLinkProps {
|
|
|
|
href: string;
|
2016-11-15 15:33:13 +08:00
|
|
|
onClick: (href: string, component: Element) => void;
|
2016-11-03 16:45:13 +08:00
|
|
|
active?: boolean;
|
|
|
|
prefixCls?: string;
|
|
|
|
children?: any;
|
2017-01-20 20:10:50 +08:00
|
|
|
title?: React.ReactNode;
|
2017-02-10 16:34:10 +08:00
|
|
|
offsetTop: number;
|
2016-11-03 16:45:13 +08:00
|
|
|
bounds: number;
|
|
|
|
target?: () => HTMLElement | Window;
|
2016-11-09 21:06:43 +08:00
|
|
|
affix?: boolean;
|
2016-10-28 14:02:55 +08:00
|
|
|
}
|
|
|
|
|
2016-11-03 16:45:13 +08:00
|
|
|
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
|
|
|
static contextTypes = {
|
|
|
|
anchorHelper: React.PropTypes.any,
|
|
|
|
};
|
2016-10-28 16:53:59 +08:00
|
|
|
|
2016-11-03 16:45:13 +08:00
|
|
|
static defaultProps = {
|
|
|
|
href: '#',
|
|
|
|
prefixCls: 'ant-anchor',
|
|
|
|
};
|
|
|
|
|
|
|
|
context: {
|
|
|
|
anchorHelper: AnchorHelper;
|
|
|
|
};
|
|
|
|
|
2016-11-15 15:33:13 +08:00
|
|
|
private _component: Element;
|
|
|
|
|
2016-11-14 15:43:55 +08:00
|
|
|
setActiveAnchor() {
|
2017-02-10 16:34:10 +08:00
|
|
|
const { bounds, offsetTop, href, affix } = this.props;
|
2016-11-14 15:43:55 +08:00
|
|
|
const { anchorHelper } = this.context;
|
2017-02-10 16:34:10 +08:00
|
|
|
const active = affix && anchorHelper && anchorHelper.getCurrentAnchor(offsetTop, bounds) === href;
|
2016-11-14 15:43:55 +08:00
|
|
|
if (active && anchorHelper) {
|
|
|
|
anchorHelper.setActiveAnchor(this._component);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.setActiveAnchor();
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
this.setActiveAnchor();
|
2016-11-03 16:45:13 +08:00
|
|
|
}
|
2016-11-09 14:22:38 +08:00
|
|
|
|
2016-11-03 16:45:13 +08:00
|
|
|
renderAnchorLink = (child) => {
|
|
|
|
const { href } = child.props;
|
|
|
|
if (href) {
|
|
|
|
this.context.anchorHelper.addLink(href);
|
|
|
|
return React.cloneElement(child, {
|
2016-11-14 15:43:55 +08:00
|
|
|
onClick: this.props.onClick,
|
2016-11-03 16:45:13 +08:00
|
|
|
prefixCls: this.props.prefixCls,
|
2016-11-14 15:43:55 +08:00
|
|
|
affix: this.props.affix,
|
2017-02-10 16:34:10 +08:00
|
|
|
offsetTop: this.props.offsetTop,
|
2016-11-03 16:45:13 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
return child;
|
|
|
|
}
|
2016-11-09 14:22:38 +08:00
|
|
|
|
2016-11-14 15:43:55 +08:00
|
|
|
refsTo = (component) => {
|
|
|
|
this._component = component;
|
|
|
|
}
|
|
|
|
|
2016-11-09 20:17:02 +08:00
|
|
|
scrollTo = (e) => {
|
2016-11-18 17:25:30 +08:00
|
|
|
e.preventDefault();
|
2016-11-09 14:40:31 +08:00
|
|
|
const { onClick, href } = this.props;
|
|
|
|
const { anchorHelper } = this.context;
|
|
|
|
if (onClick) {
|
2016-11-14 15:43:55 +08:00
|
|
|
onClick(href, this._component);
|
2016-11-09 14:40:31 +08:00
|
|
|
} else {
|
|
|
|
e.stopPreventDefault();
|
|
|
|
const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo;
|
2017-02-10 16:34:10 +08:00
|
|
|
scrollToFn(href, this.props.offsetTop);
|
2016-11-09 14:40:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 16:45:13 +08:00
|
|
|
render() {
|
2017-02-10 16:34:10 +08:00
|
|
|
const { prefixCls, href, children, title, bounds, offsetTop, affix } = this.props;
|
2016-11-03 16:45:13 +08:00
|
|
|
const { anchorHelper } = this.context;
|
2017-02-10 16:34:10 +08:00
|
|
|
const active = affix && anchorHelper && anchorHelper.getCurrentAnchor(offsetTop, bounds) === href;
|
2016-11-09 14:43:12 +08:00
|
|
|
const cls = classNames({
|
2016-11-03 16:45:13 +08:00
|
|
|
[`${prefixCls}-link`]: true,
|
|
|
|
[`${prefixCls}-link-active`]: active,
|
|
|
|
});
|
2016-11-09 14:22:38 +08:00
|
|
|
return (
|
|
|
|
<div className={cls}>
|
2016-11-09 14:40:31 +08:00
|
|
|
<a
|
2016-11-14 15:43:55 +08:00
|
|
|
ref={this.refsTo}
|
2016-11-09 14:22:38 +08:00
|
|
|
className={`${prefixCls}-link-title`}
|
2016-11-09 14:40:31 +08:00
|
|
|
onClick={this.scrollTo}
|
|
|
|
href={href}
|
2016-11-10 11:35:12 +08:00
|
|
|
title={typeof title === 'string' ? title : ''}
|
2016-11-09 14:22:38 +08:00
|
|
|
>
|
2016-11-09 14:40:31 +08:00
|
|
|
{title}
|
|
|
|
</a>
|
2016-11-09 14:22:38 +08:00
|
|
|
{React.Children.map(children, this.renderAnchorLink)}
|
|
|
|
</div>
|
|
|
|
);
|
2016-11-03 16:45:13 +08:00
|
|
|
}
|
|
|
|
}
|