开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第28天,点击查看活动详情
写在前面
最近在写一个下拉远程搜索输入分页查询的需求,本来使用el-select的remote来实现的,但是在测试过程中发现el-select在输入内容过程中鼠标失焦的话会清空输入的值,并且会触发remote-method方法,但是产品想要的交互是t在输入内容过程中鼠标失焦的话输入的值不会清空。然后查看elementplus文档发现el-autocomplete组件可以达到这个效果。
封装一个el-autocomplete下拉分页加载的组件
在项目开发过程中如果有联想输入的需求的话一般会是使用el-autocomplete组件来实现,但是这样查询的话会匹配到很多数据,接口查询会很慢,因此做成了下拉分页查询。
1. 实现下拉加载的指令
const scrollLoad = {
bind(el, binding, vnode) {
let wrapDom = el.querySelector('.el-autocomplete-suggestion__wrap')
let listDom = el.querySelector('.el-autocomplete-suggestion__wrap .el-autocomplete-suggestion__list')
wrapDom.addEventListener(
'scroll',
() => {
// 注意load的使用,节流
let condition = wrapDom.offsetHeight + wrapDom.scrollTop + 10 - listDom.offsetHeight;
console.log('condition', condition, vnode.context.loading)
if (condition > 0 && !vnode.context.loading) {
//滚动到底部则执行滚动方法load,binding.value就是v-scrollLoad绑定的值,加()表示执行绑定的方法
binding.value()
}
},
false
)
}
};
export default scrollLoad;
然后在main.js中引入指令
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import scrollLoad from './directives/scrollLoad.js';
const app = createApp(App);
app.directive('scroll-load', scrollLoad);
app.use(ElementPlus).mount('#app');
2. 封装el-autocomplete组件
需要注意的是在vue3中指令需要绑定在el-autocomplete的上一级元素上,否则会报错
<template>
<div class="autocomplete-wrapper" v-scroll-load="selectLoadMore" v-loading="loading">
<el-autocomplete
ref="autocompleteRef"
value-key="value"
v-model="state"
:fetch-suggestions="querySearch"
:placeholder="placeholder"
:trigger-on-focus="false"
@select="handleSelect"
></el-autocomplete>
</div>
</template>
<script>
export default {
name: 'InputLoadMore'
}
</script>
<script setup>
import { defineProps, defineEmits, ref, watch } from 'vue';
const props = defineProps({
// 分页查询数据的方法
getSelectOpts: {
require: true
},
// 接口联想的key
searchKey: {
type: String,
require: true
},
// v-model的绑定值
value: {
type: String,
require: true
},
// placehoder
placeholder: {
type: String,
default: '请输入'
}
});
const emits = defineEmits(['input']);
const state = ref('');
const loading = ref(false);
const page = ref(1);
const pageTotal = ref(0);
const autocompleteRef = ref(null);
watch(
() => state,
(val) => {
emits('input', val);
},
() => props.value,
(val) => {
state.value = val
}
);
const querySearch = async (queryString, cb) => {
page.value = 1
loading.value = true
try {
let { result } = await props.getSelectOpts({
page: 1,
pageSize: 20,
[props.searchKey]: queryString
})
// 根据实际接口返回数据格式将数据插入到选项中
if (result.rows) {
let arr = []
result.rows.forEach(item => {
arr.push({ value: item })
})
cb(arr)
} else {
cb([])
}
pageTotal.value = result.total || 0
} catch(e) {
// console.log(e)
} finally {
loading.value = false
}
};
const handleSelect = (item) => {};
// 加载更多
const selectLoadMore = async () => {
if(Number(pageTotal.value) <= autocompleteRef.value.suggestions.length) {
return
}
page.value++;
loading.value = true;
try {
let { result } = await props.getSelectOpts({
page: page.value,
pageSize: 20,
[props.searchKey]: state.value
})
console.log('result', result);
// 根据实际接口返回数据格式将数据插入到选项中
if (result.rows) {
const arr = result.rows.map(item => {
return { value: item }
})
// 将数据添加到下拉列表
autocompleteRef.value.suggestions = autocompleteRef.value.suggestions.concat(arr)
}
pageTotal.value = result.total || 0;
} catch(e) {
// console.log(e)
} finally {
loading.value = false
}
}
</script>
3. 在组件中使用
<template>
<div class="test-wrapper" style="color: blue">
<AutoComplete :getSelectOpts="getSelectOpts" searchKey="query" :value="value" @input="inputFunc"></AutoComplete>
</div>
</template>
<script setup>
import { ref } from "vue";
import AutoComplete from './AutoComplete.vue';
const value = ref('');
const getSelectOpts = () => {
console.log('开始查询数据');
return [{
itemKey: 1,
itemValue: '1'
},
{
itemKey: 1,
itemValue: '1'
},
{
itemKey: 1,
itemValue: '1'
},
{
itemKey: 1,
itemValue: '1'
},
{
itemKey: 1,
itemValue: '1'
}]
};
const inputFunc = (data) => {
console.log('input数据', data);
}
</script>
<style scoped>
</style>
效果如下:
el-select的remote和el-autocomplete的区别
- el-autocomplete主要是针对输入建议,value会实时刷新,选中不会有选中效果。
- el-select value不会实时刷新,选中才会更新value,并且选中会有选中效果。