autocomplete dropdown use el-scrollbar

pull/2682/merge
baiyaaaaa 2017-02-06 14:29:53 +08:00 committed by 杨奕
parent a1dc075f60
commit 9dee785465
6 changed files with 129 additions and 133 deletions

View File

@ -120,7 +120,7 @@
} }
} }
} }
.el-autocomplete__suggestions.my-autocomplete { .el-autocomplete-suggestion.my-autocomplete {
li { li {
line-height: normal; line-height: normal;
padding: 7px *; padding: 7px *;
@ -133,7 +133,6 @@
font-size: 12px; font-size: 12px;
color: #b4b4b4; color: #b4b4b4;
} }
.highlighted .addr { .highlighted .addr {
color: #ddd; color: #ddd;
} }

View File

@ -161,7 +161,7 @@
} }
} }
} }
.el-autocomplete__suggestions.my-autocomplete { .el-autocomplete-suggestion.my-autocomplete {
li { li {
line-height: normal; line-height: normal;
padding: 7px *; padding: 7px *;
@ -174,7 +174,6 @@
font-size: 12px; font-size: 12px;
color: #b4b4b4; color: #b4b4b4;
} }
.highlighted .addr { .highlighted .addr {
color: #ddd; color: #ddd;
} }

View File

@ -1,10 +1,15 @@
<template> <template>
<transition name="el-zoom-in-top" @after-leave="doDestroy"> <transition name="el-zoom-in-top" @after-leave="doDestroy">
<ul <div
v-show="showPopper" v-show="showPopper"
class="el-autocomplete__suggestions" class="el-autocomplete-suggestion"
:class="{ 'is-loading': parent.loading }" :class="{ 'is-loading': parent.loading }"
:style="{ width: dropdownWidth }" :style="{ width: dropdownWidth }"
>
<el-scrollbar
tag="ul"
wrap-class="el-autocomplete-suggestion__wrap"
view-class="el-autocomplete-suggestion__list"
> >
<li v-if="parent.loading"><i class="el-icon-loading"></i></li> <li v-if="parent.loading"><i class="el-icon-loading"></i></li>
<template v-for="(item, index) in suggestions" v-else> <template v-for="(item, index) in suggestions" v-else>
@ -24,7 +29,8 @@
:index="index"> :index="index">
</component> </component>
</template> </template>
</ul> </el-scrollbar>
</div>
</transition> </transition>
</template> </template>
<script> <script>

View File

@ -133,22 +133,22 @@
}, },
highlight(index) { highlight(index) {
if (!this.suggestionVisible || this.loading) { return; } if (!this.suggestionVisible || this.loading) { return; }
if (index < 0) { if (index < 0) index = 0;
index = 0; if (index >= this.suggestions.length) {
} else if (index >= this.suggestions.length) {
index = this.suggestions.length - 1; index = this.suggestions.length - 1;
} }
var elSuggestions = this.$refs.suggestions.$el; const suggestion = this.$refs.suggestions.$el.querySelector('.el-autocomplete-suggestion__wrap');
const suggestionList = suggestion.querySelectorAll('.el-autocomplete-suggestion__list li');
var elSelect = elSuggestions.children[index]; let highlightItem = suggestionList[index];
var scrollTop = elSuggestions.scrollTop; let scrollTop = suggestion.scrollTop;
var offsetTop = elSelect.offsetTop; let offsetTop = highlightItem.offsetTop;
if (offsetTop + elSelect.scrollHeight > (scrollTop + elSuggestions.clientHeight)) { if (offsetTop + highlightItem.scrollHeight > (scrollTop + suggestion.clientHeight)) {
elSuggestions.scrollTop += elSelect.scrollHeight; suggestion.scrollTop += highlightItem.scrollHeight;
} }
if (offsetTop < scrollTop) { if (offsetTop < scrollTop) {
elSuggestions.scrollTop -= elSelect.scrollHeight; suggestion.scrollTop -= highlightItem.scrollHeight;
} }
this.highlightedIndex = index; this.highlightedIndex = index;

View File

@ -6,22 +6,25 @@
@b autocomplete { @b autocomplete {
position: relative; position: relative;
display: inline-block; display: inline-block;
}
@e suggestions { @b autocomplete-suggestion {
position: absolute;
left: 0;
top: 110%;
margin: 5px 0 0; margin: 5px 0 0;
box-shadow: 0 0 6px 0 rgba(0,0,0,0.04), 0 2px 4px 0 rgba(0,0,0,0.12);
@e wrap {
max-height: 280px;
overflow: auto;
background-color: var(--color-white); background-color: var(--color-white);
border: 1px solid var(--color-base-gray); border: 1px solid var(--color-base-gray);
width: 100%;
padding: 6px 0; padding: 6px 0;
z-index: 10;
border-radius: 2px; border-radius: 2px;
max-height: 280px;
box-sizing: border-box; box-sizing: border-box;
overflow: auto; }
box-shadow: 0 0 6px 0 rgba(0,0,0,0.04), 0 2px 4px 0 rgba(0,0,0,0.12);
@e list {
margin: 0;
padding: 0;
}
& li { & li {
list-style: none; list-style: none;
@ -73,5 +76,4 @@
} }
} }
} }
}
} }

