vue3+elementUI-plus实现select下拉框的虚拟滚动

网上查了几个方案,要不就是不兼容,要不就是不支持vue3,

最终找到一个合适的,并且已上线使用,需要修改一下样式:

代码如下:

main.js里引用

bash 复制代码
import 'vue3-virtual-scroller/dist/vue3-virtual-scroller.css';
import { RecycleScroller } from 'vue3-virtual-scroller';
app.component('RecycleScroller', RecycleScroller);

vue文件:

bash 复制代码
<el-form-item label="用户" prop="seriesId">
                    <div ref="selectWrapper" @click="toggleDropdown($event)" class="select-wrapper">
                        <el-input style="width: 240px"
                        placeholder="请输入搜索内容"
                        v-model="selectedOption"
                        :suffix-icon="selectedOption ? 'el-icon-circle-close' : null"
                        @clear="clearSearch"
                        ></el-input>
                    </div>
                    <el-icon class="clear-btn" v-if="selectedOption" @click.stop="clearSearch"><CircleClose /></el-icon>
                    <Teleport to="body">
                        <div v-show="isOpen"  ref="dropdown" class="virtual-dropdown" :style="dropdownStyles" @click="closeDropdown">
                            <RecycleScroller
                                class="virtual-list"
                                :buffer="1000"
                                :prerender="200"
                                style="height: 270px"
                                :item-size="24"
                                key-field="id"
                                :items="filteredSeriesList"
                                >
                                <template v-slot="{ item, index }">
                                    <div class="list-item" :key="index" @click.stop="handleItemClick(item)">
                                    <span>{{ item.id }}</span>&nbsp;-&nbsp;
                                    <span>{{ item.name }}</span>
                                    </div>
                                </template>
                                </RecycleScroller>
                        </div>
                    </Teleport>
                </el-form-item>

js代码:

bash 复制代码
<script setup name="LeadsList">
const rowCount = ref(0);
    const rowCount2 = ref(0);
    const leadsList = ref([]);
    const loading = ref(false);
    const activeButton = ref(0);
    const seriesList = ref([]);
    const filteredSeriesList = ref([]); // 初始状态下,筛选后的列表与原始列表相同
    const indexLayer = ref(false);
    const open = ref(false);
    const dropdown = ref(null);
    const repeatLoading = ref(false);
    const repeatList = ref([]);
    const dropdownStyles = ref({});
    const selectWrapper = ref({});
    const isOpen = ref(false);
    const selectedOption = ref('');
    const data = reactive({
        queryParams: {
            pageIndex: 1,
            pageSize: 10,
            phone: "",
            seriesId: null,
        },
        queryParamsRepeat: {
            pageIndex: 1,
            pageSize: 10,
            companyId: 1,
            userId: 1
        }
    });

    const { queryParams,queryParamsRepeat } = toRefs(data);


    watch(selectedOption, (newValue) => {
        search(newValue);
    });
    function search (keyword) {
        if (keyword.trim() === "") {
      filteredSeriesList.value = [...seriesList.value];
        } else {
        filteredSeriesList.value = seriesList.value.filter((item) =>
            item.name.toLowerCase().includes(keyword.toLowerCase())
        );
        }
    }
    function handleItemClick(item) {
      queryParams.value.seriesId = item.id;
      selectedOption.value = item.name;
      closeDropdown()
    }
    function closeDropdown(event = null) {
        isOpen.value = false;
        if (
            event &&
            (selectWrapper.value.contains(event.target) ||
            dropdown.value.contains(event.target))
        ) {
            return;
        }
        isOpen.value = false;
    }
    function toggleDropdown($event) {
        $event.stopPropagation(); // 阻止事件冒泡
        isOpen.value = !isOpen.value;
        if (isOpen.value) {
            const rect = selectWrapper.value.getBoundingClientRect();
            const { x, y, width, height } = rect;
            dropdownStyles.value = {
            position: 'fixed',
            top: `${y + height}px`,
            left: `${x}px`,
            width: `${width}px`,
            };
        }
    }
    function clearSearch () {
        queryParams.value.seriesId = '';
        selectedOption.value = '';
        filteredSeriesList.value = [...seriesList.value];
    }

css代码:

bash 复制代码
.virtual-dropdown {
  position: absolute;
  inset: 100% auto auto 0;
  z-index: 2000;
  width: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  background-color: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.list-item {
  display: flex;
  padding: 0 10px;
  align-items: center;
  height: 24px;
  cursor: pointer;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

.list-item:hover {
  background-color: #f5f7fa;
}
.clear-btn {
    border: none;
    background: transparent;
    cursor: pointer;
    position: absolute;
    right: 14px;
  }
相关推荐
GDAL1 小时前
HTML 中的 Canvas 样式设置全解
javascript
m0_528723811 小时前
HTML中,title和h1标签的区别是什么?
前端·html
Dark_programmer1 小时前
html - - - - - modal弹窗出现时,页面怎么能限制滚动
前端·html
GDAL1 小时前
HTML Canvas clip 深入全面讲解
前端·javascript·canvas
禾苗种树1 小时前
在 Vue 3 中使用 ECharts 制作多 Y 轴折线图时,若希望 **Y 轴颜色自动匹配折线颜色**且无需手动干预,可以通过以下步骤实现:
前端·vue.js·echarts
GISer_Jing1 小时前
Javascript排序算法(冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序)详解
javascript·算法·排序算法
贵州数擎科技有限公司1 小时前
使用 Three.js 实现流光特效
前端·webgl
JustHappy1 小时前
「我们一起做组件库🌻」做个面包屑🥖,Vue的依赖注入实战💉(VersakitUI开发实录)
前端·javascript·github
拉不动的猪2 小时前
刷刷题16
前端·javascript·面试
kiramario2 小时前
【结束】JS如何不通过input的onInputFileChange使用本地mp4文件并播放,nextjs下放入public文件的视频用video标签无法打开
开发语言·javascript·音视频