mirror of https://github.com/ElemeFE/element
autocomplete dropdown use el-scrollbar
parent
a1dc075f60
commit
9dee785465
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -74,4 +77,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue