mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-18 03:14:07 +08:00
anchor
This commit is contained in:
parent
bd8482c893
commit
ef720db420
@ -14,7 +14,7 @@ title:
|
||||
The simplest usage.
|
||||
|
||||
````jsx
|
||||
import { Affix, Button } from 'antd';
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
|
21
components/anchor/AnchorLink.tsx
Normal file
21
components/anchor/AnchorLink.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
|
||||
export interface AnchorLinkProps {
|
||||
href: string;
|
||||
onClick: (href: string) => {};
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
|
||||
onClick = () => {
|
||||
if (this.props.href) {
|
||||
this.props.onClick(this.props.href);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return <div onClick={this.onClick}>
|
||||
{this.props.active ? 'active':null } {this.props.children}
|
||||
</div>;
|
||||
}
|
||||
}
|
27
components/anchor/demo/basic.md
Normal file
27
components/anchor/demo/basic.md
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 基本
|
||||
en-US: Basic
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
最简单的用法。
|
||||
|
||||
## en-US
|
||||
|
||||
The simplest usage.
|
||||
|
||||
```jsx
|
||||
|
||||
const { Anchor } = antd;
|
||||
|
||||
const { AnchorLink } = Anchor;
|
||||
|
||||
ReactDOM.render(
|
||||
<Anchor>
|
||||
<AnchorLink href="#components-anchor-demo-basic">锚点1</AnchorLink>
|
||||
</Anchor>
|
||||
, mountNode);
|
||||
```
|
24
components/anchor/demo/independ.md
Normal file
24
components/anchor/demo/independ.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
order: 1
|
||||
title:
|
||||
zh-CN: 独立使用 AnchorLink
|
||||
en-US: Independent AnchorLink
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
独立使用 AnchorLink
|
||||
|
||||
## en-US
|
||||
|
||||
Independent AnchorLink
|
||||
|
||||
```jsx
|
||||
|
||||
const { Anchor } = antd;
|
||||
const { AnchorLink } = Anchor;
|
||||
|
||||
ReactDOM.render(
|
||||
<AnchorLink href="#components-anchor-demo-basic">锚点1</AnchorLink>
|
||||
, mountNode);
|
||||
```
|
29
components/anchor/index.en-US.md
Normal file
29
components/anchor/index.en-US.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
category: Components
|
||||
type: Other
|
||||
title: Anchor
|
||||
---
|
||||
|
||||
Make an element sticky to viewport.
|
||||
|
||||
## When To Use
|
||||
|
||||
When user browses a long web page, some content need to sticky to viewport. It is common for menus and actions.
|
||||
|
||||
Please note that Affix should not cover other content in page, especially when the size of viewport is small.
|
||||
|
||||
## API
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|--------------|-----------------------|----------|--------------|
|
||||
| offsetTop | Pixels to offset from top when calculating position of scroll | Number | 0 |
|
||||
| offsetBottom | Pixels to offset from bottom when calculating position of scroll | Number | - |
|
||||
| onChange | Callback when affix state is changed | Function(affixed) | - |
|
||||
|
||||
**Note:** Children of `Affix` can not be `position: absolute`, but you can set `Affix` as `position: absolute`:
|
||||
|
||||
```jsx
|
||||
<Affix style={{ position: 'absolute', top: y, left: x}}>
|
||||
...
|
||||
</Affix>
|
||||
```
|
128
components/anchor/index.tsx
Normal file
128
components/anchor/index.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import AnchorLink from './AnchorLink';
|
||||
import Affix from '../affix';
|
||||
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
|
||||
|
||||
const reqAnimFrame = getRequestAnimationFrame();
|
||||
|
||||
const easeInOutCubic = (t, b, c, d) => {
|
||||
t /= d/2;
|
||||
if (t < 1) return c/2*t*t*t + b;
|
||||
t -= 2;
|
||||
return c/2*(t*t*t + 2) + b;
|
||||
};
|
||||
|
||||
function getDefaultTarget() {
|
||||
return typeof window !== 'undefined' ?
|
||||
window : null;
|
||||
}
|
||||
|
||||
function getOffsetTop(element): number {
|
||||
if (!element) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!element.getClientRects().length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
|
||||
if ( rect.width || rect.height ) {
|
||||
const doc = element.ownerDocument;
|
||||
const docElem = doc.documentElement;
|
||||
return rect.top + window.pageYOffset - docElem.clientTop;
|
||||
}
|
||||
|
||||
return rect.top;
|
||||
}
|
||||
|
||||
export interface AnchorProps {
|
||||
target: () => HTMLElement | Window;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
|
||||
export default class Anchor extends React.Component<AnchorProps, any> {
|
||||
static AnchorLink = AnchorLink;
|
||||
|
||||
private scrollEvent: any;
|
||||
private sections: Array<string> = [];
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activeAnchor: null,
|
||||
};
|
||||
}
|
||||
handleScroll = () => {
|
||||
const { target = getDefaultTarget } = this.props;
|
||||
const scrollTop = getScroll(target(), true);
|
||||
let activeAnchor;
|
||||
|
||||
this.sections.forEach(section => {
|
||||
const target = document.querySelector(section);
|
||||
if (target) {
|
||||
const top = target.offsetTop;
|
||||
const bottom = top + target.clientHeight;
|
||||
if ((scrollTop >= top) && (scrollTop <= bottom)) {
|
||||
activeAnchor = section;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (activeAnchor) {
|
||||
this.setState({
|
||||
activeAnchor,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.handleScroll();
|
||||
this.scrollEvent = addEventListener((this.props.target || getDefaultTarget)(), 'scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.scrollEvent) {
|
||||
this.scrollEvent.remove();
|
||||
}
|
||||
}
|
||||
|
||||
scrollTo = (href) => {
|
||||
const { target = getDefaultTarget } = this.props;
|
||||
const scrollTop = getScroll(target(), true);
|
||||
const offsetTop = getOffsetTop(document.querySelector(href));
|
||||
const startTime = Date.now();
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
document.body.scrollTop = easeInOutCubic(time, scrollTop, offsetTop, 450);
|
||||
if (time < 450) {
|
||||
reqAnimFrame(frameFunc);
|
||||
}
|
||||
};
|
||||
reqAnimFrame(frameFunc);
|
||||
}
|
||||
|
||||
renderAnchorLink = (child) => {
|
||||
const { href } = child.props;
|
||||
if (href) {
|
||||
if (this.sections.indexOf(href) === -1) {
|
||||
this.sections.push(href);
|
||||
}
|
||||
return React.cloneElement(child, { onClick: this.scrollTo, active: this.state.activeAnchor === href });
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Affix>
|
||||
<div>{React.Children.map(this.props.children, this.renderAnchorLink)}</div>
|
||||
</Affix>;
|
||||
}
|
||||
}
|
||||
|
31
components/anchor/index.zh-CN.md
Normal file
31
components/anchor/index.zh-CN.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 锚点
|
||||
type: Other
|
||||
title: Anchor
|
||||
---
|
||||
|
||||
将页面元素钉在可视范围。
|
||||
|
||||
## 何时使用
|
||||
|
||||
当内容区域比较长,需要滚动页面时,这部分内容对应的操作或者导航需要在滚动范围内始终展现。常用于侧边菜单和按钮组合。
|
||||
|
||||
页面可视范围过小时,慎用此功能以免遮挡页面内容。
|
||||
|
||||
## API
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
|-------------|----------------|--------------------|--------------|
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | Number | |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | Number | |
|
||||
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | Function | () => window |
|
||||
| onChange | 固定状态改变时触发的回调函数 | Function(affixed) | 无 |
|
||||
|
||||
**注意:**`Affix` 内的元素不要使用绝对定位,如需要绝对定位的效果,可以直接设置 `Affix` 为绝对定位:
|
||||
|
||||
```jsx
|
||||
<Affix style={{ position: 'absolute', top: y, left: x}}>
|
||||
...
|
||||
</Affix>
|
||||
```
|
5
components/anchor/style/index.less
Normal file
5
components/anchor/style/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
@import "../../style/themes/default";
|
||||
|
||||
.@{ant-prefix}-anchor {
|
||||
color: red;
|
||||
}
|
2
components/anchor/style/index.tsx
Normal file
2
components/anchor/style/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
31
components/anchor/style/index.zh-CN.md
Normal file
31
components/anchor/style/index.zh-CN.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
category: Components
|
||||
subtitle: 固钉
|
||||
type: Other
|
||||
title: Affix
|
||||
---
|
||||
|
||||
将页面元素钉在可视范围。
|
||||
|
||||
## 何时使用
|
||||
|
||||
当内容区域比较长,需要滚动页面时,这部分内容对应的操作或者导航需要在滚动范围内始终展现。常用于侧边菜单和按钮组合。
|
||||
|
||||
页面可视范围过小时,慎用此功能以免遮挡页面内容。
|
||||
|
||||
## API
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 |
|
||||
|-------------|----------------|--------------------|--------------|
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | Number | |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | Number | |
|
||||
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | Function | () => window |
|
||||
| onChange | 固定状态改变时触发的回调函数 | Function(affixed) | 无 |
|
||||
|
||||
**注意:**`Affix` 内的元素不要使用绝对定位,如需要绝对定位的效果,可以直接设置 `Affix` 为绝对定位:
|
||||
|
||||
```jsx
|
||||
<Affix style={{ position: 'absolute', top: y, left: x}}>
|
||||
...
|
||||
</Affix>
|
||||
```
|
@ -9,6 +9,8 @@ please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundl
|
||||
|
||||
export { default as Affix } from './affix';
|
||||
|
||||
export { default as Anchor } from './anchor';
|
||||
|
||||
export { default as AutoComplete } from './auto-complete';
|
||||
|
||||
export { default as Alert } from './alert';
|
||||
@ -101,4 +103,4 @@ export { default as Tooltip } from './tooltip';
|
||||
|
||||
export { default as Mention } from './mention';
|
||||
|
||||
export { default as Upload } from './upload';
|
||||
export { default as Upload } from './upload';
|
Loading…
Reference in New Issue
Block a user