Merge pull request #974 from ant-design/develop-0.12.0

Publish 0.12.0
This commit is contained in:
afc163 2016-02-01 16:21:08 +08:00
commit 8a5ad542a6
257 changed files with 5716 additions and 3192 deletions

View File

@ -12,34 +12,25 @@
"experimentalObjectRestSpread": true
},
"plugins": [
"markdown-antd",
"markdown",
"react",
"babel"
],
"rules": {
"constructor-super": 2,
"comma-dangle": 0,
"func-names": 0,
"guard-for-in": 0,
"one-var": [2, { "initialized": "never" }],
"prefer-const": 0,
"key-spacing": 0,
"no-eq-null": 0,
"no-else-return": 0,
"no-param-reassign": 0,
"no-this-before-super": 2,
"no-undef": 2,
"babel/object-shorthand": 0,
"react/jsx-no-duplicate-props": 2,
"prefer-template": 0,
"arrow-body-style": 0,
"react/sort-comp": 0,
"react/wrap-multilines": 0,
"react/no-multi-comp": 0,
"react/prop-types": 0,
"space-after-keywords": 0,
"space-before-blocks": 0,
"space-before-function-paren": 0,
"spaced-comment": 0,
"vars-on-top": 0,
"id-length": 0
"react/prefer-es6-class": 0,
"react/jsx-closing-bracket-location": 0,
"react/jsx-no-bind": 0,
"no-param-reassign": 0,
"max-len": 0,
"object-shorthand": 0,
"quote-props": 0
}
}

View File

