# MultiSelect

下拉多选

进行多个或单个类型指定时使用

**tips：** 可通过键盘上下键进行列选择，enter 键确认选择。注意，如果 开启`closeOnScroll`，则无法使用

默认搜索时，仅匹配 `label` 即：`Option children`，可通过 `matchValue=true` 开启匹配 `value` 和 `label`

## Usage

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

const Option = MultiSelect.Option;

state = {
  values: []
};

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' }
];

<MultiSelect
  values={this.state.values}
  onChange={values => this.setState({ values })}
  data={data}
  renderOption={item => <Option value={item.id}>{item.name}</Option>}
/>
```

## 案例演示

### MultiSelect 基本使用

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

const Option = MultiSelect.Option;

ReactDOM.render(
  <MultiSelect defaultValues={['1', '2']} onChange={values => console.log(values)}>
    <Option value="0">张三</Option>
    <Option value="1">李四</Option>
    <Option value="2">王五</Option>
  </MultiSelect>
  , _react_runner_);
```
---demoend

### MultiSelect 启用清除

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

const Option = MultiSelect.Option;

ReactDOM.render(
  <MultiSelect defaultValues={['1', '2']} hasClear onChange={values => console.log(values)}>
    <Option value="0">张三</Option>
    <Option value="1">李四</Option>
    <Option value="2">王五</Option>
  </MultiSelect>
  , _react_runner_);
```
---demoend

### MultiSelect data 数据

> 注意，data 数据时，value 可以为 `false、true、undefined、null` 中的任何一种，当数据项不为 true 时，MultiSelect 组件的值，将采用 `children`，即本例中的 name 字段。
>
> 建议：尽量不要用 bool 类型数据作为 value。同时也尽可能的不要采用 `undefined、null 、''` 等作为 value。

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

const Option = MultiSelect.Option;

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' },
// key 值可以传入  false、true、undefined、null
// 注意，当 key 为 true 时，将会使用 key，其它 `false` 状态的，将均使用 name
  { id: false, name: '赵六' },
  { id: true, name: '孙七' },
  { id: null, name: '周八' },
  { name: '吴九' }, // id 为 undefined
  { id: '', name: '郑十' } // id 为 空字符串
];

function handleChange(values){
  console.log('selects:', values);
}

ReactDOM.render(
  <MultiSelect
    defaultValues={[1, 2]}
    data={data}
    onChange={handleChange}
    renderOption={item => <Option value={item.id}>{item.name}</Option>}
  />
  , _react_runner_);
```
---demoend

### MultiSelect 可控

---demo
```js
import { MultiSelect, Button } from 'amos-framework';

const Option = MultiSelect.Option;

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' }
];

class Demo extends Component {

  state = {
    values: []
  };

  onChange = (values) => {
    console.log('m-select:', values);
    this.setState({
      values
    });
  }

  clear = () => {
    // 清除时，可直接将 values 设置为 `undefined | null | []` 即可，推荐 设置为 `[]`
    this.setState({
      // values: undefined
      // values: null
      values: []
    });
  }

  render() {
    const { values } = this.state;
    return (
      <div>
        <MultiSelect
          values={values}
          onChange={this.onChange}
          data={data}
          renderOption={item => <Option value={item.id}>{item.name}</Option>}
        />
        <Button onClick={this.clear}>清除</Button>
      </div>
    );
  }
}

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

### MultiSelect 初始同时设置values 和 defaultValues

> 如果初始时同时设置了 values 为 defaultValues 时，defaultValues 将不起作用。
>
> 此时，如果希望设置初始值，可直接将初始值设置在 values 中。

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

const Option = MultiSelect.Option;

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' }
];

class Demo extends Component {
  state = {
  };

  onChange = (values) => {
    console.log('m-select:', values);
    this.setState({
      values
    });
  }

  render() {
    const { values } = this.state;
    return (
      <MultiSelect
        values={values}
        defaultValues={[0, 1]}
        onChange={this.onChange}
        data={data}
        renderOption={item => <Option value={item.id}>{item.name}</Option>}
      />
    );
  }
}

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

### MultiSelect 自定义标签

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

const Option = MultiSelect.Option;

ReactDOM.render(
  <MultiSelect defaultValues={['tag1']} tagable>
    <Option>tag1</Option>
    <Option>tag2</Option>
    <Option>tag3</Option>
  </MultiSelect>
  , _react_runner_);
```
---demoend

