ant-design/components/anchor/anchorHelper.tsx

130 lines
3.3 KiB
TypeScript
Raw Normal View History

2016-11-03 16:45:13 +08:00
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
export const reqAnimFrame = getRequestAnimationFrame();
export const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
2016-11-09 14:22:38 +08:00
const cc = c - b;
t /= d / 2;
if (t < 1) {
return cc / 2 * t * t * t + b;
}
return cc / 2 * ((t -= 2) * t * t + 2) + b;
2016-11-03 16:45:13 +08:00
};
export function getDefaultTarget() {
return typeof window !== 'undefined' ?
window : null;
}
export function getOffsetTop(element: HTMLElement): number {
2016-11-03 16:45:13 +08:00
if (!element) {
return 0;
}
if (!element.getClientRects().length) {
return 0;
}
const rect = element.getBoundingClientRect();
if (rect.width || rect.height) {
2016-11-03 16:45:13 +08:00
const doc = element.ownerDocument;
const docElem = doc.documentElement;
return rect.top - docElem.clientTop;
2016-11-03 16:45:13 +08:00
}
return rect.top;
}
export type Section = {
top: number;
bottom: number;
section: any;
};
export function scrollTo(href: string, offsetTop = 0, target = getDefaultTarget, callback = () => { }) {
2016-11-09 14:22:38 +08:00
const scrollTop = getScroll(target(), true);
const targetElement = document.getElementById(href.substring(1));
if (!targetElement) {
return;
}
const eleOffsetTop = getOffsetTop(targetElement);
const targetScrollTop = scrollTop + eleOffsetTop - offsetTop;
2016-11-09 14:22:38 +08:00
const startTime = Date.now();
const frameFunc = () => {
const timestamp = Date.now();
const time = timestamp - startTime;
window.scrollTo(window.pageXOffset, easeInOutCubic(time, scrollTop, targetScrollTop, 450));
2016-11-09 14:22:38 +08:00
if (time < 450) {
reqAnimFrame(frameFunc);
} else {
callback();
2016-11-09 14:22:38 +08:00
}
};
reqAnimFrame(frameFunc);
2016-11-15 15:33:13 +08:00
history.pushState(null, '', href);
2016-11-09 14:22:38 +08:00
}
2016-11-03 16:45:13 +08:00
class AnchorHelper {
private links: Array<string>;
private currentAnchor: HTMLAnchorElement | null;
private _activeAnchor: string;
2016-11-03 16:45:13 +08:00
constructor() {
this.links = [];
this.currentAnchor = null;
this._activeAnchor = '';
2016-11-03 16:45:13 +08:00
}
addLink(link: string) {
2016-11-03 16:45:13 +08:00
if (this.links.indexOf(link) === -1) {
this.links.push(link);
}
}
getCurrentActiveAnchor(): HTMLAnchorElement | null {
2016-11-03 16:45:13 +08:00
return this.currentAnchor;
2016-11-03 19:28:28 +08:00
}
2016-11-03 16:45:13 +08:00
setActiveAnchor(component: HTMLAnchorElement) {
2016-11-03 16:45:13 +08:00
this.currentAnchor = component;
}
getCurrentAnchor(offsetTop: number = 0, bounds = 5) {
2016-11-03 16:45:13 +08:00
let activeAnchor = '';
if (typeof document === 'undefined') {
return activeAnchor;
}
const linksPositions = (this.links
.map(section => {
const target = document.getElementById(section.substring(1));
if (target && getOffsetTop(target) < offsetTop + bounds) {
const top = getOffsetTop(target);
if (top <= offsetTop + bounds) {
return {
section,
top,
bottom: top + target.clientHeight,
};
}
2016-11-03 16:45:13 +08:00
}
return null;
})
.filter(section => section !== null) as Array<Section>);
if (linksPositions.length) {
const maxSection = linksPositions.reduce((prev, curr) => curr.top > prev.top ? curr : prev);
return maxSection.section;
}
return '';
2016-11-03 16:45:13 +08:00
}
scrollTo(href: string, offsetTop: number | undefined, target = getDefaultTarget, callback = () => { }) {
scrollTo(href, offsetTop, target, callback);
2016-11-03 16:45:13 +08:00
}
}
2016-11-03 19:28:28 +08:00
export default AnchorHelper;