CascaderSelect 级联选择
如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。
安装方法
- 在命令行中执行以下命令
npm install @icedesign/base@latest -S
开发指南
何时使用
级联选择由选择器和级联组成。把级联组件以弹层的方式隐藏,多用于表单场景。
API
级联选择
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
prefix | 样式类名的品牌前缀 | String | 'next-' |
className | 自定义类名 | String | - |
style | 自定义内联样式 | Object | - |
size | 选择框大小可选值:'small', 'medium', 'large' | Enum | 'medium' |
shape | 选择框形状可选值:'normal', 'arrow-only' | Enum | 'normal' |
placeholder | 选择框占位符 | String | - |
disabled | 是否禁用 | Boolean | false |
hasArrow | 是否显示右侧的箭头 | Boolean | true |
hasClear | 是否显示清空按钮,该按钮可以清空当前选中的值,该属性仅在单选模式下有效 | Boolean | false |
dataSource | 数据源,结构可参考下方说明 | Array<Object> | [] |
defaultValue | (非受控)默认值 | String/Array<String> | null |
value | (受控)当前值 | String/Array<String> | - |
onChange | 选中值改变时触发的回调函数签名:Function(value: String/Array, data: Object/Array, extra: Object) => void参数:value: {String/Array} 选中的值,单选时返回单个值,多选时返回数组data: {Object/Array} 选中的数据,包括 value 和 label,单选时返回单个值,多选时返回数组,父子节点选中关联时,同时选中,只返回父节点extra: {Object} 额外参数extra.selectedPath: {Array} 单选时选中的数据的路径extra.checked: {Boolean} 多选时当前的操作是选中还是取消选中extra.currentData: {Object} 多选时当前操作的数据extra.checkedData: {Array} 多选时所有被选中的数据extra.indeterminateData: {Array} 多选时半选的数据 | Function | - |
defaultVisible | 初始下拉框是否显示 | Boolean | false |
defaultExpandedValue | 默认展开值,如果不设置,组件内部会根据 defaultValue/value 进行自动设置 | Array<String> | - |
expandTrigger | 展开触发的方式可选值:'click', 'hover' | Enum | 'click' |
multiple | 是否多选 | Boolean | false |
changeOnSelect | 是否选中即发生改变, 该属性仅在单选模式下有效 | Boolean | false |
canOnlyCheckLeaf | 是否只能勾选叶子项的checkbox,该属性仅在多选模式下有效 | Boolean | false |
checkStrictly | 父子节点是否选中不关联 | Boolean | false |
labelWidth | 文字区域宽度,当文字超过宽度时,结尾会以省略号显示,默认值为文字实际宽度 | String/Number | - |
showItemCount | 每一列展示的个数 | String/Number | 6 |
displayRender | 选择框单选时展示结果的函数签名:Function(label: Array) => ReactNode参数:label: {Array} 选中路径的文本数组返回值:{ReactNode} 渲染在选择框中的内容 | Function | label => label.join(' / ') |
popupClassName | 下拉框样式自定义类名 | String | - |
container | 下拉框挂载的容器节点 | String/Function | - |
loadData | 异步加载数据函数签名:Function(data: Object) => void参数:data: {Object} 当前点击异步加载的数据 | Function | - |
代码示例
展示基本的单选用法。
查看源码在线预览
import { CascaderSelect } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
fetch("https://os.alipayobjects.com/rmsportal/ODDwqcDFTLAguOvWEolX.json")
.then(response => response.json())
.then(data => {
data[1].disabled = true;
this.setState({ data });
})
.catch(e => console.log(e));
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return (
<CascaderSelect
dataSource={this.state.data}
onChange={this.handleChange}
/>
);
}
}
ReactDOM.render(<Demo />, mountNode);
可以通过displayRender
来定制单选时展示的结果,可以通过labelWidth
, showItemCount
来定制组件宽高,其中通过labelWidth
可设置文字区域宽度,当文字超过宽度时,结尾会以省略号显示,默认值为文字实际宽度,通过showItemCount
可设置展示的菜单项个数。
查看源码在线预览
import { CascaderSelect } from "@icedesign/base";
const dataSource = [
{
value: "2973",
label: "陕西",
children: [
{
value: "2974",
label: "西安",
children: [
{ value: "2975", label: "西安市" },
{ value: "2976", label: "高陵县" }
]
},
{
value: "2980",
label: "铜川",
children: [
{ value: "2981", label: "铜川市" },
{ value: "2982", label: "宜君县" }
]
}
]
},
{
value: "3371",
label: "新疆",
children: [
{
value: "3430",
label: "巴音郭楞蒙古自治州",
children: [
{ value: "3431", label: "库尔勒市" },
{ value: "3432", label: "和静县" }
]
}
]
}
];
const displayRender = labels => {
return labels.reduce((ret, label, index) => {
ret.push(
<span className="label-ellipsis" title={label}>
{label}
</span>
);
if (index < labels.length - 1) {
ret.push(<span className="label-separator"> / </span>);
}
return ret;
}, []);
};
ReactDOM.render(
<CascaderSelect
style={{ width: "240px" }}
displayRender={displayRender}
showItemCount="5"
labelWidth="80"
defaultValue="3431"
dataSource={dataSource}
/>,
mountNode
);
.label-ellipsis {
display: inline-block;
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
.label-separator {
display: inline-block;
vertical-align: top;
margin: 0 5px;
}
展示动态获取数据的用法。
查看源码在线预览
import { CascaderSelect } from "@icedesign/base";
const dataSource = [
{
value: "2973",
label: "陕西"
}
];
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
dataSource
};
this.onLoadData = this.onLoadData.bind(this);
}
onLoadData(data) {
console.log(data);
return new Promise(resolve => {
setTimeout(() => {
this.setState(
{
dataSource: [
{
value: "2973",
label: "陕西",
children: [
{
value: "2974",
label: "西安",
children: [
{ value: "2975", label: "西安市", isLeaf: true },
{ value: "2976", label: "高陵县", isLeaf: true }
]
},
{
value: "2980",
label: "铜川",
children: [
{ value: "2981", label: "铜川市", isLeaf: true },
{ value: "2982", label: "宜君县", isLeaf: true }
]
}
]
}
]
},
resolve
);
}, 500);
});
}
render() {
return (
<CascaderSelect
dataSource={this.state.dataSource}
loadData={this.onLoadData}
/>
);
}
}
ReactDOM.render(<Demo />, mountNode);
展示可通过expandTrigger
来设置不同的展开触发行为,支持click
和hover
,默认值为click
。
查看源码在线预览
import { Radio, CascaderSelect } from "@icedesign/base";
const { Group: RadioGroup } = Radio;
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
trigger: "click",
data: []
};
this.handleChange = this.handleChange.bind(this);
this.handleChangeTrigger = this.handleChangeTrigger.bind(this);
}
componentDidMount() {
fetch("https://os.alipayobjects.com/rmsportal/ODDwqcDFTLAguOvWEolX.json")
.then(response => response.json())
.then(data => this.setState({ data }))
.catch(e => console.log(e));
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
handleChangeTrigger(trigger) {
this.setState({
trigger
});
}
render() {
return (
<div>
<div className="trigger-check">
展开触发行为:
<RadioGroup
dataSource={["click", "hover"]}
value={this.state.trigger}
onChange={this.handleChangeTrigger}
/>
</div>
<CascaderSelect
expandTrigger={this.state.trigger}
dataSource={this.state.data}
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.trigger-check {
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
展示受控多选以及是否开启严格受控父子节点选中不再关联的用法。
查看源码在线预览
import { Checkbox, CascaderSelect } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: [],
data: [],
checkStrictly: false
};
this.handleCheck = this.handleCheck.bind(this);
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
fetch("https://os.alipayobjects.com/rmsportal/ODDwqcDFTLAguOvWEolX.json")
.then(response => response.json())
.then(data => this.setState({ data, value: ["2975"] }))
.catch(e => console.log(e));
}
handleCheck() {
this.setState({
checkStrictly: !this.state.checkStrictly,
value: []
});
}
handleChange(value, data, extra) {
console.log(value, data, extra);
this.setState({
value
});
}
render() {
return (
<div className="control-multiple-demo">
<label className="strictly-check">
<Checkbox
value={this.state.checkStrictly}
onChange={this.handleCheck}
/>
<span className="strictly-text">
开启严格受控,父子节点选中不再关联
</span>
</label>
<CascaderSelect
multiple
checkStrictly={this.state.checkStrictly}
value={this.state.value}
dataSource={this.state.data}
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.control-multiple-demo .strictly-check {
display: block;
margin-bottom: 10px;
}
.control-multiple-demo .strictly-text {
display: inline-block;
margin-left: 10px;
vertical-align: middle;
color: #666;
font-size: 14px;
}
展示基本的多选用法。
查看源码在线预览
import { CascaderSelect } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
fetch("https://os.alipayobjects.com/rmsportal/ODDwqcDFTLAguOvWEolX.json")
.then(response => response.json())
.then(data => {
data[1].disabled = true;
data[2].checkboxDisabled = true;
this.setState({ data });
})
.catch(e => console.log(e));
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return (
<CascaderSelect
multiple
dataSource={this.state.data}
onChange={this.handleChange}
/>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.cascader-value {
width: 500px;
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
展示受控单选以及是否选择即改变。
查看源码在线预览
import { Checkbox, CascaderSelect } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
changeOnSelect: false,
data: []
};
this.handleCheck = this.handleCheck.bind(this);
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
fetch("https://os.alipayobjects.com/rmsportal/ODDwqcDFTLAguOvWEolX.json")
.then(response => response.json())
.then(data => this.setState({ data, value: "2975" }))
.catch(e => console.log(e));
}
handleCheck() {
this.setState({
changeOnSelect: !this.state.changeOnSelect,
value: null
});
}
handleChange(value, data, extra) {
console.log(value, data, extra);
this.setState({
value
});
}
render() {
return (
<div className="control-single-demo">
<label className="change-check">
<Checkbox
value={this.state.changeOnSelect}
onChange={this.handleCheck}
/>
<span className="change-text">开启选择即改变</span>
</label>
<CascaderSelect
hasClear
changeOnSelect={this.state.changeOnSelect}
value={this.state.value}
dataSource={this.state.data}
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.control-single-demo .change-check {
display: block;
margin-bottom: 10px;
}
.control-single-demo .change-text {
display: inline-block;
margin-left: 10px;
vertical-align: middle;
color: #666;
font-size: 14px;
}