This commit is contained in:
RaoHai 2016-10-28 14:02:55 +08:00
parent bd8482c893
commit ef720db420
11 changed files with 302 additions and 2 deletions

View File

@ -14,7 +14,7 @@ title:
The simplest usage.
````jsx
import { Affix, Button } from 'antd';
import { Anchor } from 'antd';
ReactDOM.render(
<div>

View 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>;
}
}

View 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);
```

View 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);
```

View 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
View 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>;
}
}

View 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>
```

View File

@ -0,0 +1,5 @@
@import "../../style/themes/default";
.@{ant-prefix}-anchor {
color: red;
}

View File

@ -0,0 +1,2 @@
import '../../style/index.less';
import './index.less';

View 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>
```

View File

@ -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';