Commit d3afe22e authored by baiyaaaaa's avatar baiyaaaaa Committed by GitHub

Merge pull request #1401 from Leopoldthecoder/select-refactor

Select: refactor and bug fix
parents 395a1294 3ee74b29
......@@ -62,6 +62,16 @@
}]
}],
options4: [],
options5: [{
value: 'HTML',
label: 'HTML'
}, {
value: 'CSS',
label: 'CSS'
}, {
value: 'JavaScript',
label: 'JavaScript'
}],
cities: [{
value: 'Beijing',
label: 'Beijing'
......@@ -87,9 +97,10 @@
value4: '',
value5: [],
value6: '',
value7: [],
value7: '',
value8: '',
value9: [],
value10: [],
loading: false,
states: ["Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"]
};
......@@ -569,15 +580,58 @@ Enter keywords and search data from server.
```
:::
### Create new items
Create and select new items that are not included in select options
:::demo By using the `allow-create` attribute, users can create new items by typing in the input box. Note that for `allow-create` to work, `filterable` must be `true`.
```html
<template>
<el-select
v-model="value10"
multiple
filterable
allow-create
placeholder="Choose tags for your article">
<el-option
v-for="item in options5"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
<script>
export default {
data() {
return {
options5: [{
value: 'HTML',
label: 'HTML'
}, {
value: 'CSS',
label: 'CSS'
}, {
value: 'JavaScript',
label: 'JavaScript'
}],
value10: []
}
}
}
</script>
```
:::
### Select Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| multiple | whether multiple-select is activated | boolean | — | false |
| disabled | whether Select is disabled | boolean | — | false |
| clearable | whether single select can be cleared | boolean | — | false |
| multiple-limit | maximum number of options user can select when `multiple` is `true`. No limit when set to 0 | number | — | 0 |
| name | the name attribute of select input | string | — | — |
| placeholder | placeholder | string | — | Select |
| filterable | whether Select is filterable | boolean | — | false |
| allow-create | whether creating new items is allowed. To use this, `filterable` must be true | boolean | — | false |
| filter-method | custom filter method | function | — | — |
| remote | whether options are loaded from server | boolean | — | false |
| remote-method | custom remote search method | function | — | — |
......
......@@ -62,6 +62,16 @@
}]
}],
options4: [],
options5: [{
value: 'HTML',
label: 'HTML'
}, {
value: 'CSS',
label: 'CSS'
}, {
value: 'JavaScript',
label: 'JavaScript'
}],
cities: [{
value: 'Beijing',
label: '北京'
......@@ -87,9 +97,10 @@
value4: '',
value5: [],
value6: '',
value7: [],
value7: '',
value8: '',
value9: [],
value9: '',
value10: [],
loading: false,
states: ["Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"]
};
......@@ -129,7 +140,6 @@
### 基础用法
适用广泛的基础单选
:::demo `v-model`的值为当前被选中的`el-option`的 value 属性值
```html
<template>
......@@ -499,7 +509,6 @@
### 远程搜索
从服务器搜索数据,输入关键字进行查找
:::demo 为了启用远程搜索,需要将`filterable``remote`设置为`true`,同时传入一个`remote-method``remote-method`为一个`Function`,它会在输入值发生变化时调用,参数为当前输入值。需要注意的是,如果`el-option`是通过`v-for`指令渲染出来的,此时需要为`el-option`添加`key`属性,且其值需具有唯一性,比如此例中的`item.value`
```html
<template>
......@@ -573,15 +582,58 @@
```
:::
### 创建条目
可以创建并选中选项中不存在的条目
:::demo 使用`allow-create`属性即可通过在输入框中输入文字来创建新的条目。注意此时`filterable`必须为真。
```html
<template>
<el-select
v-model="value10"
multiple
filterable
allow-create
placeholder="请选择文章标签">
<el-option
v-for="item in options5"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
<script>
export default {
data() {
return {
options5: [{
value: 'HTML',
label: 'HTML'
}, {
value: 'CSS',
label: 'CSS'
}, {
value: 'JavaScript',
label: 'JavaScript'
}],
value10: []
}
}
}
</script>
```
:::
### Select Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------------- |---------- |-------------------------------- |-------- |
| multiple | 是否多选 | boolean | — | false |
| disabled | 是否禁用 | boolean | — | false |
| clearable | 单选时是否可以清空选项 | boolean | — | false |
| multiple-limit | 多选时用户最多可以选择的项目数,为 0 则不限制 | number | — | 0 |
| name | select input 的 name 属性 | string | — | — |
| placeholder | 占位符 | string | — | 请选择 |
| filterable | 是否可搜索 | boolean | — | false |
| allow-create | 是否允许用户创建新条目,需配合 `filterable` 使用 | boolean | — | false |
| filter-method | 自定义过滤方法 | function | — | — |
| remote | 是否为远程搜索 | boolean | — | false |
| remote-method | 远程搜索方法 | function | — | — |
......
......@@ -140,17 +140,15 @@ export default {
return (
<span class="el-pagination__sizes">
<el-select
size="small"
value={ this.$parent.internalPageSize }
on-change={ this.handleChange }
width={ 110 }>
on-input={ this.handleChange }>
{
this.pageSizes.map(item =>
<el-option
value={ item }
label={ item + ' ' + this.t('el.pagination.pagesize') }>
</el-option>
)
<el-option
value={ item }
label={ item + ' ' + this.t('el.pagination.pagesize') }>
</el-option>
)
}
</el-select>
</span>
......
......@@ -4,7 +4,11 @@
@click.stop="selectOptionClick"
class="el-select-dropdown__item"
v-show="visible"
:class="{ 'selected': itemSelected, 'is-disabled': disabled || groupDisabled, 'hover': parent.hoverIndex === index }">
:class="{
'selected': itemSelected,
'is-disabled': disabled || groupDisabled || limitReached,
'hover': parent.hoverIndex === index
}">
<slot>
<span>{{ currentLabel }}</span>
</slot>
......@@ -30,6 +34,7 @@
type: Boolean,
default: false
},
created: Boolean,
disabled: {
type: Boolean,
default: false
......@@ -63,22 +68,20 @@
},
itemSelected() {
if (Object.prototype.toString.call(this.parent.selected) === '[object Object]') {
return this === this.parent.selected;
} else if (Array.isArray(this.parent.selected)) {
if (!this.parent.multiple) {
return this.value === this.parent.value;
} else {
return this.parent.value.indexOf(this.value) > -1;
}
},
currentSelected() {
return this.selected || (this.parent.multiple ? this.parent.value.indexOf(this.value) > -1 : this.parent.value === this.value);
}
},
watch: {
currentSelected(val) {
if (val === true) {
this.dispatch('ElSelect', 'addOptionToValue', this);
limitReached() {
if (this.parent.multiple) {
return !this.itemSelected &&
this.parent.value.length >= this.parent.multipleLimit &&
this.parent.multipleLimit > 0;
} else {
return false;
}
}
},
......@@ -103,7 +106,7 @@
queryChange(query) {
// query 里如果有正则中的特殊字符,需要先将这些字符转义
let parsedQuery = query.replace(/(\^|\(|\)|\[|\]|\$|\*|\+|\.|\?|\\|\{|\}|\|)/g, '\\$1');
this.visible = new RegExp(parsedQuery, 'i').test(this.currentLabel);
this.visible = new RegExp(parsedQuery, 'i').test(this.currentLabel) || this.created;
if (!this.visible) {
this.parent.filteredOptionsCount--;
}
......@@ -122,10 +125,6 @@
this.parent.filteredOptionsCount++;
this.index = this.parent.options.indexOf(this);
if (this.currentSelected === true) {
this.dispatch('ElSelect', 'addOptionToValue', [this, true]);
}
this.$on('queryChange', this.queryChange);
this.$on('handleGroupDisabled', this.handleGroupDisabled);
this.$on('resetIndex', this.resetIndex);
......
This diff is collapsed.
......@@ -23,6 +23,8 @@
width: 110px;
input {
padding-right: 25px;
border-radius: var(--border-radius-small);
height: 28px;
}
}
......
......@@ -51,5 +51,9 @@
max-height: var(--select-dropdown-max-height);
box-sizing: border-box;
overflow-y: auto;
@when empty {
padding: 0;
}
}
}
......@@ -12,13 +12,6 @@
display: block;
position: relative;
@when small {
& input {
border-radius: var(--border-radius-small);
height: 28px;
}
}
&:hover {
.el-input__inner {
border-color: var(--select-border-color-hover);
......
......@@ -3,9 +3,10 @@ import Select from 'packages/select';
describe('Select', () => {
const getSelectVm = (configs = {}, options) => {
['multiple', 'clearable', 'filterable', 'remote'].forEach(config => {
['multiple', 'clearable', 'filterable', 'allowCreate', 'remote'].forEach(config => {
configs[config] = configs[config] || false;
});
configs.multipleLimit = configs.multipleLimit || 0;
if (!options) {
options = [{
value: '选项1',
......@@ -35,8 +36,10 @@ describe('Select', () => {
<el-select
v-model="value"
:multiple="multiple"
:multiple-limit="multipleLimit"
:clearable="clearable"
:filterable="filterable"
:allow-create="allowCreate"
:filterMethod="filterMethod"
:remote="remote"
:loading="loading"
......@@ -55,8 +58,10 @@ describe('Select', () => {
return {
options,
multiple: configs.multiple,
multipleLimit: configs.multipleLimit,
clearable: configs.clearable,
filterable: configs.filterable,
allowCreate: configs.allowCreate,
loading: false,
filterMethod: configs.filterMethod && configs.filterMethod(this),
remote: configs.remote,
......@@ -349,6 +354,23 @@ describe('Select', () => {
}, 100);
});
it('allow create', done => {
vm = getSelectVm({ filterable: true, allowCreate: true });
const select = vm.$children[0];
select.selectedLabel = 'new';
select.onInputChange();
select.visible = true;
setTimeout(() => {
const options = document.querySelectorAll('.el-select-dropdown__item span');
const target = [].filter.call(options, option => option.innerText === 'new');
target[0].click();
setTimeout(() => {
expect(select.value.indexOf('new') > -1).to.true;
done();
}, 50);
}, 50);
});
it('multiple select', done => {
vm = getSelectVm({ multiple: true });
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
......@@ -368,6 +390,20 @@ describe('Select', () => {
}, 100);
});
it('multiple limit', done => {
vm = getSelectVm({ multiple: true, multipleLimit: 1 });
const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
options[1].click();
setTimeout(() => {
expect(vm.value.indexOf('选项2') > -1).to.true;
options[3].click();
setTimeout(() => {
expect(vm.value.indexOf('选项4')).to.equal(-1);
done();
}, 50);
}, 50);
});
it('multiple remote search', done => {
const remoteMethod = vm => {
return query => {
......@@ -387,21 +423,23 @@ describe('Select', () => {
remoteMethod
});
const select = vm.$children[0];
select.query = '';
setTimeout(() => {
expect(select.filteredOptionsCount).to.equal(1);
select.query = '';
select.options[0].$el.click();
vm.$nextTick(() => {
expect(vm.value[0]).to.equal('选项4');
select.deletePrevTag({ target: select.$refs.input });
select.deletePrevTag({ target: select.$refs.input });
select.resetInputState({ keyCode: 1 });
vm.$nextTick(() => {
select.query = '';
setTimeout(() => {
expect(select.filteredOptionsCount).to.equal(1);
select.query = '';
select.options[0].$el.click();
vm.$nextTick(() => {
expect(vm.value.length).to.equal(0);
done();
expect(vm.value[0]).to.equal('选项4');
select.deletePrevTag({ target: select.$refs.input });
select.deletePrevTag({ target: select.$refs.input });
select.resetInputState({ keyCode: 1 });
vm.$nextTick(() => {
expect(vm.value.length).to.equal(0);
done();
});
});
});
}, 250);
}, 250);
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment