表单使用场景**HTML**<el-form-item label="名称"prop="merchantId"ref="merchantIdRef"><ScrollSelect v-model="form.merchantId":options="merchantOptions":loading="merchantLoading":has-more="hasMoreMerchant"popper-class="merchantIdPopper"placeholder="请选择名称"class="filter-option filter-h36"clearable remote filterable @load-more="handleMerchantLoadMore"@remote-method="handleMerchantRemoteMethod"@focus="handleMerchantFocus"/></el-form-item>**JS代码**// 商家列表数据constmerchantOptions=ref([])constmerchantQueryParams=reactive({current:1,size:10,keyword:""})constmerchantLoading=ref(false)consthasMoreMerchant=ref(true)constgetMerchantOptions=(isLoadMore=false)=>{if(merchantLoading.value||(!hasMoreMerchant.value&&isLoadMore))returnmerchantLoading.value=truemerchantApi.merchantPage(merchantQueryParams).then(response=>{if(response.code===200){constnewOptions=response.data.records.map(item=>({label:item.name,value:item.id,}))merchantOptions.value=isLoadMore?[...merchantOptions.value,...newOptions]:newOptions hasMoreMerchant.value=merchantOptions.value.length<response.data.total}}).finally(()=>{merchantLoading.value=false})}// 滚动加载更多consthandleMerchantLoadMore=()=>{merchantQueryParams.current++getMerchantOptions(true)}// 获取焦点时加载初始数据consthandleMerchantFocus=()=>{if(merchantOptions.value.length===0){merchantQueryParams.current=1merchantQueryParams.keyword=''hasMoreMerchant.value=truegetMerchantOptions()}}// 远程搜索consthandleMerchantRemoteMethod=(query)=>{merchantQueryParams.current=1merchantQueryParams.keyword=query hasMoreMerchant.value=truegetMerchantOptions()}```-```javascript 表单使用场景**HTML**<el-form-item label="名称"prop="merchantId"ref="merchantIdRef"><ScrollSelect v-model="form.merchantId":options="merchantOptions":loading="merchantLoading":has-more="hasMoreMerchant"popper-class="merchantIdPopper"placeholder="请选择名称"class="filter-option filter-h36"clearable remote filterable @load-more="handleMerchantLoadMore"@remote-method="handleMerchantRemoteMethod"@focus="handleMerchantFocus"/></el-form-item>**JS代码**// 商家列表数据constmerchantOptions=ref([])constmerchantQueryParams=reactive({current:1,size:10,keyword:""})constmerchantLoading=ref(false)consthasMoreMerchant=ref(true)constgetMerchantOptions=(isLoadMore=false)=>{if(merchantLoading.value||(!hasMoreMerchant.value&&isLoadMore))returnmerchantLoading.value=truemerchantApi.merchantPage(merchantQueryParams).then(response=>{if(response.code===200){constnewOptions=response.data.records.map(item=>({label:item.name,value:item.id,}))merchantOptions.value=isLoadMore?[...merchantOptions.value,...newOptions]:newOptions hasMoreMerchant.value=merchantOptions.value.length<response.data.total}}).finally(()=>{merchantLoading.value=false})}// 滚动加载更多consthandleMerchantLoadMore=()=>{merchantQueryParams.current++getMerchantOptions(true)}// 获取焦点时加载初始数据consthandleMerchantFocus=()=>{if(merchantOptions.value.length===0){merchantQueryParams.current=1merchantQueryParams.keyword=''hasMoreMerchant.value=truegetMerchantOptions()}}// 远程搜索consthandleMerchantRemoteMethod=(query)=>{merchantQueryParams.current=1merchantQueryParams.keyword=query hasMoreMerchant.value=truegetMerchantOptions()}```支持 v-model 双向绑定 - 支持远程查询(remote-method) - 支持滚动加载更多(load-more) - 支持焦点事件(focus) - 支持可见性变化事件(visible-change) **下拉选择通用组件**```javascript<template><el-select v-bind="$attrs"v-model="internalValue":popper-class="popperClass":remote-method="handleRemoteMethod"@visible-change="handleVisibleChange"@focus="handleFocus"><el-option v-for="option in options":key="option.value":label="option.label":value="option.value"/><div v-if="loading"class="loading-more"><el-iconclass="is-loading"><Loading/></el-icon><span>加载中...</span></div><div v-else-if="!hasMore"class="no-more">没有更多数据</div></el-select></template><script setup>import{ref,watch,onMounted}from'vue'import{Loading}from'@element-plus/icons-vue'constprops=defineProps({modelValue:{type:[String,Number,Boolean],default:''},options:{type:Array,default:()=>[]},loading:{type:Boolean,default:false},hasMore:{type:Boolean,default:true},popperClass:{type:String,default:'scroll-select-popper'}})constemit=defineEmits(['update:modelValue','visible-change','load-more','remote-method','focus'])consthandleFocus=()=>{emit('focus')}consthandleRemoteMethod=(query)=>{emit('remote-method',query)}constinternalValue=ref(props.modelValue)// 监听 modelValue 的变化,更新内部值watch(()=>props.modelValue,(newValue)=>{internalValue.value=newValue})// 监听内部值的变化,更新父组件的值watch(internalValue,(newValue)=>{emit('update:modelValue',newValue)})consthandleVisibleChange=(visible)=>{emit('visible-change',visible)if(visible){setTimeout(()=>{setupScrollListener()},100)}else{removeScrollListener()}}constsetupScrollListener=()=>{constpopper=document.querySelector(`.${props.popperClass}.el-select-dropdown__wrap`)if(popper){popper.removeEventListener('scroll',handleScroll)popper.addEventListener('scroll',handleScroll)}}constremoveScrollListener=()=>{constpopper=document.querySelector(`.${props.popperClass}.el-select-dropdown__wrap`)if(popper){popper.scrollTop=0popper.removeEventListener('scroll',handleScroll)}}consthandleScroll=(e)=>{const{scrollTop,scrollHeight,clientHeight}=e.targetif(scrollTop+clientHeight>=scrollHeight-10&&!props.loading&&props.hasMore){emit('load-more')}}</script><style scoped>.loading-more,.no-more{text-align:center;padding:10px0;font-size:14px;color:#909399;}.loading-more.is-loading{margin-right:5px;}</style>
调用组件
在表单使用情景**HTML**<el-form-item label="名称"prop="merchantId"ref="merchantIdRef"><ScrollSelect v-model="form.merchantId":options="merchantOptions":loading="merchantLoading":has-more="hasMoreMerchant"popper-class="merchantIdPopper"placeholder="请选择名称"class="filter-option filter-h36"clearable remote filterable @load-more="handleMerchantLoadMore"@remote-method="handleMerchantRemoteMethod"@focus="handleMerchantFocus"/></el-form-item>**JS代码**// 商家列表constmerchantOptions=ref([])constmerchantQueryParams=reactive({current:1,size:10,keyword:"",})constmerchantLoading=ref(false)consthasMoreMerchant=ref(true)constmerchantSelectVisible=ref(false)constgetMerchantOptions=(isLoadMore=false)=>{if(merchantLoading.value||(!hasMoreMerchant.value&&isLoadMore))returnmerchantLoading.value=truemerchantApi.merchantPage(merchantQueryParams).then(response=>{if(response.code===200){constnewOptions=response.data.records.map(item=>({label:item.name,value:item.id,}))if(isLoadMore){merchantOptions.value=[...merchantOptions.value,...newOptions]}else{merchantOptions.value=newOptions}// 检查是否还有更多数据hasMoreMerchant.value=merchantOptions.value.length<response.data.total}else{// 接口请求失败时的处理// proxy.$modal.msgError('获取商家列表失败')}}).catch(()=>{// 网络错误时的处理// proxy.$modal.msgError('网络错误,请稍后重试')}).finally(()=>{merchantLoading.value=false})}// 滚动查询consthandleMerchantLoadMore=()=>{merchantQueryParams.current++getMerchantOptions(true)}consthandleMerchantFocus=()=>{// 当获取焦点时,如果还没有数据,加载初始数据if(merchantOptions.value.length===0){merchantQueryParams.current=1merchantQueryParams.keyword=''hasMoreMerchant.value=truegetMerchantOptions()}}// 远程关键字查询consthandleMerchantRemoteMethod=(query)=>{// 重置分页参数merchantQueryParams.current=1merchantQueryParams.keyword=query hasMoreMerchant.value=true// 重新加载数据getMerchantOptions()}