Select: remove resetIndex

pull/6325/head
Leopoldthecoder 2017-07-29 18:24:07 +08:00 committed by 杨奕
parent f477390c79
commit f23629ac43
6 changed files with 139 additions and 122 deletions

View File

@ -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));
}
}
};

View File

@ -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() {

View File

@ -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() {

View File

@ -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);

View File

@ -67,6 +67,10 @@
}
}
}
&.is-focus .el-input__inner {
border-color: var(--input-focus-border);
}
}
& > .el-input {

View File

@ -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');