Skip to content

Commit

Permalink
fix autocomplete do not hide on blur bug
Browse files Browse the repository at this point in the history
  • Loading branch information
baiyaaaaa authored and Leopoldthecoder committed Jan 6, 2017
1 parent 0b52468 commit 0b8b011
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 39 deletions.
1 change: 1 addition & 0 deletions examples/docs/en-US/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ Attribute | Description | Type | Options | Default
|custom-item | component name of your customized suggestion list item | string |||
|fetch-suggestions | a method to fetch input suggestions. When suggestions are ready, invoke `callback(data:[])` to return them to Autocomplete | Function(queryString, callback) |||
| popper-class | custom class name for autocomplete's dropdown | string |||
| trigger-on-focus | whether show suggestions when input focus | boolean || true |

### Autocomplete Events

Expand Down
1 change: 1 addition & 0 deletions examples/docs/zh-CN/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ export default {
| custom-item | 通过该参数指定自定义的输入建议列表项的组件名 | string |||
| fetch-suggestions | 返回输入建议的方法,仅当你的输入建议数据 resolve 时,通过调用 callback(data:[]) 来返回它 | Function(queryString, callback) |||
| popper-class | Autocomplete 下拉列表的类名 | string |||
| trigger-on-focus | 是否在输入框 focus 时显示建议列表 | boolean || true |

### Autocomplete Events
| 事件名称 | 说明 | 回调参数 |
Expand Down
13 changes: 10 additions & 3 deletions packages/autocomplete/src/autocomplete-suggestions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
<li
v-if="!parent.customItem"
:class="{'highlighted': parent.highlightedIndex === index}"
@click="parent.select(index)"
@click="select(item)"
>
{{item.value}}
</li>
<component
v-else
:class="{'highlighted': parent.highlightedIndex === index}"
@click="parent.select(index)"
@click="select(item)"
:is="parent.customItem"
:item="item"
:index="index">
Expand All @@ -29,8 +29,9 @@
</template>
<script>
import Popper from 'element-ui/src/utils/vue-popper';
import Emitter from 'element-ui/src/mixins/emitter';
export default {
mixins: [Popper],
mixins: [Popper, Emitter],
componentName: 'ElAutocompleteSuggestions',
Expand All @@ -53,6 +54,12 @@
}
},
methods: {
select(item) {
this.dispatch('ElAutocomplete', 'item-click', item);
}
},
mounted() {
this.popperElm = this.$el;
this.referenceElm = this.$parent.$refs.input.$refs.input;
Expand Down
73 changes: 47 additions & 26 deletions packages/autocomplete/src/autocomplete.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="el-autocomplete" v-clickoutside="handleBlur">
<div class="el-autocomplete" v-clickoutside="handleClickoutside">
<el-input
ref="input"
:value="value"
Expand All @@ -9,9 +9,10 @@
:size="size"
@change="handleChange"
@focus="handleFocus"
@blur="handleBlur"
@keydown.up.native="highlight(highlightedIndex - 1)"
@keydown.down.native="highlight(highlightedIndex + 1)"
@keydown.enter.stop.native="select(highlightedIndex)"
@keydown.enter.stop.native="handleKeyEnter"
>
<template slot="prepend" v-if="$slots.prepend">
<slot name="prepend"></slot>
Expand Down Expand Up @@ -39,6 +40,8 @@
mixins: [Emitter],
componentName: 'ElAutocomplete',
components: {
ElInput,
ElAutocompleteSuggestions
Expand All @@ -53,6 +56,7 @@
name: String,
size: String,
value: String,
autofocus: Boolean,
fetchSuggestions: Function,
triggerOnFocus: {
type: Boolean,
Expand All @@ -62,53 +66,65 @@
},
data() {
return {
isFocus: false,
suggestions: [],
suggestionVisible: false,
loading: false,
highlightedIndex: -1
};
},
computed: {
suggestionVisible() {
const suggestions = this.suggestions;
let isValidData = Array.isArray(suggestions) && suggestions.length > 0;
return (isValidData || this.loading) && this.isFocus;
}
},
watch: {
suggestionVisible(val) {
this.broadcast('ElAutocompleteSuggestions', 'visible', [val, this.$refs.input.$refs.input.offsetWidth]);
}
},
methods: {
getData(queryString) {
this.loading = true;
this.fetchSuggestions(queryString, (suggestions) => {
this.loading = false;
if (Array.isArray(suggestions)) {
this.suggestions = suggestions;
} else {
console.error('autocomplete suggestions must be an array');
}
});
},
handleChange(value) {
this.$emit('input', value);
this.showSuggestions(value);
this.getData(value);
},
handleFocus() {
this.isFocus = true;
if (this.triggerOnFocus) {
this.showSuggestions(this.value);
this.getData(this.value);
}
},
handleBlur() {
this.hideSuggestions();
// 因为 blur 事件处理优先于 select 事件执行
setTimeout(_ => {
this.isFocus = false;
}, 100);
},
select(index) {
if (this.suggestions && this.suggestions[index]) {
this.$emit('input', this.suggestions[index].value);
this.$emit('select', this.suggestions[index]);
this.$nextTick(() => {
this.hideSuggestions();
});
handleKeyEnter() {
if (this.suggestionVisible) {
this.select(this.suggestions[this.highlightedIndex]);
}
},
hideSuggestions() {
this.suggestionVisible = false;
this.loading = false;
handleClickoutside() {
this.isFocus = false;
},
showSuggestions(value) {
this.suggestionVisible = true;
this.loading = true;
this.fetchSuggestions(value, (suggestions) => {
this.loading = false;
if (Array.isArray(suggestions) && suggestions.length > 0) {
this.suggestions = suggestions;
} else {
this.hideSuggestions();
}
select(item) {
this.$emit('input', item.value);
this.$emit('select', item);
this.$nextTick(_ => {
this.suggestions = [];
});
},
highlight(index) {
Expand All @@ -134,6 +150,11 @@
this.highlightedIndex = index;
}
},
mounted() {
this.$on('item-click', item => {
this.select(item);
});
},
beforeDestroy() {
this.$refs.suggestions.$destroy();
}
Expand Down
75 changes: 65 additions & 10 deletions test/unit/specs/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ describe('Autocomplete', () => {
it('create', done => {
vm = createVue({
template: `
<el-autocomplete
ref="autocomplete"
v-model="state"
:fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete1"
></el-autocomplete>
<div>
<button class="btn">a</button>
<el-autocomplete
ref="autocomplete"
v-model="state"
:fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete1"
></el-autocomplete>
</div>
`,
data() {
return {
Expand Down Expand Up @@ -52,12 +55,13 @@ describe('Autocomplete', () => {
expect(inputElm.getAttribute('placeholder')).to.be.equal('请输入内容autocomplete1');

setTimeout(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el;
expect(suggestionsList.style.display).to.not.equal('none');
expect(suggestionsList.children.length).to.be.equal(4);
const suggestions = vm.$refs.autocomplete.$refs.suggestions.$el;
expect(suggestions.style.display).to.not.equal('none');
expect(suggestions.children.length).to.be.equal(4);

document.body.click();
setTimeout(_ => {
expect(document.querySelector('.el-autocomplete__suggestions').style.display).to.be.equal('none');
expect(suggestions.style.display).to.be.equal('none');
done();
}, 500);
}, 500);
Expand Down Expand Up @@ -276,4 +280,55 @@ describe('Autocomplete', () => {
});
}, 500);
});
it('triggerOnFocus', done => {
vm = createVue({
template: `
<el-autocomplete
ref="autocomplete"
v-model="state"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
placeholder="请输入内容autocomplete1"
></el-autocomplete>
`,
data() {
return {
restaurants: [],
state: ''
};
},
methods: {
querySearch(queryString, cb) {
var restaurants = this.restaurants;
var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
cb(results);
},
createFilter(queryString) {
return (restaurant) => {
return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
};
},
loadAll() {
return [
{ 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
{ 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
{ 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
{ 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
];
}
},
mounted() {
this.restaurants = this.loadAll();
}
}, true);
let elm = vm.$el;
let inputElm = elm.querySelector('input');
inputElm.focus();

setTimeout(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el;
expect(suggestionsList.style.display).to.be.equal('none');
done();
}, 500);
});
});

0 comments on commit 0b8b011

Please sign in to comment.