### SingleTagSelect 自定义标签

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

const Option = MultiSelect.Option;
const SingleTagSelect = MultiSelect.SingleTagSelect;

class MyDemo extends Component {
  state = {
    value: ''
  };

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

  remove = () => {
    // 通过设置为 空、undefined、null 来实现删除
    this.setState({
      value: ''
    });
  }

  render() {
    const { value } = this.state;
    return (
      <div>
        <SingleTagSelect hasClear value={value} tagable onChange={this.handleChange}>
          <Option>tag1</Option>
          <Option>tag2</Option>
          <Option>tag3</Option>
        </SingleTagSelect>
        <Button onClick={this.remove}>清除</Button>
      </div>
    );
  }
}

function handleChange(value){
  console.log(value);
}

ReactDOM.render((
  <div>
    基本使用：
    <SingleTagSelect defaultValue="tag1" tagable onChange={handleChange}>
      <Option>tag1</Option>
      <Option>tag2</Option>
      <Option>tag3</Option>
    </SingleTagSelect>
    <br />
    <br />
    启用清除：
    <SingleTagSelect hasClear defaultValue="tag1" tagable onChange={handleChange}>
      <Option>tag1</Option>
      <Option>tag2</Option>
      <Option>tag3</Option>
    </SingleTagSelect>
    <br />
    外部清除：<MyDemo />
  </div>
), _react_runner_);
```
---demoend

### SingleTagSelect 自定义标签存储新数据

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

const Option = MultiSelect.Option;
const SingleTagSelect = MultiSelect.SingleTagSelect;

class Demo extends Component {

  state = {
    value: '',
    datas: [
    'tag1', 'tag2', 'tag3', 'tag4', 'tag5'
    ]
  };

  onChange = (value) => {
    const { datas } = this.state;
    if (!datas.includes(value)){
      this.setState({
        value,
        datas: [
          ...datas,
          value
        ]
      });
    } else {
      this.setState({
        value
      });
    }
  }

  render() {
    const { value, datas } = this.state;
    return (
    <SingleTagSelect value={value} defaultValue="tag1" tagable onChange={this.onChange}>
      {
        datas.map(d => <Option key={d}>{d}</Option>)
      }
    </SingleTagSelect>
    );
  }
}

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

### MultiSelect 禁用

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

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

### MultiSelect 设置内部弹出层

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

const Option = MultiSelect.Option;

ReactDOM.render(
  <MultiSelect popInset defaultValues={['1', '2']} onChange={values => console.log(values)}>
    <Option value="0">张三</Option>
    <Option value="1">李四</Option>
    <Option value="2">王五</Option>
  </MultiSelect>
  , _react_runner_);
```
---demoend

### 使用内置的 pretty

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

const SingleTagSelect = MultiSelect.SingleTagSelect;
const Option = MultiSelect.Option;

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' },
  { id: 3, name: '赵六' },
  { id: 4, name: '孙七' },
  { id: 5, name: '周八' },
  { id: 6, name: '吴九' },
  { id: 7, name: '郑十' }
];

function handleChange(values){
  console.log('selects:', values);
}

ReactDOM.render(
  <div>
    MultiSelect多选：
    <MultiSelect
      pretty
      defaultValues={[1, 2]}
      data={data}
      onChange={handleChange}
      renderOption={item => <Option value={item.id}>{item.name}</Option>}
    />
    <br />
    <br />
    SingleTagSelect：
    <SingleTagSelect
      pretty
      data={data}
      onChange={handleChange}
      renderOption={item => <Option value={item.id}>{item.name}</Option>}
    />
  </div>
  , _react_runner_);
```
---demoend


### MultiSelect 搜索时匹配 value 和 label

> 设置 `matchValue = true`

---demo
```js
import { MultiSelect, Button } from 'amos-framework';

