# Cascader 级联选择

点击/鼠标移入元素，弹出气泡式的卡片浮层。

## 使用场景

- 需要从一组相关联的数据集合进行选择，例如省市区，公司层级，事物分类等。
- 从一个较大的数据集合中进行选择时，用多级分类进行分隔，方便选择。
- 在同层级中实现多级选择，优于 Select 组件。

## 案例演示

### 基本使用

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', children: [
      { value: 'yantaqu', label: '雁塔区', children: [ { value: 'zhonglou', label: '大雁塔' } ]}
    ]
  },
  { value: 'shangluo', label: '商洛市', disabled: true, children: [
      { value: 'zhenan', label: '镇安', children: [ { value: 'tayunshan', label: '塔云山' } ] }
  ]}
];

class Demo extends Component {
  constructor(props) {
    super(props);
  }

  onChange = (value, item) => {
    console.log(value, item);
  };

  render() {
    return <Cascader options={datas} defaultValue={['xian', 'yantaqu', 'zhonglou']} onChange={this.onChange} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 无数据项

设置 `showEmpty` 为 true 时，将会渲染默认的 notFoundContent。
当设置了 defaultValue，但是无 options 数据时，将直接显示 defaultValue 值

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [];

class Demo extends Component {

  onChange = (value, item) => {
    console.log(value, item);
  };

  render() {
    return (
      <div>
        <Cascader options={datas} placeholder="Please select" />
        <br />
        <Cascader options={datas} showEmpty placeholder="showEmpty is true" />
        <br />
        <Cascader defaultValue={['abcdef', '12345']} options={datas} showEmpty placeholder="showEmpty is true" />
        <br />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 允许选中父节点

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', children: [
      { value: 'yantaqu', label: '雁塔区', children: [ { value: 'zhonglou', label: '大雁塔' } ]}
    ]
  },
  { value: 'shangluo', label: '商洛市', children: [
      { value: 'zhenan', label: '镇安', children: [ { value: 'tayunshan', label: '塔云山' } ] }
  ]}
];

class Demo extends Component {
  constructor(props) {
    super(props);
  }

  onChange = (value, item) => {
    console.log(value, item);
  };

  render() {
    return <Cascader options={datas} enableParent onChange={this.onChange} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 自定义渲染

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', children: [
      { value: 'yantaqu', label: '雁塔区', children: [ { value: 'zhonglou', label: '大雁塔', code: '029' } ]}
    ]
  },
  { value: 'shangluo', label: '商洛市', children: [
      { value: 'zhenan', label: '镇安', children: [ { value: 'tayunshan', label: '塔云山', code: '0914' } ] }
  ]}
];

class Demo extends Component {

  handleAreaClick(e, label, option) {
    e.stopPropagation();
    console.log('clicked', label, option);
  }

  displayRender = (labels, selectedOptions) =>
    labels.map((label, i) => {
      const option = selectedOptions[i];
      if (i === labels.length - 1) {
        return (
          <span key={option.value}>
            {label} (<a onClick={e => this.handleAreaClick(e, label, option)}>{option.code}</a>)
          </span>
        );
      }
      return <span key={option.value}>{label} / </span>;
    });

  render() {
    return <Cascader options={datas} displayRender={this.displayRender} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 禁用某一项

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', children: [
      { value: 'yantaqu', label: '雁塔区', children: [ { value: 'zhonglou', label: '大雁塔' } ]}
    ]
  },
  { value: 'shangluo', label: '商洛市', disabled: true, children: [
      { value: 'zhenan', label: '镇安', children: [ { value: 'tayunshan', label: '塔云山' } ] }
  ]}
];

