Cascader 级联
如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。
安装方法
- 在命令行中执行以下命令
npm install @icedesign/base@latest -S
开发指南
何时使用
适用于从一组具有关联性的数据集合中进行选择的交互方式。
由于子集目录隐藏,级联是一种节约屏幕空间的有效方法。
级别数因业务需求而定,建议不超过5级。
级联多用于表单场景,可以独立在页面中使用,也可以与其他元素组合使用,如级联选择。
API
级联
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
prefix | 样式类名的品牌前缀 | String | 'next-' |
className | 自定义类名 | String | - |
style | 自定义内联样式 | Object | - |
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 | - |
defaultExpandedValue | (非受控)默认展开值,如果不设置,组件内部会根据 defaultValue/value 进行自动设置 | Array<String> | - |
expandedValue | (受控)当前展开值 | Array<String> | - |
expandTrigger | 展开触发的方式可选值:'click', 'hover' | Enum | 'click' |
onExpand | 展开时触发的回调函数签名:Function(expandedValue: Array) => void参数:expandedValue: {Array} 各列展开值的数组 | Function | - |
multiple | 是否多选 | Boolean | false |
canOnlySelectLeaf | 单选时是否只能选中叶子节点 | Boolean | false |
canOnlyCheckLeaf | 多选时是否只能选中叶子节点 | Boolean | false |
checkStrictly | 父子节点是否选中不关联 | Boolean | false |
labelWidth | 文字区域宽度,当文字超过宽度时,结尾会以省略号显示,默认值为文字实际宽度 | String/Number | - |
showItemCount | 每一列展示的个数 | String/Number | 6 |
loadData | 异步加载数据函数签名:Function(data: Object) => void参数:data: {Object} 当前点击异步加载的数据 | Function | - |
代码示例
展示基本的单选用法。
查看源码在线预览
import { Cascader } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
label: "",
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);
this.setState({
label: extra.selectedPath.map(d => d.label).join(" / ")
});
}
render() {
return (
<div>
<div className="cascader-value">选择:{this.state.label}</div>
<Cascader
dataSource={this.state.data}
defaultValue="2975"
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.cascader-value {
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
可以通过labelWidth
, showItemCount
来定制组件宽高,其中通过labelWidth
可设置文字区域宽度,当文字超过宽度时,结尾会以省略号显示,默认值为文字实际宽度,通过showItemCount
可设置展示的菜单项个数。
查看源码在线预览
import { Cascader } 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: "和静县" }
]
}
]
}
];
ReactDOM.render(
<Cascader
defaultValue="3439"
defaultExpandedValue={["3371", "3430"]}
showItemCount="5"
labelWidth="100"
dataSource={dataSource}
/>,
mountNode
);
展示动态获取数据的用法。
查看源码在线预览
import { Cascader } 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 (
<Cascader
canOnlySelectLeaf
dataSource={this.state.dataSource}
loadData={this.onLoadData}
/>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.cascader-value {
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
展示可通过expandTrigger
来设置不同的展开触发行为,支持click
和hover
,默认值为click
。
查看源码在线预览
import { Radio, Cascader } 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>
<Cascader
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, Cascader } 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>
<Cascader
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 { Cascader } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
label: "",
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);
this.setState({
label: data.map(d => d.label).join(", ")
});
}
render() {
return (
<div>
<div className="cascader-value">选择:{this.state.label}</div>
<Cascader
multiple
defaultValue={["2975"]}
dataSource={this.state.data}
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.cascader-value {
width: 500px;
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
展示受控单选以及是否只能选择叶子项的用法。
查看源码在线预览
import { Checkbox, Cascader } from "@icedesign/base";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
canOnlySelectLeaf: 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({
canOnlySelectLeaf: !this.state.canOnlySelectLeaf,
value: null
});
}
handleChange(value, data, extra) {
console.log(value, data, extra);
this.setState({
value
});
}
render() {
return (
<div className="control-single-demo">
<label className="leaf-check">
<Checkbox
value={this.state.canOnlySelectLeaf}
onChange={this.handleCheck}
/>
<span className="leaf-text">开启只能选择叶子项</span>
</label>
<Cascader
canOnlySelectLeaf={this.state.canOnlySelectLeaf}
value={this.state.value}
dataSource={this.state.data}
onChange={this.handleChange}
/>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
.control-single-demo .leaf-check {
display: block;
margin-bottom: 10px;
}
.control-single-demo .leaf-text {
display: inline-block;
margin-left: 10px;
vertical-align: middle;
color: #666;
font-size: 14px;
}