Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component cascader #778

Merged
merged 7 commits into from
Dec 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions components/cascader/demo/basic.md
Original file line number Diff line number Diff line change
@@ -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);
````
53 changes: 53 additions & 0 deletions components/cascader/demo/custom-trigger.md
Original file line number Diff line number Diff line change
@@ -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);
````
43 changes: 43 additions & 0 deletions components/cascader/demo/default-value.md
Original file line number Diff line number Diff line change
@@ -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);
````
49 changes: 49 additions & 0 deletions components/cascader/demo/hover.md
Original file line number Diff line number Diff line change
@@ -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);
````
102 changes: 102 additions & 0 deletions components/cascader/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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, style, size } = this.props;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

忽略了用户设置的 className ,有意还是?

<Cascader className="something" />

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对,意义不大。更多是用 popupClassName 。

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,
});
return (
<Cascader {...this.props}
value={this.state.value}
popupVisible={this.state.popupVisible}
onPopupVisibleChange={this.handlePopupVisibleChange}
onChange={this.handleChange}>
{children ||
<span className={`${prefixCls}-picker`}>
<Input placeholder={placeholder}
className={`${prefixCls}-input ant-input ${sizeCls}`}
style={style}
value={this.getLabel()}
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(' / ');
},
size: 'default',
onPopupVisibleChange() {},
};

export default AntCascader;
34 changes: 34 additions & 0 deletions components/cascader/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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 | - |
| popupClassName | 自定义浮层类名 | string | - |
| placeholder | 输入框占位文本 | string | '请选择' |
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
2 changes: 2 additions & 0 deletions components/select/demo/coordinate.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

省市联动是典型的例子。

推荐使用 [cascader](/components/cascader/) 组件。

---

````jsx
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const antd = {
Calendar: require('./components/calendar'),
TimePicker: require('./components/time-picker'),
Transfer: require('./components/transfer'),
Cascader: require('./components/cascader'),
};

antd.version = require('./package.json').version;
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
],
"license": "MIT",
"dependencies": {
"array-tree-filter": "~1.0.0",
"classnames": "~2.2.0",
"css-animation": "1.1.x",
"gregorian-calendar": "~4.1.0",
"gregorian-calendar-format": "~4.0.4",
"object-assign": "~4.0.1",
"rc-animate": "~2.0.2",
"rc-calendar": "~5.2.0",
"rc-cascader": "~0.5.0",
"rc-checkbox": "~1.1.1",
"rc-collapse": "~1.4.4",
"rc-dialog": "~5.2.2",
Expand Down
Loading