class Demo extends Component {
  render() {
    return <Cascader options={datas} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend


### 自定义字段名

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { code: 'xian', displayName: '西安市', items: [
      { code: 'yantaqu', displayName: '雁塔区', items: [ { code: 'zhonglou', displayName: '大雁塔' } ]}
    ]
  },
  { code: 'shangluo', displayName: '商洛市', disabled: true, items: [
      { code: 'zhenan', displayName: '镇安', items: [ { code: 'tayunshan', displayName: '塔云山' } ] }
  ]}
];

ReactDOM.render(
  <Cascader
    options={datas}
    fieldNames={{ label: 'displayName', value: 'code', children: 'items' }}
    placeholder="Please select"
  />, _react_runner_);
```
---demoend

### 动态加载下一级数据

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', isLeaf: false },
  { value: 'shangluo', label: '商洛市', isLeaf: false }
];

class Demo extends Component {
  state = {
    datas,
  };

  asyncData = selectedOptions => {
    const targetOption = selectedOptions[selectedOptions.length - 1];
    targetOption.loading = true;

    // load datas lazily
    setTimeout(() => {
      targetOption.loading = false;
      targetOption.children = [
        {
          label: `${targetOption.label} sub 1`,
          value: 'dynamic1',
        },
        {
          label: `${targetOption.label} sub 2`,
          value: 'dynamic2',
        },
      ];
      this.setState({
        datas: [...this.state.datas],
      });
    }, 1000);
  };

  render() {
    return <Cascader options={this.state.datas} asyncData={this.asyncData} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend


### 启用清除

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { value: 'xian', label: '西安市', children: [
      { value: 'yantaqu', label: '雁塔区', children: [ { value: 'zhonglou', label: '大雁塔' } ]}
    ]
  },
  { value: 'shangluo', label: '商洛市', disabled: true, children: [
      { value: 'zhenan', label: '镇安', children: [ { value: 'tayunshan', label: '塔云山' } ] }
  ]}
];

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: ['xian', 'yantaqu', 'zhonglou']
    };
  }

  onChange = (value, item) => {
    console.log(value, item);
    this.setState({
      value
    });
  };

  render() {
    const { value } = this.state;
    return <Cascader options={datas} hasClear value={value} onChange={this.onChange} placeholder="Please select" />;
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend


### 设置内部弹出层

> 此处的 pop 弹出层设置，需要脱离 Trigger 层，否则将会导致单词选择时，即会关闭 pop 层。

---demo
```js
import { Cascader } from 'amos-framework';

const datas = [
  { code: 'xian', displayName: '西安市', items: [
      { code: 'yantaqu', displayName: '雁塔区', items: [ { code: 'zhonglou', displayName: '大雁塔' } ]}
    ]
  },
  { code: 'shangluo', displayName: '商洛市', disabled: true, items: [
      { code: 'zhenan', displayName: '镇安', items: [ { code: 'tayunshan', displayName: '塔云山' } ] }
  ]}
];

ReactDOM.render((
  <div>
    <Cascader
      options={datas}
      fieldNames={{ label: 'displayName', value: 'code', children: 'items' }}
      placeholder="Please select"
      popoverProps={{
        fixed: true,
        getPopContainer: () => document.getElementById('my-cascader-pop')
      }}
    />
    <div id="my-cascader-pop" style={{ position: 'relative' }} />
  </div>
), _react_runner_);
```
---demoend

## props

| params | type | default | description |
| ------ | ------ | ------ | ------ |
| style | string | - | 自定义样式 |
| className | string | - | 自定义类名 |
| enableParent | boolean | false | 当此项为 true 时，点选每级菜单选项值都会发生变化，具体见上面的演示。仅在点击末位叶子结点时，才关闭 pop 层 |
| defaultValue | string[] | [] | 默认的选中项 |
| disabled | boolean | false | 禁用 |
| showEmpty | boolean | false | 是否显示空数据时，默认的下拉框提示 |
| displayRender | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` | 选择后展示的渲染函数 |
| expandTrigger | string | 'click' | 次级菜单的展开方式，可选 'click' 和 'hover' |
| fieldNames | object | `{ label: 'label', value: 'value', children: 'children' }` | 自定义 options 中 label name children 的字段 |
| asyncData | `(selectedOptions) => void` | - | 用于动态加载选项 |
| notFoundContent | ReactNode | '暂无数据' | 当下拉列表为空时显示的内容 |
| options | object | - | 可选项数据源 |
| placeholder | string | '请选择' | 输入框占位文本 |
| value | `string[]` | - | 指定选中项 |
| onChange | `(value, selectedOptions) => void` | - | 选择完成后的回调 |
| hasClear | bool | - | 是否可清除，since v1.8.6 添加 |
| popoverClassName | String | - | popover 弹出层自定义 className |
| popoverStyle | Object | - | 弹出层自定义样式 |
| popoverContentStyle | Object | - | 弹出层内容自定义样式 |
| popoverProps | Object | - | 弹出层 popover 配置项，since v1.9.3 添加。注意，不能传入 `open` |

> 启用 hasClear 时，也会调用 `onChange` 传参为 `([], null)`，此时第一个参数 value 将会赋值为空数组，第二个参数将赋值为 null。