View File

@ -57,7 +57,7 @@ describe('Autocomplete', () => {
setTimeout(_ => { setTimeout(_ => {
const suggestions = vm.$refs.autocomplete.$refs.suggestions.$el; const suggestions = vm.$refs.autocomplete.$refs.suggestions.$el;
expect(suggestions.style.display).to.not.equal('none'); expect(suggestions.style.display).to.not.equal('none');
expect(suggestions.children.length).to.be.equal(4); expect(suggestions.querySelectorAll('.el-autocomplete-suggestion__list li').length).to.be.equal(4);
document.body.click(); document.body.click();
setTimeout(_ => { setTimeout(_ => {
@ -74,14 +74,12 @@ describe('Autocomplete', () => {
ref="autocomplete" ref="autocomplete"
:fetch-suggestions="querySearch" :fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete2" placeholder="请输入内容autocomplete2"
@select="handleSelect"
></el-autocomplete> ></el-autocomplete>
`, `,
data() { data() {
return { return {
restaurants: [], restaurants: [],
state: '', state: ''
onceSelected: false
}; };
}, },
methods: { methods: {
@ -102,27 +100,29 @@ describe('Autocomplete', () => {
{ 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' }, { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
{ 'value': '泷千家(天山西路店)', 'address': '天山西路438号' } { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
]; ];
},
handleSelect() {
this.onceSelected = true;
} }
}, },
mounted() { mounted() {
this.restaurants = this.loadAll(); this.restaurants = this.loadAll();
} }
}, true); }, true);
let elm = vm.$el; const autocomplete = vm.$refs.autocomplete;
let inputElm = elm.querySelector('input'); const elm = vm.$el;
const inputElm = elm.querySelector('input');
const spy = sinon.spy();
autocomplete.$on('select', spy);
inputElm.focus(); inputElm.focus();
setTimeout(_ => { setTimeout(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el; const suggestions = autocomplete.$refs.suggestions.$el;
suggestionsList.children[1].click(); const suggestionList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
suggestionList[1].click();
setTimeout(_ => { setTimeout(_ => {
expect(inputElm.value).to.be.equal('Hot honey 首尔炸鸡(仙霞路)'); expect(inputElm.value).to.be.equal('Hot honey 首尔炸鸡(仙霞路)');
expect(vm.state).to.be.equal('Hot honey 首尔炸鸡(仙霞路)'); expect(vm.state).to.be.equal('Hot honey 首尔炸鸡(仙霞路)');
expect(vm.onceSelected).to.be.true; expect(spy.withArgs().calledOnce).to.be.true;
expect(elm.querySelector('.el-autocomplete__suggestions')).to.not.exist; expect(suggestions.style.display).to.be.equal('none');
done(); done();
}, 500); }, 500);
}, 500); }, 500);
@ -135,14 +135,12 @@ describe('Autocomplete', () => {
v-model="state" v-model="state"
:fetch-suggestions="querySearch" :fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete3" placeholder="请输入内容autocomplete3"
@select="handleSelect"
></el-autocomplete> ></el-autocomplete>
`, `,
data() { data() {
return { return {
restaurants: [], restaurants: [],
state: '', state: ''
onceSelected: false
}; };
}, },
methods: { methods: {
@ -181,28 +179,25 @@ describe('Autocomplete', () => {
{ 'value': '纵食', 'address': '元丰天山花园(东门) 双流路267号' }, { 'value': '纵食', 'address': '元丰天山花园(东门) 双流路267号' },
{ 'value': '钱记', 'address': '上海市长宁区天山西路' } { 'value': '钱记', 'address': '上海市长宁区天山西路' }
]; ];
},
handleSelect() {
this.onceSelected = true;
} }
}, },
mounted() { mounted() {
this.restaurants = this.loadAll(); this.restaurants = this.loadAll();
} }
}, true); }, true);
let elm = vm.$el; const autocomplete = vm.$refs.autocomplete;
let inputElm = elm.querySelector('input'); const inputElm = autocomplete.$el.querySelector('input');
inputElm.focus(); inputElm.focus();
setTimeout(_ => { setTimeout(_ => {
vm.$refs.autocomplete.highlight(8); autocomplete.highlight(8);
vm.$nextTick(_ => { vm.$nextTick(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el; const suggestions = autocomplete.$refs.suggestions.$el.querySelector('.el-autocomplete-suggestion__wrap');
let highlightedItem = suggestionsList.children[8]; let suggestionsList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
expect(highlightedItem.className).to.be.equal('highlighted'); let highlightedItem = suggestionsList[8];
expect(suggestionsList.scrollTop === highlightedItem.scrollHeight).to.be.true; expect(highlightedItem.classList.contains('highlighted')).to.be.true;
expect(suggestions.scrollTop === highlightedItem.scrollHeight).to.be.true;
vm.$refs.autocomplete.highlight(8);
done(); done();
}); });
}, 500); }, 500);
@ -215,14 +210,12 @@ describe('Autocomplete', () => {
v-model="state" v-model="state"
:fetch-suggestions="querySearch" :fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete3" placeholder="请输入内容autocomplete3"
@select="handleSelect"
></el-autocomplete> ></el-autocomplete>
`, `,
data() { data() {
return { return {
restaurants: [], restaurants: [],
state: '', state: ''
onceSelected: false
}; };
}, },
methods: { methods: {
@ -251,29 +244,27 @@ describe('Autocomplete', () => {
{ 'value': '阿姨奶茶/豪大大', 'address': '嘉定区曹安路1611号' }, { 'value': '阿姨奶茶/豪大大', 'address': '嘉定区曹安路1611号' },
{ 'value': '新麦甜四季甜品炸鸡', 'address': '嘉定区曹安公路2383弄55号' } { 'value': '新麦甜四季甜品炸鸡', 'address': '嘉定区曹安公路2383弄55号' }
]; ];
},
handleSelect() {
this.onceSelected = true;
} }
}, },
mounted() { mounted() {
this.restaurants = this.loadAll(); this.restaurants = this.loadAll();
} }
}, true); }, true);
let elm = vm.$el; const autocomplete = vm.$refs.autocomplete;
let inputElm = elm.querySelector('input'); let inputElm = vm.$el.querySelector('input');
inputElm.focus(); inputElm.focus();
setTimeout(_ => { setTimeout(_ => {
vm.$refs.autocomplete.highlight(15); autocomplete.highlight(15);
vm.$nextTick(_ => { vm.$nextTick(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el; const suggestions = autocomplete.$refs.suggestions.$el;
let highlightedItem = suggestionsList.children[11]; const suggestionsList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
let highlightedItem = suggestionsList[11];
expect(highlightedItem.className).to.be.equal('highlighted'); expect(highlightedItem.className).to.be.equal('highlighted');
vm.$refs.autocomplete.highlight(-5); autocomplete.highlight(-5);
vm.$nextTick(_ => { vm.$nextTick(_ => {
let highlightedItem = suggestionsList.children[0]; let highlightedItem = suggestionsList[0];
expect(highlightedItem.className).to.be.equal('highlighted'); expect(highlightedItem.className).to.be.equal('highlighted');
}); });
done(); done();
@ -321,13 +312,12 @@ describe('Autocomplete', () => {
this.restaurants = this.loadAll(); this.restaurants = this.loadAll();
} }
}, true); }, true);
let elm = vm.$el; let inputElm = vm.$el.querySelector('input');
let inputElm = elm.querySelector('input');
inputElm.focus(); inputElm.focus();
setTimeout(_ => { setTimeout(_ => {
let suggestionsList = vm.$refs.autocomplete.$refs.suggestions.$el; let suggestions = vm.$refs.autocomplete.$refs.suggestions.$el;
expect(suggestionsList.style.display).to.be.equal('none'); expect(suggestions.style.display).to.be.equal('none');
done(); done();
}, 500); }, 500);
}); });