@ -4,6 +4,66 @@
---
## 0.12.0
`2016-02-01`
- 新增 [级联选择(Cascader)](http://ant.design/components/cascader/) 组件。
- 新增 [树选择控件(TreeSelect)](http://ant.design/components/tree-select/) 组件。
- Form 自身支持校验功能,废弃 Validation。[演示](http://ant.design/components/form/#demo-validate-basic)
- Tabs
- `activeKey` 修正为受控属性。
- 当前项现在会始终显示。[#815](https://github.com/ant-design/ant-design/issues/815)
- Modal 可以配置右上关闭按钮是否显示。
- Select
- 打开选项菜单时,自动滚动到选中项。
- `combobox` 模式时,可配置是否默认选中第一项。[rc-select#38](https://github.com/react-component/select/issues/38)
- Table
- filter 支持层级选择。
- 支持行点击事件 `onRowClick`
- 支持多列的横向切换。[演示](http://ant.design/components/table/#demo-paging-columns)
- 更换 `dataSource` 和变换页面时不再默认清除选择数据,你可以用 `selectedRowKeys` 手动控制。`原来默认清除的行为会触发一个数据更新的死循环,而且难以实现跨页选择。`
- 支持固定表头。[演示](http://ant.design/components/table/#demo-fixed-header)
- Tag 去除 `href` 属性,默认标签名从 `a` 改为 `span`
- Timeline 支持指定 pending 节点的内容。
- Tree
- 节点支持拖拽。
- 支持动态控制节点展开与否。[演示](http://ant.design/components/tree/#demo-basic-controlled)
- 可以监听节点展开/关闭事件 `onExpand`
- `onCheck` `onSelect` 参数调整。
- `onDataLoaded` 改为 `loadData`
- 新增 drag&drop 相关属性:
- `onDragStart`
- `onDragEnter`
- `onDragOver`
- `onDragLeave`
- `onDrop`
- 新增 TreeNode 节点属性:
- `disableCheckbox`
- `isLeaf`
- Transfer 给 `onChange` 增加参数。[#972](https://github.com/ant-design/ant-design/issues/972)
- DatePicker
- 修复 RangePicker 开始结束日期相同的 bug。[#822](https://github.com/ant-design/ant-design/issues/822)
- 修复 `format` 对浮层不生效问题。[#917](https://github.com/ant-design/ant-design/issues/917)
- TimePicker 修复一个 `value``null` 时没有进入受控模式的问题。
- Upload
- 可以用 `headers` 设置上传头部。
- 新增上传图片卡片样式。[演示](http://ant.design/components/upload/#demo-picture-card)
- Radio
- 更换 Radio.Button 的展现样式。
- 可以设置 Radio.Button 的大小。
- Progress
- `format` 属性现在支持自定义 function 的方式进行定义。[#893](https://github.com/ant-design/ant-design/issues/893)
- `format` 指定 string 和 React.Node 的方式被废弃。
- 支持 `style` 属性。[#895](https://github.com/ant-design/ant-design/issues/895)
- message && notification 现在可以销毁。
- Button
- 小号 Button 的圆角调整为 `4px`
- 修复 Button.Group disabled 后的样式问题。[#926](https://github.com/ant-design/ant-design/issues/926)
- BreadCrumb
- 移除 `router` 属性,无需设置。
- 修复一个链接参数不对的问题。
## 0.11.3
`2016-01-19`

View File

@ -8,10 +8,10 @@ function getScroll(w, top) {
let method = 'scroll' + (top ? 'Top' : 'Left');
if (typeof ret !== 'number') {
let d = w.document;
//ie6,7,8 standard mode
// ie6,7,8 standard mode
ret = d.documentElement[method];
if (typeof ret !== 'number') {
//quirks mode
// quirks mode
ret = d.body[method];
}
}

View File

@ -9,7 +9,7 @@
````jsx
import { Alert } from 'antd';
const onClose = function(e) {
const onClose = function (e) {
console.log(e, '我要被关闭啦!');
};

View File

@ -44,20 +44,20 @@ export default React.createClass({
let iconType = '';
switch (type) {
case 'success':
iconType = 'check-circle';
break;
case 'info':
iconType = 'info-circle';
break;
case 'error':
iconType = 'exclamation-circle';
break;
case 'warn':
iconType = 'exclamation-circle';
break;
default:
iconType = 'default';
case 'success':
iconType = 'check-circle';
break;
case 'info':
iconType = 'info-circle';
break;
case 'error':
iconType = 'exclamation-circle';
break;
case 'warn':
iconType = 'exclamation-circle';
break;
default:
iconType = 'default';
}
// use outline icon in alert with description
@ -80,9 +80,9 @@ export default React.createClass({
return this.state.closed ? null : (
<Animate component=""
showProp="data-show"
transitionName="slide-up"
onEnd={this.animationEnd}>
showProp="data-show"
transitionName="slide-up"
onEnd={this.animationEnd}>
<div data-show={this.state.closing} className={alertCls}>
{showIcon ? <Icon className="ant-alert-icon" type={iconType} /> : null}
<span className={prefixCls + '-message'}>{message}</span>

View File

@ -26,16 +26,13 @@ class AntScrollNumber extends React.Component {
if (this.state.count > this.lastCount) {
if (currentDigit >= lastDigit) {
return 10 + num;
} else {
return 20 + num;
}
} else {
if (currentDigit <= lastDigit) {
return 10 + num;
} else {
return num;
}
return 20 + num;
}
if (currentDigit <= lastDigit) {
return 10 + num;
}
return num;
}
componentWillReceiveProps(nextProps) {
@ -80,7 +77,7 @@ class AntScrollNumber extends React.Component {
style: {
transition: removeTransition && 'none',
transform: 'translate3d(0, ' + (-position * height) + 'px, 0)',
height: height,
height,
},
key: i,
}, this.renderNumberList());
@ -106,13 +103,12 @@ class AntScrollNumber extends React.Component {
props,
this.renderNumberElement()
);
} else {
return createElement(
this.props.component,
props,
props.count
);
}
return createElement(
this.props.component,
props,
props.count
);
}
}
@ -120,7 +116,7 @@ AntScrollNumber.defaultProps = {
prefixCls: 'ant-scroll-number',
count: null,
component: 'sup',
onAnimated: function() {},
onAnimated() {},
height: 18,
};

View File

@ -40,30 +40,32 @@ const Test = React.createClass({
});
},
render() {
return <div>
<Badge count={this.state.count}>
<a href="#" className="head-example"></a>
</Badge>
<Badge dot={this.state.show}>
<a href="#" className="head-example"></a>
</Badge>
<div style={{ marginTop: 10 }}>
<Button type="ghost" onClick={this.onNumberClick} style={{marginRight: 6}}>
切换数字显隐
</Button>
<Button type="ghost" onClick={this.onClick} style={{marginRight: 6}}>
切换红点显隐
</Button>
<ButtonGroup>
<Button type="ghost" onClick={this.decline}>
<Icon type="minus" />
return (
<div>
<Badge count={this.state.count}>
<a href="#" className="head-example"></a>
</Badge>
<Badge dot={this.state.show}>
<a href="#" className="head-example"></a>
</Badge>
<div style={{ marginTop: 10 }}>
<Button type="ghost" onClick={this.onNumberClick} style={{ marginRight: 6 }}>
切换数字显隐
</Button>
<Button type="ghost" onClick={this.increase}>
<Icon type="plus" />
<Button type="ghost" onClick={this.onClick} style={{ marginRight: 6 }}>
切换红点显隐
</Button>
</ButtonGroup>
<ButtonGroup>
<Button type="ghost" onClick={this.decline}>
<Icon type="minus" />
</Button>
<Button type="ghost" onClick={this.increase}>
<Icon type="plus" />
</Button>
</ButtonGroup>
</div>
</div>
</div>;
);
}
});

View File

@ -13,7 +13,7 @@ import { Badge } from 'antd';
ReactDOM.render(<div>
<Badge count={25} />
<Badge count={4} style={{backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9'}} />
<Badge count={109} style={{backgroundColor: '#87d068'}} />
<Badge count={4} style={{ backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9' }} />
<Badge count={109} style={{ backgroundColor: '#87d068' }} />
</div>, mountNode);
````

View File

@ -13,41 +13,53 @@ import { Breadcrumb } from 'antd';
const Apps = React.createClass({
render() {
return <ul className="app-list">
<li><Link to="/apps/1">应用1</Link></li>
<li><Link to="/apps/2">应用2</Link></li>
</ul>;
return (
<ul className="app-list">
<li>
<Link to="/apps/1">应用1</Link><Link to="/apps/1/detail">详情</Link>
</li>
<li>
<Link to="/apps/2">应用2</Link><Link to="/apps/2/detail">详情</Link>
</li>
</ul>
);
}
});
const Home = React.createClass({
render() {
return (<div>
<div className="demo-nav">
<Link to="/">首页</Link>
<Link to="/apps">应用列表</Link>
return (
<div>
<div className="demo-nav">
<Link to="/">首页</Link>
<Link to="/apps">应用列表</Link>
</div>
{this.props.children || 'Home'}
<div style={{
marginBottom: 15,
marginTop: 15,
paddingBottom: 15,
borderBottom: '1px dashed #ccc'
}}>
点击上面的导航切换页面,面包屑在下面:
</div>
<Breadcrumb {...this.props} />
</div>
{this.props.children || 'Home'}
<div style={{
marginBottom: 15,
marginTop: 15,
paddingBottom: 15,
borderBottom: '1px dashed #ccc'
}}>点击上面的导航切换页面,面包屑在下面:</div>
<Breadcrumb {...this.props} router={ReactRouter} />
</div>);
);
}
});
ReactDOM.render((
ReactDOM.render(
<Router>
<Route name="home" breadcrumbName="首页" path="/" component={Home}>
<Route name="apps" breadcrumbName="应用列表" path="apps" component={Apps}>
<Route name="app" breadcrumbName="应用:id" path=":id" />
<Route name="app" breadcrumbName="应用:id" path=":id">
<Route name="detail" breadcrumbName="详情" path="detail" />
</Route>
</Route>
</Route>
</Router>
), mountNode);
, mountNode);
````
<style>

View File

@ -21,10 +21,12 @@ const BreadcrumbItem = React.createClass({
if (typeof this.props.href === 'undefined') {
link = <span className={prefixCls + '-link'} {...this.props}>{children}</span>;
}
return <span>
{link}
<span className={prefixCls + '-separator'}>{separator}</span>
</span>;
return (
<span>
{link}
<span className={prefixCls + '-separator'}>{separator}</span>
</span>
);
}
});
@ -41,29 +43,35 @@ const Breadcrumb = React.createClass({
React.PropTypes.string,
React.PropTypes.element,
]),
router: React.PropTypes.object,
routes: React.PropTypes.array,
params: React.PropTypes.object
params: React.PropTypes.object,
},
render() {
let crumbs;
const { separator, prefixCls, router, routes, params, children } = this.props;
const ReactRouter = router;
if (routes && routes.length > 0 && ReactRouter) {
let Link = ReactRouter.Link;
crumbs = routes.map(function(route, i) {
const { separator, prefixCls, routes, params, children } = this.props;
if (routes && routes.length > 0) {
const paths = [];
crumbs = routes.map((route, i) => {
if (!route.breadcrumbName) {
return null;
}
const name = route.breadcrumbName.replace(/\:(.*)/g, function(replacement, key) {
const name = route.breadcrumbName.replace(/\:(.*)/g, (replacement, key) => {
return params[key] || replacement;
});
let link;
const path = route.path.indexOf('/') === 0 ? route.path : ('/' + route.path);
let path = route.path.replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(':' + key, params[key]);
});
if (path) {
paths.push(path);
}
if (i === routes.length - 1) {
link = <span>{name}</span>;
} else {
link = <Link to={path} params={params}>{name}</Link>;
link = <a href={'#/' + paths.join('/')}>{name}</a>;
}
return <BreadcrumbItem separator={separator} key={name}>{link}</BreadcrumbItem>;
});

View File

@ -29,7 +29,6 @@
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|-----------|-----------------------------------|-------------------|---------|--------|
| router | 可传入 react-router 的实例 | Object | | - |
| routes | router 的路由栈信息 | Array | | - |
| params | 路由的参数 | Object | | - |
| separator | 分隔符自定义 | String or Element | | '/' |

View File

@ -5,13 +5,13 @@ const prefix = 'ant-btn-group-';
export default class ButtonGroup extends React.Component {
render() {
const {size, className, ...others} = this.props;
const { size, className, ...others } = this.props;
// large => lg
// small => sm
const sizeCls = ({
'large': 'lg',
'small': 'sm'
large: 'lg',
small: 'sm',
})[size] || '';
const classes = classNames({

View File

@ -32,13 +32,13 @@ export default class Button extends React.Component {
}
render() {
const props = this.props;
const {type, shape, size, onClick, className, htmlType, children, ...others} = props;
const { type, shape, size, onClick, className, htmlType, children, ...others } = props;
// large => lg
// small => sm
const sizeCls = ({
'large': 'lg',
'small': 'sm'
large: 'lg',
small: 'sm',
})[size] || '';
const classes = classNames({
@ -52,9 +52,11 @@ export default class Button extends React.Component {
const kids = React.Children.map(children, insertSpace);
return <button {...others} type={htmlType || 'button'} className={classes} onClick={onClick}>
{kids}
</button>;
return (
<button {...others} type={htmlType || 'button'} className={classes} onClick={onClick}>
{kids}
</button>
);
}
}

View File

@ -19,9 +19,9 @@ ReactDOM.render(<div>
<Button type="primary">取消</Button>
</ButtonGroup>
<ButtonGroup>
<Button></Button>
<Button></Button>
<Button></Button>
<Button disabled></Button>
<Button disabled></Button>
<Button disabled></Button>
</ButtonGroup>
<ButtonGroup>
<Button type="primary"></Button>

View File

@ -23,24 +23,26 @@ const App = React.createClass({
this.setState({ iconLoading: true });
},
render() {
return <div>
<Button type="primary" size="large" loading>
加载中
</Button>
<Button type="primary" loading>
加载中
</Button>
<Button type="primary" size="small" loading>
加载中
</Button>
<br />
<Button type="primary" loading={this.state.loading} onClick={this.enterLoading}>
点击变加载
</Button>
<Button type="primary" loading={this.state.iconLoading} onClick={this.enterIconLoading}>
<Icon type="poweroff" />点击变加载
</Button>
</div>;
return (
<div>
<Button type="primary" size="large" loading>
加载中
</Button>
<Button type="primary" loading>
加载中
</Button>
<Button type="primary" size="small" loading>
加载中
</Button>
<br />
<Button type="primary" loading={this.state.loading} onClick={this.enterLoading}>
点击变加载
</Button>
<Button type="primary" loading={this.state.iconLoading} onClick={this.enterIconLoading}>
<Icon type="poweroff" />点击变加载
</Button>
</div>
);
}
});

View File

@ -1,20 +1,20 @@
import React, {PropTypes, Component} from 'react';
import {PREFIX_CLS} from './Constants';
import React, { PropTypes, Component } from 'react';
import { PREFIX_CLS } from './Constants';
import Select from '../select';
import {Group, Button} from '../radio';
import { Group, Button } from '../radio';
function noop() {}
class Header extends Component {
getYearSelectElement(year) {
const {yearSelectOffset, yearSelectTotal, locale, prefixCls, fullscreen} = this.props;
const { yearSelectOffset, yearSelectTotal, locale, prefixCls, fullscreen } = this.props;
const start = year - yearSelectOffset;
const end = start + yearSelectTotal;
const suffix = locale.year === '年' ? '年' : '';
const options = [];
for (let index = start; index < end; index++) {
options.push(<Option key={`${index}`}>{index + suffix}</Option> );
options.push(<Option key={`${index}`}>{index + suffix}</Option>);
}
return (
<Select
@ -32,7 +32,7 @@ class Header extends Component {
getMonthSelectElement(month) {
const props = this.props;
const months = props.locale.format.months;
const {prefixCls, fullscreen} = props;
const { prefixCls, fullscreen } = props;
const options = [];
for (let index = 0; index < 12; index++) {
@ -67,12 +67,9 @@ class Header extends Component {
this.props.onTypeChange(e.target.value);
}
render() {
const {type, value, prefixCls, locale} = this.props;
const { type, value, prefixCls, locale } = this.props;
const yearSelect = this.getYearSelectElement(value.getYear());
const monthSelect = type === 'date' ? this.getMonthSelectElement(value.getMonth()) : null;
const typeSwitch = (
<Group onChange={this.onTypeChange.bind(this)} value={type}>
<Button value="date">{locale.month}</Button>

View File

@ -19,6 +19,6 @@ function monthCellRender(value) {
ReactDOM.render(
<Calendar defaultValue={new Date('2010-10-10')}
dateCellRender={dateCellRender} monthCellRender={monthCellRender} />
dateCellRender={dateCellRender} monthCellRender={monthCellRender} />
, mountNode);
````

View File

@ -12,41 +12,45 @@ import { Calendar } from 'antd';
function getListData(value) {
let listData;
switch (value.getDayOfMonth()) {
case 8:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项.' }
]; break;
case 10:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项.' },
{ type: 'error', content: '这里是错误事项.' }
]; break;
case 15:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项好长啊。。....' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' }
]; break;
default:
case 8:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项.' }
]; break;
case 10:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项.' },
{ type: 'error', content: '这里是错误事项.' }
]; break;
case 15:
listData = [
{ type: 'warn', content: '这里是警告事项.' },
{ type: 'normal', content: '这里是普通事项好长啊。。....' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' },
{ type: 'error', content: '这里是错误事项.' }
]; break;
default:
}
return listData || [];
}
function dateCellRender(value) {
let listData = getListData(value);
return <ul className="events">
{listData.map((item, index) =>
<li key={index}>
<span className={`event-${item.type}`}></span>
{item.content}
</li>
)}
</ul>;
return (
<ul className="events">
{
listData.map((item, index) =>
<li key={index}>
<span className={`event-${item.type}`}></span>
{item.content}
</li>
)
}
</ul>
);
}

View File

@ -1,13 +1,13 @@
import React, {PropTypes, Component} from 'react';
import React, { PropTypes, Component } from 'react';
import GregorianCalendar from 'gregorian-calendar';
import zhCN from './locale/zh_CN';
import FullCalendar from 'rc-calendar/lib/FullCalendar';
import {PREFIX_CLS} from './Constants';
import { PREFIX_CLS } from './Constants';
import Header from './Header';
function noop () { return null; }
function noop() { return null; }
function zerofixed (v) {
function zerofixed(v) {
if (v < 10) return '0' + v;
return v + '';
}
@ -35,25 +35,29 @@ class Calendar extends Component {
monthCellRender(value, locale) {
const prefixCls = this.props.prefixCls;
const month = value.getMonth();
return <div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>
{locale.format.shortMonths[month]}
return (
<div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>
{locale.format.shortMonths[month]}
</div>
<div className={`${prefixCls}-content`}>
{this.props.monthCellRender(value)}
</div>
</div>
<div className={`${prefixCls}-content`}>
{this.props.monthCellRender(value)}
</div>
</div>;
);
}
dateCellRender(value) {
const prefixCls = this.props.prefixCls;
return <div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>
{zerofixed(value.getDayOfMonth())}
return (
<div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>
{zerofixed(value.getDayOfMonth())}
</div>
<div className={`${prefixCls}-content`}>
{this.props.dateCellRender(value)}
</div>
</div>
<div className={`${prefixCls}-content`}>
{this.props.dateCellRender(value)}
</div>
</div>;
);
}
setValue(value) {
if (!('value' in this.props) && this.state.value !== value) {
@ -70,8 +74,8 @@ class Calendar extends Component {
}
render() {
const props = this.props;
const {value, mode} = this.state;
const {locale, prefixCls, style, className, fullscreen} = props;
const { value, mode } = this.state;
const { locale, prefixCls, style, className, fullscreen } = props;
const type = (mode === 'year') ? 'month' : 'date';
let cls = className || '';

View File

@ -4,10 +4,10 @@ if (typeof window !== 'undefined') {
const matchMediaPolyfill = function matchMediaPolyfill() {
return {
matches: false,
addListener: function () {
addListener() {
},
removeListener() {
},
removeListener: function () {
}
};
};
window.matchMedia = window.matchMedia || matchMediaPolyfill;
@ -21,7 +21,7 @@ const AntCarousel = React.createClass({
getDefaultProps() {
return {
dots: true,
arrows: false
arrows: false,
};
},
render() {

View File

@ -0,0 +1,43 @@
# 基本
- order: 0
省市区级联。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
ReactDOM.render(
<Cascader options={options} onChange={onChange} />
, mountNode);
````

View File

@ -0,0 +1,43 @@
# 选择即改变
- order: 5
这种交互允许只选中父级选项。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
ReactDOM.render(
<Cascader options={options} onChange={onChange} changeOnSelect />
, mountNode);
````

View File

@ -0,0 +1,53 @@
# 可以自定义显示
- order: 1
切换按钮和结果分开。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
}],
}];
const CitySwitcher = React.createClass({
getInitialState() {
return {
text: '未选择',
};
},
onChange(value, selectedOptions) {
this.setState({
text: selectedOptions.map(o => o.label).join(', '),
});
},
render() {
return (
<span>
{this.state.text}
&nbsp;
<Cascader options={options} onChange={this.onChange}>
<a href="#">切换城市</a>
</Cascader>
</span>
);
},
});
ReactDOM.render(<CitySwitcher />, mountNode);
````

View File

@ -0,0 +1,43 @@
# 默认值
- order: 0
默认值通过数组的方式指定。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
ReactDOM.render(
<Cascader defaultValue={['zhejiang', 'hangzhou', 'xihu']} options={options} onChange={onChange} />
, mountNode);
````

View File

@ -0,0 +1,44 @@
# 禁用选项
- order: 4
通过指定 options 里的 `disabled` 字段。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
disabled: true,
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
ReactDOM.render(
<Cascader options={options} onChange={onChange} />
, mountNode);
````

View File

@ -0,0 +1,49 @@
# 移入展开
- order: 2
通过移入展开下级菜单,点击完成选择。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
// 只展示最后一项
function displayRender(label) {
return label[label.length - 1];
}
ReactDOM.render(
<Cascader options={options} expandTrigger="hover"
displayRender={displayRender} onChange={onChange} />
, mountNode);
````

View File

@ -0,0 +1,47 @@
# 大小
- order: 7
不同大小的级联选择器。
---
````jsx
import { Cascader } from 'antd';
const options = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
children: [{
value: 'xihu',
label: '西湖',
}],
}],
}, {
value: 'jiangsu',
label: '江苏',
children: [{
value: 'nanjing',
label: '南京',
children: [{
value: 'zhonghuamen',
label: '中华门',
}],
}],
}];
function onChange(value) {
console.log(value);
}
ReactDOM.render(
<div>
<Cascader size="large" options={options} onChange={onChange} /><br /><br />
<Cascader options={options} onChange={onChange} /><br /><br />
<Cascader size="small" options={options} onChange={onChange} /><br /><br />
</div>
, mountNode);
````

View File

@ -0,0 +1,110 @@
import React from 'react';
import Cascader from 'rc-cascader';
import Input from '../input';
import Icon from '../icon';
import arrayTreeFilter from 'array-tree-filter';
import classNames from 'classnames';
class AntCascader extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.value || props.defaultValue || [],
popupVisible: false,
};
[
'handleChange',
'handlePopupVisibleChange',
'setValue',
'getLabel',
'clearSelection',
].forEach((method) => this[method] = this[method].bind(this));
}
componentWillReceiveProps(nextProps) {
if ('value' in nextProps) {
this.setState({ value: nextProps.value || [] });
}
}
handleChange(value, selectedOptions) {
this.setValue(value, selectedOptions);
}
handlePopupVisibleChange(popupVisible) {
this.setState({ popupVisible });
this.props.onPopupVisibleChange(popupVisible);
}
setValue(value, selectedOptions = []) {
if (!('value' in this.props)) {
this.setState({ value });
}
this.props.onChange(value, selectedOptions);
}
getLabel() {
const { options, displayRender } = this.props;
const label = arrayTreeFilter(options, (o, level) => o.value === this.state.value[level])
.map(o => o.label);
return displayRender(label);
}
clearSelection(e) {
e.preventDefault();
e.stopPropagation();
this.setValue([]);
this.setState({ popupVisible: false });
}
render() {
const { prefixCls, children, placeholder, size, disabled, className } = this.props;
const sizeCls = classNames({
'ant-input-lg': size === 'large',
'ant-input-sm': size === 'small',
});
const clearIcon = this.state.value.length > 0 ?
<Icon type="cross-circle"
className={`${prefixCls}-picker-clear`}
onClick={this.clearSelection} /> : null;
const arrowCls = classNames({
[`${prefixCls}-picker-arrow`]: true,
[`${prefixCls}-picker-arrow-expand`]: this.state.popupVisible,
});
const pickerCls = classNames({
[className]: !!className,
[`${prefixCls}-picker`]: true,
[`${prefixCls}-picker-disabled`]: disabled,
});
return (
<Cascader {...this.props}
value={this.state.value}
popupVisible={this.state.popupVisible}
onPopupVisibleChange={this.handlePopupVisibleChange}
onChange={this.handleChange}>
{children ||
<span
{...this.props}
className={pickerCls}>
<Input placeholder={placeholder}
className={`${prefixCls}-input ant-input ${sizeCls}`}
style={{ width: '100%' }}
value={this.getLabel()}
disabled={disabled}
readOnly />
{clearIcon}
<Icon type="down" className={arrowCls} />
</span>
}
</Cascader>
);
}
}
AntCascader.defaultProps = {
prefixCls: 'ant-cascader',
placeholder: '请选择',
transitionName: 'slide-up',
onChange() {},
options: [],
displayRender(label) {
return label.join(' / ');
},
disabled: false,
onPopupVisibleChange() {},
};
export default AntCascader;

View File

@ -0,0 +1,36 @@
# Cascader
- category: Components
- chinese: 级联选择
- type: 表单
---
级联选择框。
## 何时使用
- 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。
- 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。
- 比起 Select 组件,可以在同一个浮层中完成选择,有较好的体验。
## API
```html
<Cascader options={options} onChange={onChange} />
```
| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| options | 可选项数据源 | object | - |
| defaultValue | 默认的选中项 | array |[] |
| value | 指定选中项 | array | - |
| onChange | 选择完成后的回调 | `function(value, selectedOptions)` | - |
| displayRender | 选择后展示的渲染函数 | `function(label)`` | `function(label) { return label.join(' / ') }` |
| style | 自定义样式 | string | - |
| className | 自定义类名 | string | - |
| popupClassName | 自定义浮层类名 | string | - |
| placeholder | 输入框占位文本 | string | '请选择' |
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
| disabled | 禁用 | boolean | false |

View File

@ -5,6 +5,7 @@ export default React.createClass({
getDefaultProps() {
return {
options: [],
defaultValue: [],
onChange() {},
};
},
@ -17,13 +18,13 @@ export default React.createClass({
getInitialState() {
const { value, defaultValue } = this.props;
return {
value: value || defaultValue || [],
value: value || defaultValue,
};
},
componentWillReceiveProps(nextProps) {
if ('value' in nextProps) {
this.setState({
value: nextProps.value,
value: nextProps.value || [],
});
}
},
@ -42,17 +43,19 @@ export default React.createClass({
},
render() {
const options = this.props.options;
return <div className="ant-checkbox-group">
{
options.map(option =>
<label className="ant-checkbox-group-item" key={option}>
<Checkbox disabled={this.props.disabled}
checked={this.state.value.indexOf(option) !== -1}
onChange={this.toggleOption.bind(this, option)} />
{option}
</label>
)
}
</div>;
return (
<div className="ant-checkbox-group">
{
options.map(option =>
<label className="ant-checkbox-group-item" key={option}>
<Checkbox disabled={this.props.disabled}
checked={this.state.value.indexOf(option) !== -1}
onChange={this.toggleOption.bind(this, option)} />
{option}
</label>
)
}
</div>
);
},
});

View File

@ -19,33 +19,35 @@ const App = React.createClass({
render() {
const label = (this.state.checked ? '选中' : '取消') + '-' +
(this.state.disabled ? '不可用' : '可用');
return <div>
<p style={{marginBottom: '20px'}}>
<label>
<Checkbox checked={this.state.checked}
disabled={this.state.disabled}
onChange={this.onChange} />
{label}
</label>
</p>
<p>
<Button type="primary" size="small"
onClick={this.toggleChecked}>
{!this.state.checked ? '选中' : '取消'}
</Button>
<Button style={{marginLeft: '10px'}}
type="primary" size="small"
onClick={this.toggleDisable}>
{!this.state.disabled ? '不可用' : '可用'}
</Button>
</p>
</div>;
return (
<div>
<p style={{ marginBottom: '20px' }}>
<label>
<Checkbox checked={this.state.checked}
disabled={this.state.disabled}
onChange={this.onChange} />
{label}
</label>
</p>
<p>
<Button type="primary" size="small"
onClick={this.toggleChecked}>
{!this.state.checked ? '选中' : '取消'}
</Button>
<Button style={{ marginLeft: '10px' }}
type="primary" size="small"
onClick={this.toggleDisable}>
{!this.state.disabled ? '不可用' : '可用'}
</Button>
</p>
</div>
);
},
toggleChecked() {
this.setState({checked: !this.state.checked});
this.setState({ checked: !this.state.checked });
},
toggleDisable() {
this.setState({disabled: !this.state.disabled});
this.setState({ disabled: !this.state.disabled });
},
onChange(e) {
console.log('checked = ', e.target.checked);

View File

@ -1,6 +1,5 @@
import Collapse from 'rc-collapse';
import React from 'react';
const prefixCls = 'ant-collapse';
class AntCollapse extends React.Component {
render() {
@ -9,7 +8,7 @@ class AntCollapse extends React.Component {
}
AntCollapse.defaultProps = {
prefixCls: prefixCls
prefixCls: 'ant-collapse',
};
AntCollapse.Panel = Collapse.Panel;

View File

@ -14,10 +14,12 @@ function animate(node, show, transitionName, done) {
}
// Fix safari flash bug
/*eslint-disable */
node.style.display = show ? 'block' : 'none';
/*eslint-enable */
velocity(node, transitionName, {
duration: 240,
complete: complete,
complete,
easing: 'easeInOutQuad'
});
return {

View File

@ -13,7 +13,11 @@ export default {
getFormatter() {
const formats = this.formats = this.formats || {};
const format = this.props.format;
let format = this.props.format;
// Remove time format text when has time-picker in calendar
if (this.props.showTime) {
format = format.replace('HH:mm:ss', '');
}
if (formats[format]) {
return formats[format];
}
@ -24,16 +28,14 @@ export default {
parseDateFromValue(value) {
if (value) {
if (typeof value === 'string') {
return this.getFormatter().parse(value, {locale: this.getLocale()});
return this.getFormatter().parse(value, { locale: this.getLocale() });
} else if (value instanceof Date) {
let date = new GregorianCalendar(this.getLocale());
date.setTime(+value);
return date;
}
} else if (value === null) {
return value;
}
return undefined;
return value;
},
// remove input readonly warning

View File

@ -25,7 +25,7 @@ export default React.createClass({
};
},
getInitialState() {
const {value, defaultValue} = this.props;
const { value, defaultValue } = this.props;
const start = (value && value[0]) || defaultValue[0];
const end = (value && value[1]) || defaultValue[1];
return {
@ -35,11 +35,12 @@ export default React.createClass({
]
};
},
mixins: [ PickerMixin ],
mixins: [PickerMixin],
componentWillReceiveProps(nextProps) {
if ('value' in nextProps) {
const start = this.parseDateFromValue(nextProps.value[0]);
const end = this.parseDateFromValue(nextProps.value[1]);
const value = nextProps.value || [];
const start = this.parseDateFromValue(value[0]);
const end = this.parseDateFromValue(value[1]);
this.setState({
value: [start, end]
});
@ -61,28 +62,31 @@ export default React.createClass({
let defaultCalendarValue = new GregorianCalendar(locale);
defaultCalendarValue.setTime(Date.now());
const {disabledDate, showTime, size, startPlaceholder, endPlaceholder,
transitionName, disabled, popupStyle, align, style} = this.props;
const { disabledDate, showTime, size, startPlaceholder, endPlaceholder,
transitionName, disabled, popupStyle, align, style } = this.props;
const state = this.state;
const timePicker = showTime
? <TimePicker prefixCls="ant-time-picker"
placeholder={locale.lang.timePlaceholder}
transitionName="slide-up" />
placeholder={locale.lang.timePlaceholder}
transitionName="slide-up" />
: null;
const calendarClassName = classNames({
['ant-calendar-time']: this.props.showTime,
});
const calendar = <RangeCalendar prefixCls="ant-calendar"
className={calendarClassName}
timePicker={timePicker}
disabledDate={disabledDate}
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
locale={locale.lang}
defaultValue={[defaultCalendarValue, defaultCalendarValue]}
showClear />;
const calendar = (
<RangeCalendar prefixCls="ant-calendar"
formatter={this.getFormatter()}
className={calendarClassName}
timePicker={timePicker}
disabledDate={disabledDate}
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
locale={locale.lang}
defaultValue={[defaultCalendarValue, defaultCalendarValue]}
showClear />
);
const pickerClass = classNames({
'ant-calendar-picker': true,
@ -109,7 +113,7 @@ export default React.createClass({
onClose={this.toggleOpen}
onChange={this.handleChange}>
{
({value}) => {
({ value }) => {
const start = value[0];
const end = value[1];
return (

View File

@ -11,7 +11,7 @@
````jsx
import { DatePicker } from 'antd';
const disabledDate = function(current) {
const disabledDate = function (current) {
// can not select days after today
return current && current.getTime() > Date.now();
};

View File

@ -14,8 +14,8 @@ function onChange(value) {
console.log('From: ', value[0], ', to: ', value[1]);
}
ReactDOM.render(<div>
<RangePicker style={{width: 184}} onChange={onChange} />
<RangePicker style={{ width: 184 }} onChange={onChange} />
<br />
<RangePicker showTime format="yyyy-MM-dd HH:mm:ss" onChange={onChange} />
<RangePicker showTime format="yyyy/MM/dd HH:mm:ss" onChange={onChange} />
</div>, mountNode);
````

View File

@ -35,16 +35,18 @@ const DateRange = React.createClass({
});
},
render() {
return <div>
<DatePicker disabledDate={this.disabledStartDate}
value={this.state.startValue}
placeholder="开始日期"
onChange={this.onChange.bind(this, 'startValue')} />
<DatePicker disabledDate={this.disabledEndDate}
value={this.state.endValue}
placeholder="结束日期"
onChange={this.onChange.bind(this, 'endValue')} />
</div>;
return (
<div>
<DatePicker disabledDate={this.disabledStartDate}
value={this.state.startValue}
placeholder="开始日期"
onChange={this.onChange.bind(this, 'startValue')} />
<DatePicker disabledDate={this.disabledEndDate}
value={this.state.endValue}
placeholder="结束日期"
onChange={this.onChange.bind(this, 'endValue')} />
</div>
);
}
});

View File

@ -14,6 +14,6 @@ function onChange(value) {
}
ReactDOM.render(
<DatePicker showTime format="yyyy-MM-dd HH:mm:ss" onChange={onChange} style={{width: 160}} />
<DatePicker showTime format="yyyy-MM-dd HH:mm:ss" onChange={onChange} style={{ width: 160 }} />
, mountNode);
````

View File

@ -3,7 +3,7 @@
- order: 4
- hidden: true
和 [时间选择框](/components/timepicer) 配合使用。
和 [时间选择框](/components/time-picker) 配合使用。
---
@ -37,10 +37,12 @@ const DateTimePicker = React.createClass({
}
},
render() {
return <div>
<DatePicker onChange={this.handleChange.bind(null, 'date')} />
<TimePicker onChange={this.handleChange.bind(null, 'time')} />
</div>;
return (
<div>
<DatePicker onChange={this.handleChange.bind(null, 'date')} />
<TimePicker onChange={this.handleChange.bind(null, 'time')} />
</div>
);
}
});

View File

@ -30,7 +30,7 @@ function createPicker(TheCalendar, defaultFormat) {
value: this.parseDateFromValue(this.props.value || this.props.defaultValue)
};
},
mixins: [ PickerMixin ],
mixins: [PickerMixin],
componentWillReceiveProps(nextProps) {
if ('value' in nextProps) {
this.setState({
@ -58,10 +58,12 @@ function createPicker(TheCalendar, defaultFormat) {
const timePicker = this.props.showTime
? <TimePicker prefixCls="ant-time-picker"
placeholder={locale.lang.timePlaceholder}
transitionName="slide-up" />
placeholder={locale.lang.timePlaceholder}
transitionName="slide-up" />
: null;
const disabledTime = this.props.showTime ? this.props.disabledTime : null;
const calendarClassName = classNames({
['ant-calendar-time']: this.props.showTime,
['ant-calendar-month']: MonthCalendar === TheCalendar,
@ -69,7 +71,9 @@ function createPicker(TheCalendar, defaultFormat) {
const calendar = (
<TheCalendar
formatter={this.getFormatter()}
disabledDate={this.props.disabledDate}
disabledTime={disabledTime}
locale={locale.lang}
timePicker={timePicker}
defaultValue={defaultCalendarValue}
@ -92,35 +96,36 @@ function createPicker(TheCalendar, defaultFormat) {
pickerClass += ' ant-calendar-picker-open';
}
return <span className={pickerClass}>
<DatePicker
transitionName={this.props.transitionName}
disabled={this.props.disabled}
calendar={calendar}
value={this.state.value}
prefixCls="ant-calendar-picker-container"
style={this.props.popupStyle}
align={this.props.align}
onOpen={this.toggleOpen}
onClose={this.toggleOpen}
onChange={this.handleChange}>
{
({value}) => {
return (
<span>
<input disabled={this.props.disabled}
onChange={this.handleInputChange}
value={value && this.getFormatter().format(value)}
placeholder={placeholder}
style={this.props.style}
className={'ant-calendar-picker-input ant-input' + sizeClass}/>
<span className="ant-calendar-picker-icon"/>
</span>
);
return (
<span className={pickerClass}>
<DatePicker transitionName={this.props.transitionName}
disabled={this.props.disabled}
calendar={calendar}
value={this.state.value}
prefixCls="ant-calendar-picker-container"
style={this.props.popupStyle}
align={this.props.align}
onOpen={this.toggleOpen}
onClose={this.toggleOpen}
onChange={this.handleChange}>
{
({ value }) => {
return (
<span>
<input disabled={this.props.disabled}
onChange={this.handleInputChange}
value={value && this.getFormatter().format(value)}
placeholder={placeholder}
style={this.props.style}
className={'ant-calendar-picker-input ant-input' + sizeClass}/>
<span className="ant-calendar-picker-icon"/>
</span>
);
}
}
}
</DatePicker>
</span>;
</DatePicker>
</span>
);
}
});
}

View File

@ -25,9 +25,9 @@
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | string | 无 |
| defaultValue | 默认日期 | string | 无 |
| format | 展示的日期格式 | string | "yyyy-MM-dd" |
| value | 日期 | string or Date | 无 |
| defaultValue | 默认日期 | string or Date | 无 |
| format | 展示的日期格式,配置参考 [GregorianCalendarFormat](https://github.com/yiminghe/gregorian-calendar-format) | string | "yyyy-MM-dd" |
| disabledDate | 不可选择的日期 | function | 无 |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(Date value) | 无 |
| disabled | 禁用 | bool | false |
@ -42,8 +42,8 @@
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | [string, string] | 无 |
| defaultValue | 默认日期 | [string, string] | 无 |
| value | 日期 | [string|Date, string|Date] | 无 |
| defaultValue | 默认日期 | [string|Date, string|Date] | 无 |
| format | 展示的日期格式 | string | "yyyy-MM-dd HH:mm:ss" |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function([Date start, Date end]) | 无 |

View File

@ -9,17 +9,19 @@
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const menu = <Menu>
<Menu.Item>
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.tmall.com/">第三个菜单项</a>
</Menu.Item>
</Menu>;
const menu = (
<Menu>
<Menu.Item>
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.tmall.com/">第三个菜单项</a>
</Menu.Item>
</Menu>
);
ReactDOM.render(
<Dropdown overlay={menu}>

View File

@ -10,21 +10,23 @@
import { Menu, Dropdown } from 'antd';
const DropdownButton = Dropdown.Button;
const menu = <Menu>
<Menu.Item>
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.tmall.com/">第三个菜单项</a>
</Menu.Item>
</Menu>;
const menu = (
<Menu>
<Menu.Item>
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" href="http://www.tmall.com/">第三个菜单项</a>
</Menu.Item>
</Menu>
);
ReactDOM.render(
<DropdownButton overlay={menu} type="primary">
某功能按钮
</DropdownButton>
<DropdownButton overlay={menu} type="primary">
某功能按钮
</DropdownButton>
, mountNode);
````

View File

@ -8,15 +8,17 @@
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const onClick = function({key}) {
const onClick = function ({ key }) {
console.log('点击了菜单' + key);
};
const menu = <Menu onClick={onClick}>
<Menu.Item key="1">第一个菜单项</Menu.Item>
<Menu.Item key="2">第二个菜单项</Menu.Item>
<Menu.Item key="3">第三个菜单项</Menu.Item>
</Menu>;
const menu = (
<Menu onClick={onClick}>
<Menu.Item key="1">第一个菜单项</Menu.Item>
<Menu.Item key="2">第二个菜单项</Menu.Item>
<Menu.Item key="3">第三个菜单项</Menu.Item>
</Menu>
);
ReactDOM.render(
<Dropdown overlay={menu}>

View File

@ -9,16 +9,18 @@
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const menu = <Menu>
<Menu.Item key="0">
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item key="1">
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Divider/>
<Menu.Item key="3" disabled>第三个菜单项(不可用)</Menu.Item>
</Menu>;
const menu = (
<Menu>
<Menu.Item key="0">
<a target="_blank" href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item key="1">
<a target="_blank" href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Divider/>
<Menu.Item key="3" disabled>第三个菜单项(不可用)</Menu.Item>
</Menu>
);
ReactDOM.render(
<Dropdown overlay={menu}>

View File

@ -10,14 +10,16 @@
import { Menu, Dropdown, Icon } from 'antd';
const SubMenu = Menu.SubMenu;
const menu = <Menu>
<Menu.Item>第一个菜单项</Menu.Item>
<Menu.Item>第二个菜单项</Menu.Item>
<SubMenu title="子菜单">
<Menu.Item>第三个菜单项</Menu.Item>
<Menu.Item>第四个菜单项</Menu.Item>
</SubMenu>
</Menu>;
const menu = (
<Menu>
<Menu.Item>第一个菜单项</Menu.Item>
<Menu.Item>第二个菜单项</Menu.Item>
<SubMenu title="子菜单">
<Menu.Item>第三个菜单项</Menu.Item>
<Menu.Item>第四个菜单项</Menu.Item>
</SubMenu>
</Menu>
);
ReactDOM.render(
<Dropdown overlay={menu}>

View File

@ -9,16 +9,18 @@
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const menu = <Menu>
<Menu.Item key="0">
<a href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item key="1">
<a href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Divider/>
<Menu.Item key="3">第三个菜单项</Menu.Item>
</Menu>;
const menu = (
<Menu>
<Menu.Item key="0">
<a href="http://www.alipay.com/">第一个菜单项</a>
</Menu.Item>
<Menu.Item key="1">
<a href="http://www.taobao.com/">第二个菜单项</a>
</Menu.Item>
<Menu.Divider/>
<Menu.Item key="3">第三个菜单项</Menu.Item>
</Menu>
);
ReactDOM.render(<div>
<Dropdown overlay={menu} trigger={['click']}>

View File

@ -17,20 +17,22 @@ const align = {
export default React.createClass({
getDefaultProps() {
return {
align: align,
align,
type: 'default',
};
},
render() {
return <ButtonGroup className="ant-dropdown-button">
<Button type={this.props.type}>
{this.props.children}
</Button>
<Dropdown {...this.props}>
return (
<ButtonGroup className="ant-dropdown-button">
<Button type={this.props.type}>
<Icon type="down" />
{this.props.children}
</Button>
</Dropdown>
</ButtonGroup>;
<Dropdown {...this.props}>
<Button type={this.props.type}>
<Icon type="down" />
</Button>
</Dropdown>
</ButtonGroup>
);
}
});

View File

@ -2,13 +2,13 @@ import React from 'react';
import Dropdown from 'rc-dropdown';
export default React.createClass({
getDefaultProps: function () {
getDefaultProps() {
return {
transitionName: 'slide-up',
prefixCls: 'ant-dropdown',
};
},
render: function () {
render() {
const { overlay, ...otherProps } = this.props;
const menu = React.cloneElement(overlay, {
openTransitionName: 'zoom-big',

View File

@ -2,6 +2,12 @@ import React from 'react';
import classNames from 'classnames';
class Form extends React.Component {
getChildContext() {
return {
form: this.props.form,
};
}
render() {
const { prefixCls, className } = this.props;
const formClassName = classNames({
@ -22,6 +28,7 @@ Form.propTypes = {
prefixCls: React.PropTypes.string,
horizontal: React.PropTypes.bool,
inline: React.PropTypes.bool,
form: React.PropTypes.object,
children: React.PropTypes.any,
onSubmit: React.PropTypes.func,
};
@ -30,4 +37,8 @@ Form.defaultProps = {
prefixCls: 'ant-form',
};
Form.childContextTypes = {
form: React.PropTypes.object,
};
module.exports = Form;

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames';
function prefixClsFn(prefixCls, ...args) {
return args.map((s)=> {
return args.map((s) => {
return prefixCls + '-' + s;
}).join(' ');
}
@ -12,37 +12,76 @@ class FormItem extends React.Component {
if (!colDef) {
return '';
}
const {span, offset} = colDef;
const { span, offset } = colDef;
const col = span ? 'col-' + span : '';
const offsetCol = offset ? ' col-offset-' + offset : '';
return col + offsetCol;
}
getHelpMsg() {
const context = this.context;
const props = this.props;
if (props.help === undefined && context.form) {
return (context.form.getFieldError(this.getId()) || []).join(', ');
}
return props.help;
}
getId() {
return this.props.children.props && this.props.children.props.id;
}
getMeta() {
return this.props.children.props && this.props.children.props.__meta;
}
renderHelp() {
const prefixCls = this.props.prefixCls;
const props = this.props;
const prefixCls = props.prefixCls;
const help = this.getHelpMsg();
return (
<div className={this.props.help ? prefixClsFn(prefixCls, 'explain') : ''} key="help">
{this.props.help}
<div className={!!help ? prefixClsFn(prefixCls, 'explain') : ''} key="help">
{ help }
</div>
);
}
renderValidateWrapper(c1, c2) {
getValidateStatus() {
const { isFieldValidating, getFieldError, getFieldValue } = this.context.form;
const field = this.getId();
if (isFieldValidating(field)) {
return 'validating';
} else if (!!getFieldError(field)) {
return 'error';
} else if (getFieldValue(field) !== undefined) {
return 'success';
}
}
renderValidateWrapper(c1, c2, c3) {
let classes = '';
if (this.props.validateStatus) {
const form = this.context.form;
const props = this.props;
const validateStatus = (props.validateStatus === undefined && form) ?
this.getValidateStatus() :
props.validateStatus;
if (validateStatus) {
classes = classNames(
{
'has-feedback': this.props.hasFeedback,
'has-success': this.props.validateStatus === 'success',
'has-warning': this.props.validateStatus === 'warning',
'has-error': this.props.validateStatus === 'error',
'is-validating': this.props.validateStatus === 'validating',
'has-feedback': props.hasFeedback,
'has-success': validateStatus === 'success',
'has-warning': validateStatus === 'warning',
'has-error': validateStatus === 'error',
'is-validating': validateStatus === 'validating',
}
);
}
return (
<div className={classes}>
{c1}{c2}
<div className={this.props.prefixCls + '-item-control ' + classes}>
{c1}{c2}{c3}
</div>
);
}
@ -56,59 +95,60 @@ class FormItem extends React.Component {
);
}
renderLabel() {
const labelCol = this.props.labelCol;
const required = this.props.required ? 'required' : '';
isRequired() {
if (this.context.form) {
const meta = this.getMeta() || {};
const validate = (meta.validate || []);
return this.props.label ? (
<label htmlFor={this.props.id} className={this._getLayoutClass(labelCol)} required={required} key="label">
{this.props.label}
return validate.filter((item) => !!item.rules).some((item) => {
return item.rules.some((rule) => rule.required);
});
}
return false;
}
renderLabel() {
const props = this.props;
const labelCol = props.labelCol;
const required = props.required === undefined ?
this.isRequired() :
props.required;
return props.label ? (
<label htmlFor={props.id || this.getId()} className={this._getLayoutClass(labelCol)} required={required} key="label">
{props.label}
</label>
) : null;
}
renderChildren() {
const props = this.props;
const children = React.Children.map(props.children, (child) => {
if (typeof child.type === 'function' && !child.props.size) {
return React.cloneElement(child, { size: 'large' });
}
return child;
});
return [
this.renderLabel(),
this.renderWrapper(
this.renderValidateWrapper(
this.props.children,
this.renderHelp()
children,
this.renderHelp(),
props.extra
)
),
];
}
// `.ant-form-item-compact`
_isCompact(children) {
const compactControls = ['checkbox', 'radio', 'radio-group', 'static', 'file'];
let isCompact = false;
if (!Array.isArray(children)) {
children = [children];
}
children.map((child) => {
const type = child.props && child.props.type;
let prefixCls = child.props && child.props.prefixCls;
prefixCls = prefixCls ? prefixCls.substring(prefixCls.indexOf('-') + 1) : '';
if ((type && compactControls.indexOf(type) > -1) || (prefixCls && compactControls.indexOf(prefixCls) > -1)) {
isCompact = true;
} else if (child.props && typeof child.props.children === 'object') {
isCompact = this._isCompact(child.props.children);
}
});
return isCompact;
}
renderFormItem(children) {
const props = this.props;
const prefixCls = props.prefixCls;
const itemClassName = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-compact`]: this._isCompact(props.children),
[`${prefixCls}-item-with-help`]: !!props.help,
[`${prefixCls}-item-with-help`]: !!this.getHelpMsg(),
[`${props.className}`]: !!props.className,
};
return (
@ -128,18 +168,22 @@ FormItem.propTypes = {
prefixCls: React.PropTypes.string,
label: React.PropTypes.node,
labelCol: React.PropTypes.object,
help: React.PropTypes.node,
help: React.PropTypes.oneOfType([React.PropTypes.node, React.PropTypes.bool]),
validateStatus: React.PropTypes.oneOf(['', 'success', 'warning', 'error', 'validating']),
hasFeedback: React.PropTypes.bool,
wrapperCol: React.PropTypes.object,
className: React.PropTypes.string,
id: React.PropTypes.string,
children: React.PropTypes.node,
};
FormItem.defaultProps = {
hasFeedback: false,
required: false,
prefixCls: 'ant-form',
};
FormItem.contextTypes = {
form: React.PropTypes.object,
};
module.exports = FormItem;

View File

@ -1,8 +1,8 @@
function merge() {
const ret = {};
const args = [].slice.call(arguments, 0);
args.forEach((a)=> {
Object.keys(a).forEach((k)=> {
args.forEach((a) => {
Object.keys(a).forEach((k) => {
ret[k] = a[k];
});
});

View File

@ -18,66 +18,66 @@ ReactDOM.render(
<Col span="8">
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="较长搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
</Col>
<Col span="8">
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="较长搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
</Col>
<Col span="8">
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="较长搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
<FormItem
label="搜索名称:"
labelCol={{span: 10}}
wrapperCol={{span: 14}}>
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}>
<Input placeholder="请输入搜索名称" />
</FormItem>
</Col>
</Row>
<Row>
<Col span="8" offset="16" style={{textAlign: 'right'}}>
<Col span="8" offset="16" style={{ textAlign: 'right' }}>
<Button type="primary" htmlType="submit">搜索</Button>
<Button type="ghost">清除条件</Button>
</Col>

View File

@ -9,15 +9,15 @@
---
````jsx
import {Row, Col, Button, Input, Form} from 'antd';
import { Row, Col, Button, Input, Form } from 'antd';
const FormItem = Form.Item;
ReactDOM.render(
<Form horizontal>
<FormItem
label="单独禁用输入框:"
labelCol={{span:5}}
wrapperCol={{span:12}}>
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}>
<Input defaultValue="我是禁用的" disabled />
</FormItem>
@ -26,16 +26,16 @@ ReactDOM.render(
<FormItem
id="userName"
label="用户名:"
labelCol={{span:5}}
wrapperCol={{span:12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
required>
<p className="ant-form-text">大眼萌 minion</p>
</FormItem>
<FormItem
id="password"
label="密码:"
labelCol={{span:5}}
wrapperCol={{span:12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
required>
<Input type="password" defaultValue="123456" id="password" />
</FormItem>

View File

@ -9,7 +9,7 @@
---
````jsx
import {Form, Input, Select, Checkbox, Radio} from 'antd';
import { Form, Input, Select, Checkbox, Radio } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const RadioGroup = Radio.Group;
@ -23,25 +23,25 @@ ReactDOM.render(
<FormItem
id="control-input"
label="输入框:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}>
<Input id="control-input" placeholder="Please enter..." />
</FormItem>
<FormItem
id="control-textarea"
label="文本域:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}>
<Input type="textarea" id="control-textarea" rows="3" />
</FormItem>
<FormItem
id="select"
label="Select 选择器:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}>
<Select id="select" size="large" defaultValue="lucy" style={{width:200}} onChange={handleSelectChange}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}>
<Select id="select" size="large" defaultValue="lucy" style={{ width: 200 }} onChange={handleSelectChange}>
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
<Option value="disabled" disabled>disabled</Option>
@ -51,8 +51,8 @@ ReactDOM.render(
<FormItem
label="Checkbox 多选框:"
labelCol={{span: 6}}
wrapperCol={{span: 18}} >
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }} >
<label className="ant-checkbox-vertical">
<Checkbox />选项一
</label>
@ -66,8 +66,8 @@ ReactDOM.render(
<FormItem
label="Checkbox 多选框:"
labelCol={{span: 6}}
wrapperCol={{span: 18}} >
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }} >
<label className="ant-checkbox-inline">
<Checkbox />选项一
</label>
@ -81,8 +81,8 @@ ReactDOM.render(
<FormItem
label="Radio 单选框:"
labelCol={{span: 6}}
wrapperCol={{span: 18}} >
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }} >
<RadioGroup value="b">
<Radio value="a">A</Radio>
<Radio value="b">B</Radio>

View File

@ -2,84 +2,57 @@
- order: 2
示例展示了如何通过使用 `Form.ValueMixin` 来获取和更新表单提交的数值。
**注意:** 1需要为每个输入控件声明 `name` 属性2ES6 语法 [不支持 `mixins`](https://facebook.github.io/react/docs/reusable-components.html#no-mixins)
示例展示了如何通过使用 `Form.create` 来获取和更新表单提交的数值。
---
````jsx
import {Form, Input, Button, Checkbox, Radio, Row, Col, message} from 'antd';
import { Form, Input, Button, Checkbox, Radio, Row, Col } from 'antd';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const Demo = React.createClass({
mixins: [Form.ValueMixin],
getInitialState() {
return {
formData: {
userName: '大眼萌 minion',
password: undefined,
gender: 'male',
remark: undefined,
agreement: undefined,
}
};
},
let Demo = React.createClass({
handleSubmit(e) {
e.preventDefault();
message.success('收到表单值~~~ ' + JSON.stringify(this.state.formData, function(k, v) {
if (typeof v === 'undefined') {
return '';
}
return v;
}));
console.log('收到表单值:', this.props.form.getFieldsValue());
},
render() {
const formData = this.state.formData;
const { getFieldProps } = this.props.form;
return (
<Form horizontal onSubmit={this.handleSubmit}>
<FormItem
label="用户名:"
labelCol={{span: 6}}
wrapperCol={{span: 6}}
required>
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}>
<p className="ant-form-text" id="userName" name="userName">大眼萌 minion</p>
</FormItem>
<FormItem
id="password"
label="密码:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}
required>
<Input type="password" id="password" name="password" placeholder="请输入密码" value={formData.password} onChange={this.setValue.bind(this, 'password')} />
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}>
<Input type="password" {...getFieldProps('pass')} placeholder="请输入密码" />
</FormItem>
<FormItem
label="您的性别:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}
required>
<RadioGroup name="gender" value={formData.gender} onChange={this.setValue.bind(this, 'gender')} >
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}d>
<RadioGroup {...getFieldProps('gender', { initialValue: 'female' })}>
<Radio value="male">男的</Radio>
<Radio value="female">女的</Radio>
</RadioGroup>
</FormItem>
<FormItem
id="remark"
label="备注:"
labelCol={{span: 6}}
wrapperCol={{span: 14}}
required
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
help="随便写点什么">
<Input type="textarea" placeholder="随便写" id="remark" name="remark" value={formData.remark} onChange={this.setValue.bind(this, 'remark')} />
<Input type="textarea" placeholder="随便写" {...getFieldProps('remark')} />
</FormItem>
<FormItem
wrapperCol={{span: 14, offset: 6}} >
wrapperCol={{ span: 14, offset: 6 }} >
<label>
<Checkbox name="agreement" value={formData.agreement} onChange={this.setValue.bind(this, 'agreement')} /> 同意
<Checkbox {...getFieldProps('agreement')} />同意
</label>
</FormItem>
<Row>
@ -92,5 +65,7 @@ const Demo = React.createClass({
}
});
Demo = Form.create()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -7,49 +7,33 @@
---
````jsx
import {Form, Input, Button, Checkbox, message} from 'antd';
import { Form, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
const Demo = React.createClass({
mixins: [Form.ValueMixin],
getInitialState() {
return {
formData: {
userName: undefined,
password: undefined,
agreement: undefined,
}
};
},
let Demo = React.createClass({
handleSubmit(e) {
e.preventDefault();
message.success('收到表单值~~~ ' + JSON.stringify(this.state.formData, function(k, v) {
if (typeof v === 'undefined') {
return '';
}
return v;
}));
console.log('收到表单值:', this.props.form.getFieldsValue());
},
render() {
const formData = this.state.formData;
const { getFieldProps } = this.props.form;
return (
<Form inline onSubmit={this.handleSubmit}>
<FormItem
id="userName"
label="账户:">
<Input placeholder="请输入账户名" id="userName" name="userName" onChange={this.setValue.bind(this, 'userName')} value={formData.userName} />
<Input placeholder="请输入账户名"
{...getFieldProps('userName')} />
</FormItem>
<FormItem
id="password"
label="密码:">
<Input type="password" placeholder="请输入密码" id="password" name="password" onChange={this.setValue.bind(this, 'password')} value={formData.password} />
<Input type="password" placeholder="请输入密码"
{...getFieldProps('password')} />
</FormItem>
<FormItem>
<label className="ant-checkbox-inline">
<Checkbox name="agreement" value={formData.agreement} onChange={this.setValue.bind(this, 'agreement')} /> 记住我
<Checkbox
{...getFieldProps('agreement')} />记住我
</label>
</FormItem>
<Button type="primary" htmlType="submit">登录</Button>
@ -58,5 +42,7 @@ const Demo = React.createClass({
}
});
Demo = Form.create()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -7,7 +7,7 @@
---
````jsx
import {Form, Input, Select, Row, Col} from 'antd';
import { Form, Input, Select, Row, Col } from 'antd';
const FormItem = Form.Item;
const InputGroup = Input.Group;
const Option = Select.Option;
@ -16,26 +16,26 @@ ReactDOM.render(
<Form horizontal>
<FormItem
label="标签输入框:"
labelCol={{span: 6}}
wrapperCol={{span: 16}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<Input addonBefore="Http://" defaultValue="mysite.com" id="site1"/>
</FormItem>
<FormItem
label="标签输入框:"
labelCol={{span: 6}}
wrapperCol={{span: 16}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<Input addonBefore="Http://" addonAfter=".com" defaultValue="mysite" id="site2"/>
</FormItem>
<FormItem
label="select 标签输入框:"
labelCol={{span: 6}}
wrapperCol={{span: 16}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<InputGroup>
<Input id="site4" placeholder="www.mysite" />
<div className="ant-input-group-wrap">
<Select defaultValue=".com" style={{width:70}}>
<Select defaultValue=".com" style={{ width: 70 }}>
<Option value=".com">.com</Option>
<Option value=".jp">.jp</Option>
<Option value=".cn">.cn</Option>
@ -47,8 +47,8 @@ ReactDOM.render(
<FormItem
label="输入身份证:"
labelCol={{span: 6}}
wrapperCol={{span: 16}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<InputGroup>
<Col span="6">
<Input id="certNo1" />
@ -67,8 +67,8 @@ ReactDOM.render(
<FormItem
label="电话号码:"
labelCol={{span: 6}}
wrapperCol={{span: 16}}>
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<Row>
<Col span="4">
<Input id="tel1" defaultValue="086" />

View File

@ -10,7 +10,7 @@
````jsx
import {Row, Col, Input} from 'antd';
import { Row, Col, Input } from 'antd';
const InputGroup = Input.Group;
ReactDOM.render(

View File

@ -7,67 +7,43 @@
---
````jsx
import { Form, Select, InputNumber, DatePicker, Switch,
Slider, Button, message, Row, Col, Upload, Icon } from 'antd';
import { Form, Select, InputNumber, DatePicker, TimePicker, Switch, Radio,
Slider, Button, Row, Col, Upload, Icon } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const Demo = React.createClass({
mixins: [Form.ValueMixin],
getInitialState() {
return {
formData: {
inputNumber: undefined,
static: '唧唧复唧唧木兰当户织呀',
switch: undefined,
slider: undefined,
select: undefined,
startDate: undefined,
endDate: undefined,
}
};
},
handleUpload(info) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(info.file.name + ' 上传成功。');
} else if (info.file.status === 'error') {
message.error(info.file.name + ' 上传失败。');
}
},
let Demo = React.createClass({
handleSubmit(e) {
e.preventDefault();
message.success('收到表单值~~~ ' + JSON.stringify(this.state.formData, function(k, v) {
if (typeof v === 'undefined') {
return '';
}
return v;
}));
console.log('收到表单值:', this.props.form.getFieldsValue());
},
normFile(e) {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
},
render() {
const formData = this.state.formData;
const { getFieldProps } = this.props.form;
return (
<Form horizontal onSubmit={this.handleSubmit} >
<FormItem
label="InputNumber 数字输入框:"
labelCol={{span: 8}}
wrapperCol={{span: 10}}
required>
<InputNumber size="large" min={1} max={10} style={{width:100}} defaultValue={3} name="inputNumber" onChange={this.setValue.bind(this, 'inputNumber')} value={formData.inputNumber} />
labelCol={{ span: 8 }}
wrapperCol={{ span: 10 }}>
<InputNumber min={1} max={10} style={{ width: 100 }}
{...getFieldProps('inputNumber', { initialValue: 3 })} />
<span className="ant-form-text"> 台机器</span>
</FormItem>
<FormItem
label="我是标题:"
labelCol={{span: 8}}
wrapperCol={{span: 10}}
required>
labelCol={{ span: 8 }}
wrapperCol={{ span: 10 }}>
<p className="ant-form-text" id="static" name="static">唧唧复唧唧木兰当户织呀</p>
<p className="ant-form-text">
<a href="#">链接文字</a>
@ -76,26 +52,27 @@ const Demo = React.createClass({
<FormItem
label="Switch 开关:"
labelCol={{span: 8}}
wrapperCol={{span: 10}}
labelCol={{ span: 8 }}
wrapperCol={{ span: 10 }}
required>
<Switch name="switch" onChange={this.setValue.bind(this, 'switch')} value={formData.switch} />
<Switch {...getFieldProps('switch')} />
</FormItem>
<FormItem
label="Slider 滑动输入条:"
labelCol={{span: 8}}
wrapperCol={{span: 10}}
labelCol={{ span: 8 }}
wrapperCol={{ span: 10 }}
required>
<Slider marks={['A', 'B', 'C', 'D', 'E', 'F', 'G']} name="slider" onChange={this.setValue.bind(this, 'slider')} />
<Slider marks={['A', 'B', 'C', 'D', 'E', 'F', 'G']} {...getFieldProps('slider')}/>
</FormItem>
<FormItem
label="Select 选择器:"
labelCol={{span: 8}}
wrapperCol={{span: 16}}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
required>
<Select size="large" defaultValue="lucy" style={{width:200}} name="select" onChange={this.setValue.bind(this, 'select')} value={formData.select}>
<Select style={{ width: 200 }}
{...getFieldProps('select')}>
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
<Option value="disabled" disabled>disabled</Option>
@ -105,30 +82,54 @@ const Demo = React.createClass({
<FormItem
label="DatePicker 日期选择框:"
labelCol={{span: 8}}
labelCol={{ span: 8 }}
required>
<Col span="6">
<DatePicker name="startDate" onChange={this.setValue.bind(this, 'startDate')} value={formData.startDate} />
<DatePicker {...getFieldProps('startDate')}/>
</Col>
<Col span="1">
<p className="ant-form-split">-</p>
</Col>
<Col span="6">
<DatePicker name="endDate" onChange={this.setValue.bind(this, 'endDate')} value={formData.endDate} />
<DatePicker {...getFieldProps('endDate')} />
</Col>
</FormItem>
<FormItem
label="TimePicker 时间选择器:"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
required>
<TimePicker {...getFieldProps('time')}/>
</FormItem>
<FormItem
label="选项:"
labelCol={{ span: 8 }}>
<RadioGroup {...getFieldProps('rg')}>
<RadioButton value="a">选项一</RadioButton>
<RadioButton value="b">选项二</RadioButton>
<RadioButton value="c">选项三</RadioButton>
</RadioGroup>
</FormItem>
<FormItem
label="logo图"
labelCol={{span: 8}}
wrapperCol={{span: 16}}
help="提示信息要长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长">
<Upload name="logo" action="/upload.do" listType="picture" onChange={this.handleUpload}>
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
help="提示信息要长长长长长长长长长长长长长长">
<Upload name="logo" action="/upload.do" listType="picture" onChange={this.handleUpload}
{...getFieldProps('upload', {
valuePropName: 'fileList',
normalize: this.normFile
})}
>
<Button type="ghost">
<Icon type="upload" /> 点击上传
</Button>
</Upload>
</FormItem>
<Row>
<Row style={{ marginTop: 24 }}>
<Col span="16" offset="8">
<Button type="primary" htmlType="submit">确定</Button>
</Col>
@ -138,5 +139,7 @@ const Demo = React.createClass({
}
});
Demo = Form.create()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -43,19 +43,21 @@ const SearchInput = React.createClass({
'ant-search-input': true,
'ant-search-input-focus': this.state.focus,
});
return <InputGroup className={searchCls} style={this.props.style}>
<Input {...this.props} value={this.state.value} onChange={this.handleInputChange}
onFocus={this.handleFocusBlur} onBlur={this.handleFocusBlur} />
<div className="ant-input-group-wrap">
<Button className={btnCls} onClick={this.handleSearch}>
<Icon type="search" />
</Button>
</div>
</InputGroup>;
return (
<InputGroup className={searchCls} style={this.props.style}>
<Input {...this.props} value={this.state.value} onChange={this.handleInputChange}
onFocus={this.handleFocusBlur} onBlur={this.handleFocusBlur} />
<div className="ant-input-group-wrap">
<Button className={btnCls} onClick={this.handleSearch}>
<Icon type="search" />
</Button>
</div>
</InputGroup>
);
}
});
ReactDOM.render(
<SearchInput placeholder="input search text" style={{width: 200}} />
<SearchInput placeholder="input search text" style={{ width: 200 }} />
, mountNode);
````

View File

@ -0,0 +1,178 @@
# 表单校验
- order: 11
基本的表单校验例子。
---
````jsx
import { Button, Form, Input } from 'antd';
const createForm = Form.create;
const FormItem = Form.Item;
function noop() {
return false;
}
class BasicDemo extends React.Component {
getValidateStatus(field) {
const { isFieldValidating, getFieldError, getFieldValue } = this.props.form;
if (isFieldValidating(field)) {
return 'validating';
} else if (!!getFieldError(field)) {
return 'error';
} else if (getFieldValue(field)) {
return 'success';
}
}
handleReset(e) {
e.preventDefault();
this.props.form.resetFields();
}
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((errors, values) => {
if (!!errors) {
console.log('Errors in form!!!');
return;
}
console.log('Submit!!!');
console.log(values);
});
}
userExists(rule, value, callback) {
if (!value) {
callback();
} else {
setTimeout(() => {
if (value === 'JasonWood') {
callback([new Error('抱歉,该用户名已被占用。')]);
} else {
callback();
}
}, 800);
}
}
checkPass(rule, value, callback) {
const { validateFields } = this.props.form;
if (value) {
validateFields(['rePasswd']);
}
callback();
}
checkPass2(rule, value, callback) {
const { getFieldValue } = this.props.form;
if (value && value !== getFieldValue('passwd')) {
callback('两次输入密码不一致!');
} else {
callback();
}
}
render() {
const { getFieldProps, getFieldError, isFieldValidating } = this.props.form;
return (
<Form horizontal form={this.props.form}>
<FormItem
label="用户名:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}
hasFeedback
help={isFieldValidating('name') ? '校验中...' : (getFieldError('name') || []).join(', ')}>
<Input placeholder="实时校验,输入 JasonWood 看看"
{...getFieldProps('name', {
rules: [
{ required: true, min: 5, message: '用户名至少为 5 个字符' },
{ validator: this.userExists },
],
})} />
</FormItem>
<FormItem
label="邮箱:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}
hasFeedback>
<Input type="email" placeholder="onBlur 与 onChange 相结合"
{...getFieldProps('email', {
validate: [{
rules: [
{ required: true },
],
trigger: 'onBlur',
}, {
rules: [
{ type: 'email', message: '请输入正确的邮箱地址' },
],
trigger: ['onBlur', 'onChange'],
}]
})}/>
</FormItem>
<FormItem
label="密码:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}
hasFeedback>
<Input type="password" autoComplete="off"
{...getFieldProps('passwd', {
rules: [
{ required: true, whitespace: true, message: '请填写密码' },
{ validator: this.checkPass.bind(this) },
],
})}
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}/>
</FormItem>
<FormItem
label="确认密码:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}
hasFeedback>
<Input type="password" autoComplete="off" placeholder="两次输入密码保持一致"
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
{...getFieldProps('rePasswd', {
rules: [{
required: true,
whitespace: true,
message: '请再次输入密码',
}, {
validator: this.checkPass2.bind(this),
}],
})}/>
</FormItem>
<FormItem
label="备注:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<Input type="textarea" placeholder="随便写" id="textarea" name="textarea"
{...getFieldProps('textarea', {
rules: [
{ required: true, message: '真的不打算写点什么吗?' },
],
})}/>
</FormItem>
<FormItem wrapperCol={{ span: 12, offset: 7 }} >
<Button type="primary" onClick={this.handleSubmit.bind(this)}>确定</Button>
&nbsp;&nbsp;&nbsp;
<Button type="ghost" onClick={this.handleReset.bind(this)}>重置</Button>
</FormItem>
</Form>
);
}
}
BasicDemo = createForm()(BasicDemo);
ReactDOM.render(<BasicDemo />, mountNode);
````

View File

@ -0,0 +1,240 @@
# 自定义校验规则
- order: 13
密码校验实例。
这里使用了 validation 的 `forceValidate(fields, callback)` 方法,在对第一次输入的密码进行校验时会触发二次密码的校验。
---
````jsx
import { Button, Form, Input, Row, Col, Modal } from 'antd';
import classNames from 'classnames';
const createForm = Form.create;
const FormItem = Form.Item;
function noop() {
return false;
}
let Demo = React.createClass({
getInitialState() {
return {
passBarShow: false, // 是否显示密码强度提示条
rePassBarShow: false,
passStrength: 'L', // 密码强度
rePassStrength: 'L',
visible: false,
};
},
handleSubmit() {
this.props.form.validateFields((errors, values) => {
if (!!errors) {
console.log('Errors in form!!!');
return;
}
console.log('Submit!!!');
console.log(values);
this.setState({ visible: false });
});
},
getPassStrenth(value, type) {
if (value) {
let strength;
// 密码强度的校验规则自定义,这里只是做个简单的示例
if (value.length < 6) {
strength = 'L';
} else if (value.length <= 9) {
strength = 'M';
} else {
strength = 'H';
}
if (type === 'pass') {
this.setState({ passBarShow: true, passStrength: strength });
} else {
this.setState({ rePassBarShow: true, rePassStrength: strength });
}
} else {
if (type === 'pass') {
this.setState({ passBarShow: false });
} else {
this.setState({ rePassBarShow: false });
}
}
},
showModal() {
this.setState({ visible: true });
},
hideModal() {
this.setState({ visible: false });
},
checkPass(rule, value, callback) {
const form = this.props.form;
this.getPassStrenth(value, 'pass');
if (form.getFieldValue('pass')) {
form.validateFields(['rePass'], { force: true });
}
callback();
},
checkPass2(rule, value, callback) {
const form = this.props.form;
this.getPassStrenth(value, 'rePass');
if (value && value !== form.getFieldValue('pass')) {
callback('两次输入密码不一致!');
} else {
callback();
}
},
renderPassStrengthBar(type) {
const strength = type === 'pass' ? this.state.passStrength : this.state.rePassStrength;
const classSet = classNames({
'ant-pwd-strength': true,
'ant-pwd-strength-low': strength === 'L',
'ant-pwd-strength-medium': strength === 'M',
'ant-pwd-strength-high': strength === 'H'
});
const level = {
L: '低',
M: '中',
H: '高'
};
return (
<div>
<ul className={classSet}>
<li className="ant-pwd-strength-item ant-pwd-strength-item-1"></li>
<li className="ant-pwd-strength-item ant-pwd-strength-item-2"></li>
<li className="ant-pwd-strength-item ant-pwd-strength-item-3"></li>
<span className="ant-form-text">
{level[strength]}
</span>
</ul>
</div>
);
},
render() {
const { getFieldProps } = this.props.form;
return (
<div>
<Button type="primary" onClick={this.showModal}>修改密码</Button>
<Modal title="修改密码" visible={this.state.visible} onOk={this.handleSubmit} onCancel={this.hideModal}>
<Form horizontal form={this.props.form}>
<Row>
<Col span="18">
<FormItem
label="密码:"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}>
<Input type="password"
{...getFieldProps('pass', {
rules: [
{ required: true, whitespace: true, message: '请填写密码' },
{ validator: this.checkPass }
]
})}
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
autoComplete="off" id="pass" />
</FormItem>
</Col>
<Col span="6">
{this.state.passBarShow ? this.renderPassStrengthBar('pass') : null}
</Col>
</Row>
<Row>
<Col span="18">
<FormItem
label="确认密码:"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}>
<Input type="password"
{...getFieldProps('rePass', {
rules: [{
required: true,
whitespace: true,
message: '请再次输入密码',
}, {
validator: this.checkPass2,
}],
})}
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
autoComplete="off" id="rePass" />
</FormItem>
</Col>
<Col span="6">
{this.state.rePassBarShow ? this.renderPassStrengthBar('rePass') : null}
</Col>
</Row>
</Form>
</Modal>
</div>
);
}
});
Demo = createForm()(Demo);
ReactDOM.render(<Demo />, mountNode);
````
````css
.ant-pwd-strength {
display: inline-block;
margin-left: 8px;
line-height: 32px;
height: 32px;
vertical-align: middle;
}
.ant-pwd-strength-item {
float: left;
margin-right: 1px;
margin-top: 12px;
width: 19px;
height: 8px;
line-height: 8px;
list-style: none;
background-color: #f3f3f3;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.ant-pwd-strength-item-1 {
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
}
.ant-pwd-strength-item-2 {
width: 20px;
}
.ant-pwd-strength-item-3 {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
margin-right: 8px;
}
.ant-pwd-strength-low .ant-pwd-strength-item-1, .ant-pwd-strength-medium .ant-pwd-strength-item-1, .ant-pwd-strength-high .ant-pwd-strength-item-1 {
background-color: #FAC450;
}
.ant-pwd-strength-medium .ant-pwd-strength-item-2, .ant-pwd-strength-high .ant-pwd-strength-item-2 {
background-color: rgba(135, 208, 104, .6);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#9987D068,endColorstr=#9987D068);
}
.ant-pwd-strength-high .ant-pwd-strength-item-3 {
background-color: #87D068;
}
````

View File

@ -0,0 +1,172 @@
# 校验其他组件
- order: 12
提供以下组件表单域的校验。
`Select` `Radio` `DatePicker` `InputNumber` `Cascader`
---
````jsx
import { Select, Radio, Button, DatePicker, InputNumber, Form, Cascader } from 'antd';
const Option = Select.Option;
const RadioGroup = Radio.Group;
const createForm = Form.create;
const FormItem = Form.Item;
let Demo = React.createClass({
handleReset(e) {
e.preventDefault();
this.props.form.resetFields();
},
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((errors, values) => {
if (!!errors) {
console.log('Errors in form!!!');
return;
}
console.log('Submit!!!');
console.log(values);
});
},
checkBirthday(rule, value, callback) {
if (value && value.getTime() >= Date.now()) {
callback(new Error('你不可能在未来出生吧!'));
} else {
callback();
}
},
checkPrime(rule, value, callback) {
if (value !== 11) {
callback(new Error('8~12之间的质数明明是11啊!'));
} else {
callback();
}
},
render() {
const address = [{
value: 'zhejiang',
label: '浙江',
children: [{
value: 'hangzhou',
label: '杭州',
}],
}];
const { getFieldProps } = this.props.form;
return (
<Form horizontal form={this.props.form}>
<FormItem
label="国籍:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<Select placeholder="请选择国家" style={{ width: '100%' }}
{...getFieldProps('select', {
rules: [
{ required: true, message: '请选择您的国籍' }
],
})}
>
<Option value="china">中国</Option>
<Option value="use">美国</Option>
<Option value="japan">日本</Option>
<Option value="korean">韩国</Option>
<Option value="Thailand">泰国</Option>
</Select>
</FormItem>
<FormItem
label="喜欢的颜色:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<Select multiple placeholder="请选择颜色" style={{ width: '100%' }}
{...getFieldProps('multiSelect', {
rules: [
{ required: true, message: '请选择您喜欢的颜色', type: 'array' },
]
})}
>
<Option value="red">红色</Option>
<Option value="orange">橙色</Option>
<Option value="yellow">黄色</Option>
<Option value="green">绿色</Option>
<Option value="blue">蓝色</Option>
</Select>
</FormItem>
<FormItem
label="性别:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<RadioGroup
{...getFieldProps('radio', {
rules: [
{ required: true, message: '请选择您的性别' }
]
})}
>
<Radio value="male"></Radio>
<Radio value="female"></Radio>
</RadioGroup>
</FormItem>
<FormItem
label="生日:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<DatePicker
{...getFieldProps('birthday', {
rules: [
{
required: true,
type: 'date',
message: '你的生日是什么呢?',
}, {
validator: this.checkBirthday,
}
]
})}
/>
</FormItem>
<FormItem
label="8~12间的质数"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<InputNumber min={8} max={12}
{...getFieldProps('primeNumber', {
rules: [{ validator: this.checkPrime }],
})}
/>
</FormItem>
<FormItem
label="选择地址:"
labelCol={{ span: 7 }}
wrapperCol={{ span: 12 }}>
<Cascader options={address}
{...getFieldProps('address', {
rules: [{ required: true, type: 'array' }],
})}
/>
</FormItem>
<FormItem
wrapperCol={{ span: 12, offset: 7 }} >
<Button type="primary" onClick={this.handleSubmit}>确定</Button>
&nbsp;&nbsp;&nbsp;
<Button type="ghost" onClick={this.handleReset}>重置</Button>
</FormItem>
</Form>
);
},
});
Demo = createForm()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -20,8 +20,8 @@ ReactDOM.render(
<Form horizontal>
<FormItem
label="失败校验:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
validateStatus="error"
help="请输入数字和字母组合">
<Input defaultValue="无效选择" id="error" />
@ -29,16 +29,16 @@ ReactDOM.render(
<FormItem
label="警告校验:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
validateStatus="warning">
<Input defaultValue="前方高能预警" id="warning" />
</FormItem>
<FormItem
label="校验中:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
hasFeedback
validateStatus="validating"
help="信息审核中...">
@ -47,8 +47,8 @@ ReactDOM.render(
<FormItem
label="成功校验:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
hasFeedback
validateStatus="success">
<Input defaultValue="我是正文" id="success" />
@ -56,8 +56,8 @@ ReactDOM.render(
<FormItem
label="警告校验:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
hasFeedback
validateStatus="warning">
<Input defaultValue="前方高能预警" id="warning" />
@ -65,8 +65,8 @@ ReactDOM.render(
<FormItem
label="失败校验:"
labelCol={{span: 5}}
wrapperCol={{span: 12}}
labelCol={{ span: 5 }}
wrapperCol={{ span: 12 }}
hasFeedback
validateStatus="error"
help="请输入数字和字母组合">
@ -75,7 +75,26 @@ ReactDOM.render(
<FormItem
label="Datepicker"
labelCol={{span: 5}}
labelCol={{ span: 5 }}
help>
<Col span="6">
<FormItem validateStatus="error" help="请选择正确日期">
<DatePicker />
</FormItem>
</Col>
<Col span="1">
<p className="ant-form-split">-</p>
</Col>
<Col span="6">
<FormItem>
<DatePicker />
</FormItem>
</Col>
</FormItem>
<FormItem
label="Datepicker"
labelCol={{ span: 5 }}
validateStatus="error"
help>
<Col span="6">
@ -88,26 +107,7 @@ ReactDOM.render(
<DatePicker />
</Col>
<Col span="19" offset="5">
<p className="ant-form-explain">请输入正确选项</p>
</Col>
</FormItem>
<FormItem
label="Datepicker"
labelCol={{span: 5}}>
<Col span="6">
<FormItem validateStatus="error">
<DatePicker />
<p className="ant-form-explain">请输入正确选项</p>
</FormItem>
</Col>
<Col span="1">
<p className="ant-form-split">-</p>
</Col>
<Col span="6">
<FormItem>
<DatePicker />
</FormItem>
<p className="ant-form-explain">请选择正确日期</p>
</Col>
</FormItem>
</Form>

View File

@ -2,8 +2,20 @@ import Form from './Form';
import FormItem from './FormItem';
import ValueMixin from './ValueMixin';
import Input from '../input';
import { createForm } from 'rc-form';
Form.create = (o = {}) => {
const options = {
...o,
fieldNameProp: 'id',
fieldMetaProp: '__meta',
};
return createForm(options);
};
Form.Item = FormItem;
// @Deprecated
Form.ValueMixin = ValueMixin;
// import { Form, Input } from 'antd/lib/form/';

View File

@ -35,17 +35,63 @@
<Input {...props} />
```
> 注:标准表单中一律使用大号控件。
## API
### Form
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| form | 经 `Form.create()` 包装过的组件会自带 `this.props.form` 属性,直接传给 Form 即可 | object | | 无 |
| horizontal | 水平排列布局 | boolean | | false |
| inline | 行内排列布局 | boolean | | false |
| onSubmit | 数据验证成功后回调事件 | Function(e:Event) | | |
| prefixCls | 样式类名,默认为 ant-form通常您不需要设置 | string | | 'ant-form' |
### Form.create(options)
使用方式如下:
```jsx
class CustomizedForm extends React.Component {}
CustomizedForm = Form.create({})(CustomizedForm);
```
`options` 的配置项如下。
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| onFieldsChange | 当 `Form.Item` 子节点的值发生改变时触发,可以把对应的值转存到 Redux store | Function(props, fields) | | |
| mapPropsToFields | 把 props 转为对应的值,可用于把 Redux store 中的值读出 | Function(props) | | | |
经过 `Form.create` 包装的组件将会自带 `this.props.form` 属性,`this.props.form` 提供的 API 如下:
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| getFieldsValue | 获取一组输入控件的值,如不传入参数,则获取全部组件的值 | Function([fieldNames: string[]]) | | |
| getFieldValue | 获取一个输入控件的值 | Function(fieldName: string) | | |
| setFieldsValue | 设置一组输入控件的值 | Function(obj: object) | | |
| setFields | 设置一组输入控件的值与 Error | Function(obj: object) | | |
| validateFields | 校验并获取一组输入域的值与 Error | Function([fieldNames: string[]], [options: object], callback: Function(errors, values)) | | |
| getFieldError | 获取某个输入控件的 Error | Function(name) | | |
| isFieldValidating | 判断一个输入控件是否在校验状态 | Function(name) | | |
| resetFields | 重置一组输入控件的值与状态,如不传入参数,则重置所有组件 | Function([names: string[]]) | | | |
| getFieldProps 详见下面描述
#### this.props.form.getFieldProps(id, options)
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| options.id | 必填输入控件唯一标志 | string | | |
| options.valuePropName | 子节点的值的属性,如 Checkbox 的是 'checked' | string | | 'value' |
| options.initialValue | 子节点的初始值,类型、可选值均由子节点决定 | | | |
| options.trigger | 收集子节点的值的时机 | string | | 'onChange' |
| options.validateTrigger | 校验子节点值的时机 | string | | 'onChange' |
| options.rules | 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) | array | | | |
### Form.Item
| 参数 | 说明 | 类型 | 可选值 |默认值 |
@ -53,32 +99,28 @@
| label | label 标签的文本 | string | | |
| labelCol | label 标签布局,通 `<Col>` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}` | object | | |
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | object | | |
| help | 提示信息 | string | | |
| required | 是否必填 | bool | | false |
| validateStatus | 校验状态 | string | 'success' 'warning' 'error' 'validating' | |
| help | 提示信息,如不设置,则会根据校验规则自动生成 | string | | |
| required | 是否必填,如不设置,则会根据校验规则自动生成 | bool | | false |
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成 | string | 'success' 'warning' 'error' 'validating' | |
| hasFeedback | 配合 validateStatus 属性使用,是否展示校验状态图标 | bool | | false |
| prefixCls | 样式类名,默认为 ant-form通常您不需要设置 | string | | 'ant-form' |
### Form.ValueMixin
Mixin当表单控件的输入值改变时更新 formData。
**你需要为每个输入控件声明 `name` 属性**
### Input
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| type | 【必须】声明 input 类型,同原生 input 标签的 type 属性 | string | | 'text' |
| value | value 值 | any | | |
| id | id | number 或 string | | |
| size | 控件大小,默认值为 default 。注:标准表单内的输入框大小限制为 large。 | string | {'large','default','small'} | 'default' |
| value | value 值 | any | | |
| defaultValue | 设置初始默认值 | any | | |
| size | 控件大小,默认值为 default 。注:标准表单内的输入框大小限制为 large。 | string | {'large','default','small'} | 'default' |
| disabled | 是否禁用状态,默认为 false | bool | | false |
| addonBefore | 带标签的 input设置前置标签 | node | | |
| addonAfter | 带标签的 input设置后置标签 | node | | |
| prefixCls | 样式类名前缀,默认是 ant通常您不需要设置 | string | | 'ant' |
> 如果 `Input``Form.Item` 内,并且 `Form.Item` 设置了 `id``options` 属性,则 `value` `defaultValue``id` 属性会被自动设置。
#### Input.Group
```html

View File

@ -21,12 +21,14 @@ const Test = React.createClass({
});
},
render() {
return <div>
<InputNumber min={1} max={10} disabled={this.state.disabled} defaultValue={3} />
<div style={{marginTop: 20}}>
<Button onClick={this.toggle} type="primary">Toggle disabled</Button>
return (
<div>
<InputNumber min={1} max={10} disabled={this.state.disabled} defaultValue={3} />
<div style={{ marginTop: 20 }}>
<Button onClick={this.toggle} type="primary">Toggle disabled</Button>
</div>
</div>
</div>;
);
}
});

View File

@ -10,7 +10,7 @@ export default React.createClass({
};
},
render() {
const {className, size, ...other} = this.props;
const { className, size, ...other } = this.props;
const inputNumberClass = classNames({
'ant-input-number-lg': size === 'large',
'ant-input-number-sm': size === 'small',

View File

@ -2,7 +2,7 @@ import React from 'react';
import assign from 'object-assign';
function prefixClsFn(prefixCls, ...args) {
return args.map((s)=> {
return args.map((s) => {
return prefixCls + '-' + s;
}).join(' ');
}
@ -26,8 +26,7 @@ class Group extends React.Component {
render() {
const className = 'ant-input-group ' + (this.props.className || '');
return (
<span className={className}
style={this.props.style}>
<span className={className} style={this.props.style}>
{this.props.children}
</span>
);
@ -73,23 +72,26 @@ class Input extends React.Component {
}
switch (props.size) {
case 'small': inputClassName = prefixClsFn(prefixCls, 'input', 'input-sm'); break;
case 'large': inputClassName = prefixClsFn(prefixCls, 'input', 'input-lg'); break;
default:
case 'small': inputClassName = prefixClsFn(prefixCls, 'input', 'input-sm'); break;
case 'large': inputClassName = prefixClsFn(prefixCls, 'input', 'input-lg'); break;
default:
}
let placeholder = props.placeholder;
if(placeholder && ieGT9()){
if (placeholder && ieGT9()) {
placeholder = null;
}
if ('value' in props) {
props.value = fixControlledValue(props.value);
}
switch (props.type) {
case 'textarea':
return <textarea {...props} placeholder={placeholder} className={inputClassName} ref="input" />;
default:
inputClassName = props.className ? props.className : inputClassName;
return <input {...props} placeholder={placeholder} className={inputClassName} ref="input"/>;
case 'textarea':
return (
<textarea {...props} placeholder={placeholder}
className={inputClassName} ref="input" />
);
default:
inputClassName = props.className ? props.className : inputClassName;
return <input {...props} placeholder={placeholder} className={inputClassName} ref="input"/>;
}
}

View File

@ -12,7 +12,7 @@ const Col = React.createClass({
children: React.PropTypes.node,
},
render() {
const {span, order, offset, push, pull, className, ...others} = this.props;
const { span, order, offset, push, pull, className, ...others } = this.props;
const classes = classNames({
['col-' + span]: span,
['col-order-' + order]: order,

View File

@ -12,7 +12,7 @@ const Row = React.createClass({
render() {
const { type, justify, align, className, ...others } = this.props;
const classes = classNames({
'row': true,
row: true,
['row-' + type]: type,
['row-' + type + '-' + justify]: justify,
['row-' + type + '-' + align]: align,

View File

@ -30,34 +30,36 @@ const Sider = React.createClass({
});
},
render() {
return <Menu onClick={this.handleClick}
style={{width:240}}
openKeys={this.state.openKeys}
onOpen={this.onToggle}
onClose={this.onToggle}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
return (
<Menu onClick={this.handleClick}
style={{ width: 240 }}
openKeys={this.state.openKeys}
onOpen={this.onToggle}
onClose={this.onToggle}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>;
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
);
}
});
ReactDOM.render(<Sider />, mountNode);

View File

@ -24,36 +24,38 @@ const Sider = React.createClass({
});
},
render() {
return <Menu onClick={this.handleClick}
style={{width:240}}
defaultOpenKeys={['sub1']}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<MenuItemGroup title="分组1">
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
</MenuItemGroup>
<MenuItemGroup title="分组2">
<Menu.Item key="3"><a href="#">选项3</a></Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</MenuItemGroup>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
return (
<Menu onClick={this.handleClick}
style={{ width: 240 }}
defaultOpenKeys={['sub1']}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<MenuItemGroup title="分组1">
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
</MenuItemGroup>
<MenuItemGroup title="分组2">
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</MenuItemGroup>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>;
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
);
}
});
ReactDOM.render(<Sider />, mountNode);

View File

@ -28,38 +28,40 @@ const Sider = React.createClass({
});
},
render() {
return <div>
<Switch onChange={this.changeTheme} checkedChildren="暗" unCheckedChildren="亮" />
<br />
<br />
<Menu theme={this.state.theme}
onClick={this.handleClick}
style={{width:240}}
defaultOpenKeys={['sub1']}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
return (
<div>
<Switch onChange={this.changeTheme} checkedChildren="暗" unCheckedChildren="亮" />
<br />
<br />
<Menu theme={this.state.theme}
onClick={this.handleClick}
style={{ width: 240 }}
defaultOpenKeys={['sub1']}
selectedKeys={[this.state.current]}
mode="inline">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
</div>;
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><Icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
</div>
);
}
});
ReactDOM.render(<Sider />, mountNode);

View File

@ -15,31 +15,32 @@ function handleClick(e) {
console.log('click', e);
}
ReactDOM.render(<Menu onClick={handleClick} style={{width:240}} mode="vertical">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<MenuItemGroup title="分组1">
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
</MenuItemGroup>
<MenuItemGroup title="分组2">
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</MenuItemGroup>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
ReactDOM.render(
<Menu onClick={handleClick} style={{ width: 240 }} mode="vertical">
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>导航一</span></span>}>
<MenuItemGroup title="分组1">
<Menu.Item key="1">选项1</Menu.Item>
<Menu.Item key="2">选项2</Menu.Item>
</MenuItemGroup>
<MenuItemGroup title="分组2">
<Menu.Item key="3">选项3</Menu.Item>
<Menu.Item key="4">选项4</Menu.Item>
</MenuItemGroup>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
<SubMenu key="sub2" title={<span><Icon type="appstore" /><span>导航二</span></span>}>
<Menu.Item key="5">选项5</Menu.Item>
<Menu.Item key="6">选项6</Menu.Item>
<SubMenu key="sub3" title="三级导航">
<Menu.Item key="7">选项7</Menu.Item>
<Menu.Item key="8">选项8</Menu.Item>
</SubMenu>
</SubMenu>
<SubMenu key="sub4" title={<span><icon type="setting" /><span>导航三</span></span>}>
<Menu.Item key="9">选项9</Menu.Item>
<Menu.Item key="10">选项10</Menu.Item>
<Menu.Item key="11">选项11</Menu.Item>
<Menu.Item key="12">选项12</Menu.Item>
</SubMenu>
</Menu>
, mountNode);
````

View File

@ -43,16 +43,16 @@ const AntMenu = React.createClass({
let openAnimation = this.props.openAnimation || this.props.openTransitionName;
if (!openAnimation) {
switch (this.props.mode) {
case 'horizontal':
openAnimation = 'slide-up';
break;
case 'vertical':
openAnimation = 'zoom-big';
break;
case 'inline':
openAnimation = animation;
break;
default:
case 'horizontal':
openAnimation = 'slide-up';
break;
case 'vertical':
openAnimation = 'zoom-big';
break;
case 'inline':
openAnimation = animation;
break;
default:
}
}

View File

@ -9,11 +9,10 @@
````jsx
import { message, Button } from 'antd';
const success = function() {
const success = function () {
message.success('这是一条成功的提示,并将于10秒后消失', 10);
};
ReactDOM.render(<Button onClick={success}>自定义时长提示</Button>
, mountNode);
````

View File

@ -9,7 +9,7 @@
````jsx
import { message, Button } from 'antd';
const info = function() {
const info = function () {
message.info('这是一条普通的提醒');
};

View File

@ -9,7 +9,7 @@
````jsx
import { message, Button } from 'antd';
const success = function() {
const success = function () {
let hide = message.loading('正在执行中...', 0);
// 异步手动移除
setTimeout(hide, 2500);

View File

@ -9,15 +9,15 @@
````jsx
import { message, Button } from 'antd';
const success = function() {
const success = function () {
message.success('这是一条成功提示');
};
const error = function() {
const error = function () {
message.error('这是一条报错提示');
};
const warn = function() {
const warn = function () {
message.warn('这是一条警告提示');
};

View File

@ -12,7 +12,7 @@ function getMessageInstance() {
prefixCls: 'ant-message',
transitionName: 'move-up',
style: {
top: top
top,
} //
});
return messageInstance;
@ -20,38 +20,38 @@ function getMessageInstance() {
function notice(content, duration = defaultDuration, type, onClose) {
let iconClass = ({
'info': 'ant-message-info',
'success': 'ant-message-success',
'error': 'ant-message-error',
'warn': 'ant-message-warn',
'loading': 'ant-message-loading'
info: 'ant-message-info',
success: 'ant-message-success',
error: 'ant-message-error',
warn: 'ant-message-warn',
loading: 'ant-message-loading'
})[type];
let iconType = ({
'info': 'info-circle',
'success': 'check-circle',
'error': 'exclamation-circle',
'warn': 'exclamation-circle',
'loading': 'loading'
info: 'info-circle',
success: 'check-circle',
error: 'exclamation-circle',
warn: 'exclamation-circle',
loading: 'loading'
})[type];
let instance = getMessageInstance();
instance.notice({
key: key,
duration: duration,
key,
duration,
style: {},
content: <div className={'ant-message-custom-content ' + iconClass}>
<Icon className={iconClass} type={iconType} />
<span>{content}</span>
</div>,
onClose: onClose
onClose
});
return (function() {
return (function () {
let target = key++;
return function() {
return function () {
instance.removeNotice(target);
};
})();
}());
}
export default {
@ -74,5 +74,11 @@ export default {
if (options.top) {
top = options.top;
}
}
},
destroy() {
if (messageInstance) {
messageInstance.destroy();
messageInstance = null;
}
},
};

View File

@ -21,7 +21,7 @@
- `message.info(content, duration)`
- `message.loading(content, duration)`
组件提供了个静态方法,参数如下:
组件提供了个静态方法,参数如下:
| 参数 | 说明 | 类型 | 默认值 |
|------------|----------------|----------------------------|--------------|
@ -29,9 +29,10 @@
| duration | 自动关闭的延时 | number | 1.5 |
还提供了一个全局配置方法:
还提供了全局配置和全局销毁方法:
- `message.config(options)`
- `message.destroy()`
```js
message.config({

View File

@ -37,7 +37,7 @@ let AntModal = React.createClass({
return;
}
//
Dom.addEventListener(document.body, 'click', function onDocumentMousemove(e) {
Dom.addEventListener(document.documentElement, 'click', (e) => {
mousePosition = {
x: e.pageX,
y: e.pageY
@ -68,8 +68,10 @@ let AntModal = React.createClass({
</Button>
];
let footer = props.footer || defaultFooter;
return <Dialog onClose={this.handleCancel} footer={footer} {...props}
visible={props.visible} mousePosition={mousePosition} />;
return (
<Dialog onClose={this.handleCancel} footer={footer} {...props}
visible={props.visible} mousePosition={mousePosition} />
);
}
});

View File

@ -3,13 +3,14 @@ import ReactDOM from 'react-dom';
import Dialog from './Modal';
import Icon from '../icon';
import Button from '../button';
import objectAssign from 'object-assign';
export default function (props) {
export default function (config) {
const props = objectAssign({}, config || {});
let div = document.createElement('div');
document.body.appendChild(div);
let d;
props = props || {};
props.iconClassName = props.iconClassName || 'question-circle';
let iconClassType = props.iconClassName;
@ -72,28 +73,34 @@ export default function (props) {
}
}
let body = <div className="ant-confirm-body">
<Icon type={iconClassType} />
<span className="ant-confirm-title">{props.title}</span>
<div className="ant-confirm-content">{props.content}</div>
</div>;
let body = (
<div className="ant-confirm-body">
<Icon type={iconClassType} />
<span className="ant-confirm-title">{props.title}</span>
<div className="ant-confirm-content">{props.content}</div>
</div>
);
let footer = null;
if (props.okCancel) {
footer = <div className="ant-confirm-btns">
<Button type="ghost" size="large" onClick={onCancel}>
{props.cancelText}
</Button>
<Button type="primary" size="large" onClick={onOk}>
{props.okText}
</Button>
</div>;
footer = (
<div className="ant-confirm-btns">
<Button type="ghost" size="large" onClick={onCancel}>
{props.cancelText}
</Button>
<Button type="primary" size="large" onClick={onOk}>
{props.okText}
</Button>
</div>
);
} else {
footer = <div className="ant-confirm-btns">
<Button type="primary" size="large" onClick={onOk}>
{props.okText}
</Button>
</div>;
footer = (
<div className="ant-confirm-btns">
<Button type="primary" size="large" onClick={onOk}>
{props.okText}
</Button>
</div>
);
}
ReactDOM.render(<Dialog
@ -105,7 +112,7 @@ export default function (props) {
transitionName="zoom"
footer=""
maskTransitionName="fade" width={width}>
<div style={{zoom: 1, overflow: 'hidden'}}>{body} {footer}</div>
<div style={{ zoom: 1, overflow: 'hidden' }}>{body} {footer}</div>
</Dialog>, div, function () {
d = this;
});

View File

@ -40,16 +40,18 @@ const Test = React.createClass({
});
},
render() {
return <div>
<Button type="primary" onClick={this.showModal}>显示对话框</Button>
<Modal title="对话框标题"
visible={this.state.visible}
onOk={this.handleOk}
confirmLoading={this.state.confirmLoading}
onCancel={this.handleCancel}>
<p>{this.state.ModalText}</p>
</Modal>
</div>;
return (
<div>
<Button type="primary" onClick={this.showModal}>显示对话框</Button>
<Modal title="对话框标题"
visible={this.state.visible}
onOk={this.handleOk}
confirmLoading={this.state.confirmLoading}
onCancel={this.handleCancel}>
<p>{this.state.ModalText}</p>
</Modal>
</div>
);
}
});

View File

@ -30,15 +30,17 @@ const App = React.createClass({
});
},
render() {
return <div>
<Button type="primary" onClick={this.showModal}>显示对话框</Button>
<Modal title="第一个 Modal" visible={this.state.visible}
onOk={this.handleOk} onCancel={this.handleCancel}>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
</Modal>
</div>;
return (
<div>
<Button type="primary" onClick={this.showModal}>显示对话框</Button>
<Modal title="第一个 Modal" visible={this.state.visible}
onOk={this.handleOk} onCancel={this.handleCancel}>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
</Modal>
</div>
);
}
});

View File

@ -10,16 +10,16 @@
import { Modal, Button } from 'antd';
const confirm = Modal.confirm;
function showConfirm(){
function showConfirm() {
confirm({
title: '您是否确认要删除这项内容',
content: '点确认 1 秒后关闭',
onOk: function() {
return new Promise(function(resolve) {
onOk() {
return new Promise((resolve) => {
setTimeout(resolve, 1000);
});
},
onCancel: function() {}
onCancel() {}
});
}

View File

@ -10,14 +10,14 @@
import { Modal, Button } from 'antd';
const confirm = Modal.confirm;
function showConfirm(){
function showConfirm() {
confirm({
title: '您是否确认要删除这项内容',
content: '一些解释',
onOk: function() {
onOk: function () {
console.log('确定');
},
onCancel: function() {}
onCancel: function () {}
});
}

View File

@ -10,7 +10,7 @@
import { Modal, Button } from 'antd';
const Test = React.createClass({
getInitialState: function() {
getInitialState: function () {
return {
loading: false,
visible: false
@ -31,26 +31,28 @@ const Test = React.createClass({
this.setState({ visible: false });
},
render() {
return <div>
<Button type="primary" onClick={this.showModal}>
显示对话框
</Button>
<Modal ref="modal"
visible={this.state.visible}
title="对话框标题" onOk={this.handleOk} onCancel={this.handleCancel}
footer={[
<Button key="back" type="ghost" size="large" onClick={this.handleCancel}>返 回</Button>,
<Button key="submit" type="primary" size="large" loading={this.state.loading} onClick={this.handleOk}>
提 交
</Button>
]}>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
</Modal>
</div>;
return (
<div>
<Button type="primary" onClick={this.showModal}>
显示对话框
</Button>
<Modal ref="modal"
visible={this.state.visible}
title="对话框标题" onOk={this.handleOk} onCancel={this.handleCancel}
footer={[
<Button key="back" type="ghost" size="large" onClick={this.handleCancel}>返 回</Button>,
<Button key="submit" type="primary" size="large" loading={this.state.loading} onClick={this.handleOk}>
提 交
</Button>
]}>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
<p>对话框的内容</p>
</Modal>
</div>
);
}
});

View File

@ -13,7 +13,7 @@ function info() {
Modal.info({
title: '这是一条通知信息',
content: '一些附加信息一些附加信息一些附加信息',
onOk: function() {}
onOk: function () {}
});
}

View File

@ -29,16 +29,18 @@ const LocalizedModal = React.createClass({
});
},
render() {
return <div>
<Button type="primary" onClick={this.showModal}>Show Modal</Button>
<Modal title="Modal" visible={this.state.visible}
onOk={this.handleOk} onCancel={this.handleCancel}
okText="OK" cancelText="Cancel">
<p>Bla bla ...</p>
<p>Bla bla ...</p>
<p>Bla bla ...</p>
</Modal>
</div>;
return (
<div>
<Button type="primary" onClick={this.showModal}>Show Modal</Button>
<Modal title="Modal" visible={this.state.visible}
onOk={this.handleOk} onCancel={this.handleCancel}
okText="OK" cancelText="Cancel">
<p>Bla bla ...</p>
<p>Bla bla ...</p>
<p>Bla bla ...</p>
</Modal>
</div>
);
}
});

View File

@ -1,27 +1,36 @@
import AntModal from './Modal';
import confirm from './confirm';
import objectAssign from 'object-assign';
AntModal.info = function (props) {
props.iconClassName = 'info-circle';
props.okCancel = false;
return confirm(props);
const config = objectAssign({}, props, {
iconClassName: 'info-circle',
okCancel: false,
});
return confirm(config);
};
AntModal.success = function (props) {
props.iconClassName = 'check-circle';
props.okCancel = false;
return confirm(props);
const config = objectAssign({}, props, {
iconClassName: 'check-circle',
okCancel: false,
});
return confirm(config);
};
AntModal.error = function (props) {
props.iconClassName = 'exclamation-circle';
props.okCancel = false;
return confirm(props);
const config = objectAssign({}, props, {
iconClassName: 'exclamation-circle',
okCancel: false,
});
return confirm(config);
};
AntModal.confirm = function (props) {
props.okCancel = true;
return confirm(props);
const config = objectAssign({}, props, {
okCancel: true,
});
return confirm(config);
};
export default AntModal;

View File

@ -23,6 +23,7 @@
| visible | 对话框是否可见 | Boolean | 无 |
| confirmLoading | 确定按钮 loading | Boolean | 无 |
| title | 标题 | React.Element | 无 |
| closable | 是否显示右上角的关闭按钮 | Boolean | true |
| onOk | 点击确定回调 | function | 无 |
| onCancel | 点击遮罩层或右上角叉或取消按钮的回调 | function | 无 |
| width | 宽度 | String or Number | 520 |

View File

@ -9,7 +9,7 @@
````jsx
import { Button, notification } from 'antd';
const openNotification = function() {
const openNotification = function () {
notification.open({
message: '这是标题',
description: '这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案'

View File

@ -9,7 +9,7 @@
````jsx
import { Button, notification } from 'antd';
const openNotification = function() {
const openNotification = function () {
const args = {
message: '这是标题',
description: '我不会自动关闭,我不会自动关闭,我不会自动关闭,我不会自动关闭,我不会自动关闭,我不会自动关闭,我不会自动关闭',

View File

@ -9,11 +9,11 @@
````jsx
import { Button, notification } from 'antd';
const close = function() {
const close = function () {
console.log('我被默认的关闭按钮关闭了!');
};
const openNotification = function() {
const openNotification = function () {
const args = {
message: '这是标题',
description: '这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案',

View File

@ -9,19 +9,21 @@
````jsx
import { Button, notification } from 'antd';
const close = function() {
const close = function () {
console.log('我被默认的关闭按钮关闭了!');
};
const openNotification = function() {
const openNotification = function () {
const key = 'open' + Date.now();
const btnClick = function() {
const btnClick = function () {
// 隐藏提醒框
notification.close(key);
};
const btn = <Button type="primary" size="small" onClick={btnClick}>
自定义关闭按钮并触发回调函数
</Button>;
const btn = (
<Button type="primary" size="small" onClick={btnClick}>
自定义关闭按钮并触发回调函数
</Button>
);
notification.open({
message: '这是标题',
description: '这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案',

View File

@ -9,8 +9,8 @@
````jsx
import { Button, notification } from 'antd';
const openNotificationWithIcon = function(type) {
return function(){
const openNotificationWithIcon = function (type) {
return function () {
notification[type]({
message: '这是标题',
description: '这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案'
@ -18,11 +18,12 @@ const openNotificationWithIcon = function(type) {
};
};
ReactDOM.render(<div>
<Button onClick={openNotificationWithIcon('success')}>成功</Button>
<Button onClick={openNotificationWithIcon('info')}>消息</Button>
<Button onClick={openNotificationWithIcon('warn')}>警告</Button>
<Button onClick={openNotificationWithIcon('error')}>错误</Button>
ReactDOM.render(
<div>
<Button onClick={openNotificationWithIcon('success')}>成功</Button>
<Button onClick={openNotificationWithIcon('info')}>消息</Button>
<Button onClick={openNotificationWithIcon('warn')}>警告</Button>
<Button onClick={openNotificationWithIcon('error')}>错误</Button>
</div>
, mountNode);
````

Some files were not shown because too many files have changed in this diff Show More