const Option = MultiSelect.Option;

const data = [
  { id: 0, name: '张三' },
  { id: 1, name: '李四' },
  { id: 2, name: '王五' }
];

class Demo extends Component {

  state = {
    values: []
  };

  onChange = (values) => {
    console.log('m-select:', values);
    this.setState({
      values
    });
  }

  render() {
    const { values } = this.state;
    return (
      <MultiSelect
        values={values}
        onChange={this.onChange}
        data={data}
        matchValue
        renderOption={item => <Option value={item.id}>{item.name}</Option>}
      />
    );
  }
}

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

## props

### MultiSelect props

| params | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-multi-select` | 组件默认clssname prefix |
| className | String | - | 组件自定义clssname |
| popoverClassName | string | - |popover 外层 自定义 className |
| values | Number[] or String[] | - | 选中的值 |
| defaultValues | Number[] or String[] | - | 初始化时选中的值（不可控） |
| onChange | func | - | 切换选择后的回调，参数为选中的值 |
| disabled | bool | - | 是否禁用 |
| tagable | bool | - | 是否开启自定义标签输入功能 |
| data | array | - | 数据源，结合 renderOption 属性定义 Option 渲染逻辑 |
| renderOption | func | - | data 方式时 Option 渲染回调，参数为当前数据和索引，返回一个 Option |
| placeholder | String | 请选择 | 无 `values` 时显示的内容 |
| size | String | - | 尺寸,除了默认值外，可选值 `sm`、`lg` |
| minWidth | number | 160 | 最小宽度，默认 160 |
| noOptionsContent | String | 无选项 | 搜索无匹配项时显示的内容，默认`无选项` |
| checkAllContent | String | 全选 | 全选切换复选框显示的文字，默认`全选` |
| closeOnScroll | bool | false | 外围进行滚动时，关闭dropdown，需要`document`能触发 `scroll` 事件。默认为false |
| scrolling | bool | - | 正在进行滚动，针对无法自动触发`scroll`时，可手动进行设置`scrolling`, 以强制关闭dropdown |
| popInset | bool | - | 弹出层是否内置，默认在 body 上，since v1.8.12 添加 |
| hasClear | bool | - | 是否可清除，since v1.9.1 添加 |
| matchValue | bool | - | 搜索时是匹配value，设置为 `true` 时，搜索时，则匹配 value 和 label，since v1.13.2 添加 |

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

### MultiSelect.Option props

同 Select.option

| params | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-select` | 组件默认clssname prefix |
| className | String | - | 组件自定义clssname |
| value | Number or String | - | 值，与 `Select value` 对应，数据类型也要一致 |
| selected | bool | - | 选中 |
| active | bool | - | 当前 |

### MultiSelect.SingleTagSelect props

与 MultiSelect props 基本相同，除了 values 和 defaultValues，无 checkAllContent。

| params | type | default | description |
|--------- |-------- |--------- |-------- |
| prefixCls | String | `amos-singletag-select` | 组件默认clssname prefix |
| className | String | - | 组件自定义clssname |
| popoverClassName | string | - |popover 外层 自定义 className |
| value | Number or String | - | 选中的值 |
| defaultValue | Number or String | - | 初始化时选中的值（不可控） |
| onChange | func | - | 切换选择后的回调，参数为选中的值 |
| disabled | bool | - | 是否禁用 |
| tagable | bool | - | 是否开启自定义标签输入功能 |
| data | array | - | 数据源，结合 renderOption 属性定义 Option 渲染逻辑 |
| renderOption | func | - | data 方式时 Option 渲染回调，参数为当前数据和索引，返回一个 Option |
| placeholder | String | 请选择 | 无 `values` 时显示的内容 |
| noOptionsContent | String | 无选项 | 搜索无匹配项时显示的内容，默认`无选项` |
| closeOnScroll | bool | false | 外围进行滚动时，关闭dropdown，需要`document`能触发 `scroll` 事件。默认为false |
| scrolling | bool | - | 正在进行滚动，针对无法自动触发`scroll`时，可手动进行设置`scrolling`, 以强制关闭dropdown |

## Methods

* closeDropdown()
