Необходимо реализовать активное изменение ссылки при прокрутке, используя React и Fabri c ui. Подошел к этому примеру https://github.com/OfficeDev/office-ui-fabric-react/blob/2a162cb9dcee4fb702ad3efc0b653478db4b012e/packages/example-app-base/src/components/SideRail/SideRail.tsx.
Пытаюсь использовать, но когда я нажимаю на ссылку, она фактически переходит на раздел, я бы предпочел использовать плавную прокрутку. Как я могу реализовать это в моем примере ниже?
classNamesFunction,
css,
FocusZone,
FocusZoneDirection,
IProcessedStyleSet,
Link,
styled
} from "office-ui-fabric-react";
import * as React from "react";
import { getStyles } from "./SideRail.styles";
import {
ISideRailLink,
ISideRailProps,
ISideRailStyleProps,
ISideRailStyles
} from "./SideRail.types";
export interface ISideRailState {
activeLink?: string;
}
const getClassNames = classNamesFunction<
ISideRailStyleProps,
ISideRailStyles
>();
class SideRailBase extends React.Component<ISideRailProps, ISideRailState> {
public readonly state: ISideRailState = {};
private _classNames: IProcessedStyleSet<ISideRailStyles>;
private _observer: IntersectionObserver;
public componentDidMount() {
if (typeof IntersectionObserver !== "undefined") {
const { observe, jumpLinks } = this.props;
if (observe && jumpLinks) {
this._observer = new IntersectionObserver(this._handleObserver, {
threshold: [0.5]
});
jumpLinks.forEach((jumpLink: ISideRailLink) => {
const element = document.getElementById(jumpLink.url);
if (element) {
this._observer.observe(element);
}
});
}
}
}
public componentWillUnmount() {
if (this._observer) {
this._observer.disconnect();
}
}
render() {
this._classNames = getClassNames(this.props.styles, {
theme: this.props.theme
});
const jumpLinkList = this._renderJumpLinkList();
return jumpLinkList ? (
<FocusZone
direction={FocusZoneDirection.vertical}
className={this._classNames.root}
>
{jumpLinkList}
</FocusZone>
) : null;
}
private _handleObserver = (entries: IntersectionObserverEntry[]) => {
for (const entry of entries) {
const { intersectionRatio, target } = entry;
if (intersectionRatio > 0.5) {
this.setState({
activeLink: target.id
});
break;
}
}
};
private _renderJumpLinkList = (): JSX.Element | null => {
const { activeLink } = this.state;
const { jumpLinks } = this.props;
const classNames = this._classNames;
if (!jumpLinks || !jumpLinks.length) {
return null;
}
const links = jumpLinks.map((jumpLink: ISideRailLink) => (
<li
key={jumpLink.url}
className={css(classNames.linkWrapper, classNames.jumpLinkWrapper)}
>
<Link
href={this._getJumpLinkUrl(jumpLink.url)}
styles={{
root: [
classNames.jumpLink,
activeLink === jumpLink.url && classNames.jumpLinkActive
]
}}
>
{jumpLink.text}
</Link>
</li>
));
return (
<div className={css(classNames.section, classNames.jumpLinkSection)}>
<ul className={classNames.links}>{links}</ul>
</div>
);
};
private _getJumpLinkUrl(anchor: string): string {
// This makes sure that location hash changes don't append
// eslint-disable-next-line no-restricted-globals
return `${removeAnchorLink(location.hash)}#${anchor}`;
}
}
/**
* Remove the anchor link from a full page URL or a hash.
* Preserves any route path specified in the URL.
* Behavior with more than two # in the URL is unspecified.
*/
export const removeAnchorLink = (url: string): string => {
// First group: most of the URL
// Second group: optional last hash with only word or dash characters following (an anchor)
const match = url.match(/^(.*?)(#[\w-]*)?$/);
if (match) {
return match[1];
}
return url;
};
export const SideRail: React.StatelessComponent<ISideRailProps> = styled<
ISideRailProps,
ISideRailStyleProps,
ISideRailStyles
>(SideRailBase, getStyles, undefined, { scope: "SideRail" });