# TreeSelect

下拉树选择

## Usage

```js
import { TreeSelect } from 'amos-framework';

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    onChange={value => console.log(value)}
  />
  , _react_runner_);
```

## 案例演示

### TreeSelect 基本使用

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: '很长的标题内容1', disabled: true, children: [
      { key: 'p1-2-1', value:'p1-2-1', title: '很长的标题内容1-1' },
      { key: 'p1-2-2', value:'p1-2-2', title: '很长的标题内容1-2' },
    ] },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    onChange={value => console.log(value)}
    pretty
  />
  , _react_runner_);
```
---demoend

### TreeSelect 可控

> 当 value 存在，但与树数据不匹配时，则会显示 `noMatchingContent` 内容

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

class Demo extends Component {
  state = {
    value: 'ddd'
  };

  onChange = (value) => {
    this.setState({
      value
    });
  }

  render() {
    return (
      <TreeSelect
        value={this.state.value}
        dataSource={dataSource}
        onChange={this.onChange}
      />
    );
  }
}

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

### TreeSelect 自定义 renderOption

如果数据中，显示名称，没有采用 `title` 字段，此时可以进行自定义渲染。

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

const dataSource = [
  { key: 'p1', value:'p1', label: 'p1', children: [
    { key: 'p1-1', value:'p1-1', label: 'p1-1' },
    { key: 'p1-2', value:'p1-2', label: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', label: 'p2', children: [
    { key: 'p2-1', value:'p2-1', label: 'p2-1' },
    { key: 'p2-2', value:'p2-2', label: 'p2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    onChange={value => console.log(value)}
    renderOption={(item, isSelect) => {
      if (isSelect){
        return item.label
      } else {
        // tree 自定义渲染数据
        return {
          ...item,
          title: item.label
        };
      }
    }}
  />
  , _react_runner_);
```
---demoend

### TreeSelect 多选

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

const dataSource = [
  { key: 'p1', value:'p1', title: '节点1', children: [
    { key: 'p1-1', value:'p1-1', title: '节点1-1' },
    { key: 'p1-2', value:'p1-2', title: '节点1-2' , children: [
      { key: 'p1-2-1', value:'p1-2-1', title: '节点1-2-1' },
      { key: 'p1-2-2', value:'p1-2-2', title: '节点1-2-2' },
    ]},
  ] },
    { key: 'p2', value:'p2', title: '节点2', children: [
    { key: 'p2-1', value:'p2-1', title: '节点2-1' },
    { key: 'p2-2', value:'p2-2', title: '节点2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    multiple
    dataSource={dataSource}
    onChange={value => console.log(value)}
  />
  , _react_runner_);
```
---demoend

### TreeSelect 禁用

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    disabled
    onChange={value => console.log(value)}
  />
  , _react_runner_);
```
---demoend

### TreeSelect 设置内部弹出层

将 pop 层绘制在指定的容器内

why not `popInset`? 由于 pop 层在 trigger 层内部，tree 的展开事件必然会触发 trigger 显隐。

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render(
  <span>
    <TreeSelect
      dataSource={dataSource}
      onChange={value => console.log(value)}
      popoverProps={{
        fixed: true,
        getPopContainer: () => document.getElementById('mytag1122')
      }}
    />
    <div style={{ position: 'relative' }} id="mytag1122" />
  </span>
  , _react_runner_);
```
---demoend

### TreeSelect 开启搜索

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    searchable
    onChange={value => console.log(value)}
  />
  , _react_runner_);
```
---demoend

### TreeSelect 自定义搜索

> 输入 `p` 进行匹配试试

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

const dataSource = [
  { key: '1', value:'1', title: 'PP1', children: [
    { key: '1-1', value:'1-1', title: 'PP1-1' },
    { key: '1-2', value:'1-2', title: 'PB1-2' },
  ] },
    { key: '2', value:'2', title: 'PD2', children: [
    { key: '2-1', value:'2-1', title: 'PG2-1' },
    { key: '2-2', value:'2-2', title: 'PL2-2' },
  ] }
];

function filterTreeNode(inputValue, child) {
  return child.title.toLocaleLowerCase().includes(inputValue.toLocaleLowerCase())
}

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    searchable
    onChange={value => console.log(value)}
    filterTreeNode={filterTreeNode}
  />
  , _react_runner_);
```
---demoend


### TreeSelect 大数据量的搜索

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

const dataSource = [];
for (let i = 0; i < 500; i++) {
  const item = {
    key: i,
    value: i,
    title: `p-${i}`,
    children: []
  };
	for (let j = 0; j < 5; j++) {
    item.children.push({
      key: `${i}-${j}`,
      value: `${i}-${j}`,
      title: `p-${i}-${j}`
    });
  }
	dataSource.push(item);
}

ReactDOM.render(
  <TreeSelect
    dataSource={dataSource}
    searchable
    onChange={value => console.log(value)}
  />
  , _react_runner_);
```
---demoend

### TreeSelect 可清除

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

const dataSource = [
  { key: 'p1', value:'p1', title: 'p1', children: [
    { key: 'p1-1', value:'p1-1', title: 'p1-1' },
    { key: 'p1-2', value:'p1-2', title: 'p1-2' },
  ] },
    { key: 'p2', value:'p2', title: 'p2', children: [
    { key: 'p2-1', value:'p2-1', title: 'p2-1' },
    { key: 'p2-2', value:'p2-2', title: 'p2-2' },
  ] }
];

ReactDOM.render((
  <div>
    单选：
    <TreeSelect
      dataSource={dataSource}
      onChange={value => console.log(value)}
      hasClear
    />
    <p style={{ marginTOp: 20 }}/>
    多选：
    <TreeSelect
      multiple
      dataSource={dataSource}
      onChange={value => console.log(value)}
      hasClear
    />
  </div>
), _react_runner_);
```
---demoend

### TreeSelect 多选搜索

> 搜索时，选中某一个值之后，清空搜索值继续搜索，然后执行选中，查看两个案例的区别。

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


function mockData(count, childCnt){
  const result = [];
  for (let i = 0; i < count; i++) {
    const k = `p${i}`;
    const item = {
      key: k,
      value: k,
      title: k,
      children: []
    };
    for (let j = 0; j < childCnt; j++) {
      const ck = `${k}-${j}`;
      item.children.push({
        key: ck,
        value: ck,
        title: ck
      });
    }

    result.push(item);
  }

  return result;
}

const dataSource = mockData(5, 3);

class Demo extends Component {
  state = {
    value: []
  };

  onChange = value => {
    this.setState({
      value
    });
  };

  render() {
    return (
      <TreeSelect
        value={this.state.value}
        multiple
        searchable
        dataSource={dataSource}
        onChange={this.onChange}
      />
    );
  }
}

class Demo2 extends Component {
  state = {
    value: []
  };

  onChange = value => {
    this.setState({
      value
    });
  };

  render() {
    return (
      <TreeSelect
        value={this.state.value}
        multiple
        searchable
        keepSelected
        dataSource={dataSource}
        onChange={this.onChange}
      />
    );
  }
}

ReactDOM.render((
  <div>
    keepSelected为false：<Demo />
    <br />
    <br />
    keepSelected为 true：<Demo2 />
  </div>
), _react_runner_);
```
---demoend

## props

### MultiSelect props

| params | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-tree-select` | 组件默认clssname prefix |
| className | String | - | 组件自定义clssname |
| popoverClassName | string | - |popover 外层 自定义 className |
| value | Number[] or String[] | - | 值，单选为字符串，多选为数组，与数据源 value 字段对应 |
| defaultValue | Number[] or String[] | - | 初始化值（不可控） |
| onChange | func | - | 切换选择后的回调，回调参数为选中的节点（多选模式为数组） |
| disabled | bool | - | 是否禁用 |
| dataSource | array | - | 树结构数据源，与 Tree 组件不同的是需要 value 字段一一对应 |
| renderOption | `func: (item, isSelect) => {}` | - | 同 Tree processDataProps, (item, isSelect) => {} |
| placeholder | String | 请选择 | 无 `value` 时显示的内容 |
| multiple | bool | - | 是否多选，开启此属性后才会出现复选框，多选模式 value 要求数组格式 |
| minWidth | number | 160 | 最小宽度，默认 160 |
| searchable | bool | - | 是否可搜索，搜索默认为 `treeNodeFilterProp` 指定的字段 |
| treeNodeFilterProp | string | `value` | 搜索匹配字段，默认为 value |
| filterTreeNode | func: `(input, child, props) => boolean` | - | 自定义匹配方法 |
| searchPlaceholder | String | - | 搜索框 placeholder |
| searchStyle | Object | - | 启用 search 时，search 组件的样式, 数据格式为：`{ style: {}, inputStyle: {}, btnStyle: {} }` |
| notFoundContent | ReactNode | `无选项` | 搜索无匹配时显示内容 |
| noMatchingContent | string | 无匹配选项 | 有 `value` 但无选项匹配时显示的内容，默认`无匹配选项`，since v1.9.7 添加 |
| hasClear | bool | - | 是否可清除，since v1.9.1 添加 |
| treeProps | Object | - | tree 支持的更多 props，since v1.9.3 添加 |
| pretty | bool | - | 启用内置美化，主要用于内部组件统一效果，如：滚动条 |
| keepSelected | bool | - | 开启搜索，多选时，如果清空了 tree data ，这会导致选择的数据重置。此时可以通过设置该值为 true，采用 display 方式隐藏未匹配项 |

> 注意，如果发现下拉菜单跟随页面滚动，设置 `closeOnScroll` 为 `true`，如果还不起效，请检查 `document` 是否无法触发 `scroll` 事件。如果是自定义的 `scrollbar`，无法触发 `document`时，当scroll start时可手动设置 `scrolling=true`, scroll stop时，设置 `scrolling=false`。同时防止主文件body节点设置 `overflow：auto/scroll/hidden`，以防造成scroll滑动监听整体失效。

## Methods

* closeDropdown()
