mirror of https://github.com/ElemeFE/element
Select: remove resetIndex
parent
f477390c79
commit
f23629ac43
|
@ -0,0 +1,54 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
hoverOption: -1
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
optionsAllDisabled() {
|
||||
return this.options.length === this.options.filter(item => item.disabled === true).length;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
hoverIndex(val) {
|
||||
if (typeof val === 'number' && val > -1) {
|
||||
this.hoverOption = this.options[val] || {};
|
||||
}
|
||||
this.options.forEach(option => {
|
||||
option.hover = this.hoverOption === option;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
navigateOptions(direction) {
|
||||
if (!this.visible) {
|
||||
this.visible = true;
|
||||
return;
|
||||
}
|
||||
if (this.options.length === 0 || this.filteredOptionsCount === 0) return;
|
||||
if (!this.optionsAllDisabled) {
|
||||
if (direction === 'next') {
|
||||
this.hoverIndex++;
|
||||
if (this.hoverIndex === this.options.length) {
|
||||
this.hoverIndex = 0;
|
||||
}
|
||||
} else if (direction === 'prev') {
|
||||
this.hoverIndex--;
|
||||
if (this.hoverIndex < 0) {
|
||||
this.hoverIndex = this.options.length - 1;
|
||||
}
|
||||
}
|
||||
const option = this.options[this.hoverIndex];
|
||||
if (option.disabled === true ||
|
||||
option.groupDisabled === true ||
|
||||
!option.visible) {
|
||||
this.navigateOptions(direction);
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => this.scrollToOption(this.hoverOption.$el));
|
||||
}
|
||||
}
|
||||
};
|
|
@ -7,7 +7,7 @@
|
|||
:class="{
|
||||
'selected': itemSelected,
|
||||
'is-disabled': disabled || groupDisabled || limitReached,
|
||||
'hover': parent.hoverIndex === index
|
||||
'hover': hover
|
||||
}">
|
||||
<slot>
|
||||
<span>{{ currentLabel }}</span>
|
||||
|
@ -26,6 +26,8 @@
|
|||
|
||||
componentName: 'ElOption',
|
||||
|
||||
inject: ['select'],
|
||||
|
||||
props: {
|
||||
value: {
|
||||
required: true
|
||||
|
@ -43,7 +45,8 @@
|
|||
index: -1,
|
||||
groupDisabled: false,
|
||||
visible: true,
|
||||
hitState: false
|
||||
hitState: false,
|
||||
hover: false
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -60,27 +63,19 @@
|
|||
return this.value || this.label || '';
|
||||
},
|
||||
|
||||
parent() {
|
||||
let result = this.$parent;
|
||||
while (!result.isSelect) {
|
||||
result = result.$parent;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
itemSelected() {
|
||||
if (!this.parent.multiple) {
|
||||
return this.isEqual(this.value, this.parent.value);
|
||||
if (!this.select.multiple) {
|
||||
return this.isEqual(this.value, this.select.value);
|
||||
} else {
|
||||
return this.contains(this.parent.value, this.value);
|
||||
return this.contains(this.select.value, this.value);
|
||||
}
|
||||
},
|
||||
|
||||
limitReached() {
|
||||
if (this.parent.multiple) {
|
||||
if (this.select.multiple) {
|
||||
return !this.itemSelected &&
|
||||
this.parent.value.length >= this.parent.multipleLimit &&
|
||||
this.parent.multipleLimit > 0;
|
||||
this.select.value.length >= this.select.multipleLimit &&
|
||||
this.select.multipleLimit > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -89,10 +84,10 @@
|
|||
|
||||
watch: {
|
||||
currentLabel() {
|
||||
if (!this.created && !this.parent.remote) this.dispatch('ElSelect', 'setSelected');
|
||||
if (!this.created && !this.select.remote) this.dispatch('ElSelect', 'setSelected');
|
||||
},
|
||||
value() {
|
||||
if (!this.created && !this.parent.remote) this.dispatch('ElSelect', 'setSelected');
|
||||
if (!this.created && !this.select.remote) this.dispatch('ElSelect', 'setSelected');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -101,7 +96,7 @@
|
|||
if (!this.isObject) {
|
||||
return a === b;
|
||||
} else {
|
||||
const valueKey = this.parent.valueKey;
|
||||
const valueKey = this.select.valueKey;
|
||||
return getValueByPath(a, valueKey) === getValueByPath(b, valueKey);
|
||||
}
|
||||
},
|
||||
|
@ -110,7 +105,7 @@
|
|||
if (!this.isObject) {
|
||||
return arr.indexOf(target) > -1;
|
||||
} else {
|
||||
const valueKey = this.parent.valueKey;
|
||||
const valueKey = this.select.valueKey;
|
||||
return arr.some(item => {
|
||||
return getValueByPath(item, valueKey) === getValueByPath(target, valueKey);
|
||||
});
|
||||
|
@ -123,7 +118,7 @@
|
|||
|
||||
hoverItem() {
|
||||
if (!this.disabled && !this.groupDisabled) {
|
||||
this.parent.hoverIndex = this.parent.options.indexOf(this);
|
||||
this.select.hoverIndex = this.select.options.indexOf(this);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -138,27 +133,20 @@
|
|||
let parsedQuery = String(query).replace(/(\^|\(|\)|\[|\]|\$|\*|\+|\.|\?|\\|\{|\}|\|)/g, '\\$1');
|
||||
this.visible = new RegExp(parsedQuery, 'i').test(this.currentLabel) || this.created;
|
||||
if (!this.visible) {
|
||||
this.parent.filteredOptionsCount--;
|
||||
this.select.filteredOptionsCount--;
|
||||
}
|
||||
},
|
||||
|
||||
resetIndex() {
|
||||
this.$nextTick(() => {
|
||||
this.index = this.parent.options.indexOf(this);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.parent.options.push(this);
|
||||
this.parent.cachedOptions.push(this);
|
||||
this.parent.optionsCount++;
|
||||
this.parent.filteredOptionsCount++;
|
||||
this.index = this.parent.options.indexOf(this);
|
||||
this.select.options.push(this);
|
||||
this.select.cachedOptions.push(this);
|
||||
this.select.optionsCount++;
|
||||
this.select.filteredOptionsCount++;
|
||||
this.index = this.select.options.indexOf(this);
|
||||
|
||||
this.$on('queryChange', this.queryChange);
|
||||
this.$on('handleGroupDisabled', this.handleGroupDisabled);
|
||||
this.$on('resetIndex', this.resetIndex);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
@keydown.esc.stop.prevent="visible = false"
|
||||
@keydown.delete="deletePrevTag"
|
||||
v-model="query"
|
||||
@input="e => handleQueryChange(e.target.value)"
|
||||
:debounce="remote ? 300 : 0"
|
||||
v-if="filterable"
|
||||
:style="{ width: inputLength + 'px', 'max-width': inputWidth - 42 + 'px' }"
|
||||
|
@ -50,6 +51,7 @@
|
|||
:disabled="disabled"
|
||||
:readonly="!filterable || multiple"
|
||||
:validate-event="false"
|
||||
:class="{ 'is-focus': visible }"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
@click="handleIconClick"
|
||||
|
@ -107,6 +109,7 @@
|
|||
import { t } from 'element-ui/src/locale';
|
||||
import scrollIntoView from 'element-ui/src/utils/scroll-into-view';
|
||||
import { getValueByPath } from 'element-ui/src/utils/util';
|
||||
import NavigationMixin from './navigation-mixin';
|
||||
|
||||
const sizeMap = {
|
||||
'large': 42,
|
||||
|
@ -127,12 +130,18 @@
|
|||
};
|
||||
|
||||
export default {
|
||||
mixins: [Emitter, Locale, Focus('reference')],
|
||||
mixins: [Emitter, Locale, Focus('reference'), NavigationMixin],
|
||||
|
||||
name: 'ElSelect',
|
||||
|
||||
componentName: 'ElSelect',
|
||||
|
||||
provide() {
|
||||
return {
|
||||
'select': this
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
iconClass() {
|
||||
let criteria = this.clearable &&
|
||||
|
@ -223,7 +232,6 @@
|
|||
createdLabel: null,
|
||||
createdSelected: false,
|
||||
selected: this.multiple ? [] : {},
|
||||
isSelect: true,
|
||||
inputLength: 20,
|
||||
inputWidth: 0,
|
||||
cachedPlaceHolder: '',
|
||||
|
@ -233,7 +241,7 @@
|
|||
selectedLabel: '',
|
||||
hoverIndex: -1,
|
||||
query: '',
|
||||
optionsAllDisabled: false,
|
||||
previousQuery: '',
|
||||
inputHovering: false,
|
||||
currentPlaceholder: ''
|
||||
};
|
||||
|
@ -260,33 +268,6 @@
|
|||
this.dispatch('ElFormItem', 'el.form.change', val);
|
||||
},
|
||||
|
||||
query(val) {
|
||||
this.$nextTick(() => {
|
||||
if (this.visible) this.broadcast('ElSelectDropdown', 'updatePopper');
|
||||
});
|
||||
this.hoverIndex = -1;
|
||||
if (this.multiple && this.filterable) {
|
||||
this.inputLength = this.$refs.input.value.length * 15 + 20;
|
||||
this.managePlaceholder();
|
||||
this.resetInputHeight();
|
||||
}
|
||||
if (this.remote && typeof this.remoteMethod === 'function') {
|
||||
this.hoverIndex = -1;
|
||||
this.remoteMethod(val);
|
||||
this.broadcast('ElOption', 'resetIndex');
|
||||
} else if (typeof this.filterMethod === 'function') {
|
||||
this.filterMethod(val);
|
||||
this.broadcast('ElOptionGroup', 'queryChange');
|
||||
} else {
|
||||
this.filteredOptionsCount = this.optionsCount;
|
||||
this.broadcast('ElOption', 'queryChange', val);
|
||||
this.broadcast('ElOptionGroup', 'queryChange');
|
||||
}
|
||||
if (this.defaultFirstOption && (this.filterable || this.remote) && this.filteredOptionsCount) {
|
||||
this.checkDefaultFirstOption();
|
||||
}
|
||||
},
|
||||
|
||||
visible(val) {
|
||||
if (!val) {
|
||||
this.$refs.reference.$el.querySelector('input').blur();
|
||||
|
@ -321,7 +302,8 @@
|
|||
this.handleIconShow();
|
||||
this.broadcast('ElSelectDropdown', 'updatePopper');
|
||||
if (this.filterable) {
|
||||
this.query = this.selectedLabel;
|
||||
this.query = this.remote ? '' : this.selectedLabel;
|
||||
this.handleQueryChange(this.query);
|
||||
if (this.multiple) {
|
||||
this.$refs.input.focus();
|
||||
} else {
|
||||
|
@ -336,9 +318,8 @@
|
|||
this.$emit('visible-change', val);
|
||||
},
|
||||
|
||||
options(val) {
|
||||
options() {
|
||||
if (this.$isServer) return;
|
||||
this.optionsAllDisabled = val.length === val.filter(item => item.disabled === true).length;
|
||||
if (this.multiple) {
|
||||
this.resetInputHeight();
|
||||
}
|
||||
|
@ -353,6 +334,35 @@
|
|||
},
|
||||
|
||||
methods: {
|
||||
handleQueryChange(val) {
|
||||
if (this.previousQuery === val) return;
|
||||
console.log(val);
|
||||
this.previousQuery = val;
|
||||
this.$nextTick(() => {
|
||||
if (this.visible) this.broadcast('ElSelectDropdown', 'updatePopper');
|
||||
});
|
||||
this.hoverIndex = -1;
|
||||
if (this.multiple && this.filterable) {
|
||||
this.inputLength = this.$refs.input.value.length * 15 + 20;
|
||||
this.managePlaceholder();
|
||||
this.resetInputHeight();
|
||||
}
|
||||
if (this.remote && typeof this.remoteMethod === 'function') {
|
||||
this.hoverIndex = -1;
|
||||
this.remoteMethod(val);
|
||||
} else if (typeof this.filterMethod === 'function') {
|
||||
this.filterMethod(val);
|
||||
this.broadcast('ElOptionGroup', 'queryChange');
|
||||
} else {
|
||||
this.filteredOptionsCount = this.optionsCount;
|
||||
this.broadcast('ElOption', 'queryChange', val);
|
||||
this.broadcast('ElOptionGroup', 'queryChange');
|
||||
}
|
||||
if (this.defaultFirstOption && (this.filterable || this.remote) && this.filteredOptionsCount) {
|
||||
this.checkDefaultFirstOption();
|
||||
}
|
||||
},
|
||||
|
||||
handleIconHide() {
|
||||
let icon = this.$el.querySelector('.el-input__icon');
|
||||
if (icon) {
|
||||
|
@ -464,7 +474,6 @@
|
|||
|
||||
doDestroy() {
|
||||
this.$refs.popper && this.$refs.popper.doDestroy();
|
||||
this.dropdownUl = null;
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
|
@ -545,6 +554,7 @@
|
|||
this.emitChange(value);
|
||||
if (option.created) {
|
||||
this.query = '';
|
||||
this.handleQueryChange('');
|
||||
this.inputLength = 20;
|
||||
}
|
||||
if (this.filterable) this.$refs.input.focus();
|
||||
|
@ -583,40 +593,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
navigateOptions(direction) {
|
||||
if (!this.visible) {
|
||||
this.visible = true;
|
||||
return;
|
||||
}
|
||||
if (this.options.length === 0 || this.filteredOptionsCount === 0) return;
|
||||
this.optionsAllDisabled = this.options.length === this.options.filter(item => item.disabled === true).length;
|
||||
if (!this.optionsAllDisabled) {
|
||||
if (direction === 'next') {
|
||||
this.hoverIndex++;
|
||||
if (this.hoverIndex === this.options.length) {
|
||||
this.hoverIndex = 0;
|
||||
}
|
||||
if (this.options[this.hoverIndex].disabled === true ||
|
||||
this.options[this.hoverIndex].groupDisabled === true ||
|
||||
!this.options[this.hoverIndex].visible) {
|
||||
this.navigateOptions('next');
|
||||
}
|
||||
}
|
||||
if (direction === 'prev') {
|
||||
this.hoverIndex--;
|
||||
if (this.hoverIndex < 0) {
|
||||
this.hoverIndex = this.options.length - 1;
|
||||
}
|
||||
if (this.options[this.hoverIndex].disabled === true ||
|
||||
this.options[this.hoverIndex].groupDisabled === true ||
|
||||
!this.options[this.hoverIndex].visible) {
|
||||
this.navigateOptions('prev');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => this.scrollToOption(this.options[this.hoverIndex]));
|
||||
},
|
||||
|
||||
selectOption() {
|
||||
if (this.options[this.hoverIndex]) {
|
||||
this.handleOptionSelect(this.options[this.hoverIndex]);
|
||||
|
@ -644,8 +620,9 @@
|
|||
},
|
||||
|
||||
onInputChange() {
|
||||
if (this.filterable) {
|
||||
if (this.filterable && this.query !== this.selectedLabel) {
|
||||
this.query = this.selectedLabel;
|
||||
this.handleQueryChange(this.query);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -656,7 +633,6 @@
|
|||
if (index > -1) {
|
||||
this.options.splice(index, 1);
|
||||
}
|
||||
this.broadcast('ElOption', 'resetIndex');
|
||||
},
|
||||
|
||||
resetInputWidth() {
|
||||
|
|
|
@ -91,6 +91,10 @@
|
|||
color: var(--input-disabled-placeholder-color);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__icon {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
@m large {
|
||||
font-size: var(--input-large-font-size);
|
||||
|
|
|
@ -67,6 +67,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-focus .el-input__inner {
|
||||
border-color: var(--input-focus-border);
|
||||
}
|
||||
}
|
||||
|
||||
& > .el-input {
|
||||
|
|
|
@ -140,7 +140,6 @@ describe('Select', () => {
|
|||
});
|
||||
|
||||
it('single select', done => {
|
||||
sinon.stub(window.console, 'log');
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div>
|
||||
|
@ -174,13 +173,14 @@ describe('Select', () => {
|
|||
value: '选项5',
|
||||
label: '北京烤鸭'
|
||||
}],
|
||||
value: ''
|
||||
value: '',
|
||||
count: 0
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleChange() {
|
||||
console.log('changed');
|
||||
this.count++;
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
@ -190,12 +190,12 @@ describe('Select', () => {
|
|||
options[2].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value).to.equal('选项3');
|
||||
expect(window.console.log.callCount).to.equal(1);
|
||||
expect(vm.count).to.equal(1);
|
||||
triggerEvent(options[2], 'mouseenter');
|
||||
options[4].click();
|
||||
setTimeout(() => {
|
||||
expect(vm.value).to.equal('选项5');
|
||||
expect(window.console.log.callCount).to.equal(2);
|
||||
window.console.log.restore();
|
||||
expect(vm.count).to.equal(2);
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
|
@ -460,7 +460,7 @@ describe('Select', () => {
|
|||
<el-option
|
||||
v-for="item in options"
|
||||
:label="item"
|
||||
:key="item.value"
|
||||
:key="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
|
@ -471,14 +471,6 @@ describe('Select', () => {
|
|||
options: ['1', '2', '3', '4', '5'],
|
||||
value: ''
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
filterMethod(query) {
|
||||
// simulate async filterMethod / remoteMethod
|
||||
setTimeout(() => {
|
||||
this.options.filter(option => option.label.indexOf(query) !== -1);
|
||||
}, 5);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
@ -486,7 +478,7 @@ describe('Select', () => {
|
|||
setTimeout(() => {
|
||||
select.$el.querySelector('input').focus();
|
||||
select.query = '3';
|
||||
select.selectedLabel = '3';
|
||||
select.handleQueryChange('3');
|
||||
setTimeout(() => {
|
||||
const enterKey = document.createEvent('Events');
|
||||
enterKey.initEvent('keydown', true, true);
|
||||
|
@ -635,10 +627,9 @@ describe('Select', () => {
|
|||
});
|
||||
const select = vm.$children[0];
|
||||
vm.$nextTick(() => {
|
||||
select.query = '面';
|
||||
select.handleQueryChange('面');
|
||||
setTimeout(() => {
|
||||
expect(select.filteredOptionsCount).to.equal(1);
|
||||
select.query = '';
|
||||
select.options[0].$el.click();
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.value[0]).to.equal('选项4');
|
||||
|
|
Loading…
Reference in New Issue