Vue3+setup+el-pagination+el-select封装下拉分页及懒加载

vue2下拉分页

<template>  
  <div>  
    <el-select v-model="selected" placeholder="请选择" @visible-change="handleDropdownVisibility">  
      <el-option  
        v-for="item in options"  
        :key="item.value"  
        :label="item.label"  
        :value="item.value">  
      </el-option>  
      <el-option  
        value="more"  
        disabled  
        @click.native.prevent="showDialog = true"  
        style="cursor: pointer;">  
        更多选项...  
      </el-option>  
    </el-select>  
    <el-dialog  
      title="选择选项"  
      :visible.sync="showDialog"  
      width="30%">  
      <div v-for="group in paginatedOptions" :key="group.page">  
        <p>第 {{ group.page }} 页</p>  
        <el-option  
          v-for="item in group.items"  
          :key="item.value"  
          :label="item.label"  
          :value="item.value"  
          @click="selectOption(item.value); showDialog = false;">  
        </el-option>  
      </div>  
      <el-pagination  
        @size-change="handleSizeChange"  
        @current-change="handleCurrentChange"  
        :current-page="currentPage"  
        :page-sizes="[10, 20, 30, 40]"  
        :page-size="pageSize"  
        layout="total, sizes, prev, pager, next, jumper"  
        :total="totalItems">  
      </el-pagination>  
    </el-dialog>  
  </div>  
</template>  
  
<script>  
export default {  
  data() {  
    return {  
      selected: null,  
      showDialog: false,  
      currentPage: 1,  
      pageSize: 10,  
      totalItems: 100, // 假设总项数为100  
      allOptions: [], // 这里应该包含所有选项,通过API或其他方式加载  
      paginatedOptions: [], // 分页后的选项  
    };  
  },  
  computed: {  
    options() {  
      // 这里可以返回一些初始选项,或者空数组  
      return [];  
    },  
  },  
  methods: {  
    handleDropdownVisibility(val) {  
      // 如果需要的话,可以在这里处理下拉菜单的显示逻辑  
      // 但对于分页,我们主要依赖点击“更多选项...”  
    },  
    showDialogOptions() {  
      // 根据当前页和每页数量计算分页选项  
      const start = (this.currentPage - 1) * this.pageSize;  
      const end = start + this.pageSize;  
      this.paginatedOptions = [  
        { page: this.currentPage, items: this.allOptions.slice(start, end) }  
      ];  
      // 如果需要支持多页预览,可以修改此逻辑来包含多页  
    },  
    handleSizeChange(val) {  
      this.pageSize = val;  
      this.currentPage = 1; // 当改变每页数量时,重置到第一页  
      this.showDialogOptions();  
    },  
    handleCurrentChange(val) {  
      this.currentPage = val;  
      this.showDialogOptions();  
    },  
    selectOption(value) {  
      this.selected = value;  
    },  
    // 假设在某个地方加载了所有选项  
    loadAllOptions() {  
      // 模拟从API加载数据  
      this.allOptions = Array.from({ length: 100 }, (_, i) => ({  
        value: i,  
        label: `选项 ${i + 1}`  
      }));  
      this.totalItems = this.allOptions.length;  
    },  
    // 在组件创建或需要时调用  
    mounted() {  
      this.loadAllOptions();  
    }  
  },  
};  
</script>

vue2下拉懒加载

<template>  
  <div>  
    <el-select v-model="selected" placeholder="请选择" ref="select">  
      <el-option  
        v-for="item in visibleOptions"  
        :key="item.value"  
        :label="item.label"  
        :value="item.value">  
      </el-option>  
      <el-option  
        disabled  
        @click.native.prevent="showPopover = true"  
        slot="prepend"  
        style="cursor: pointer;">  
        请选择...  
      </el-option>  
    </el-select>  
    <el-popover  
      placement="bottom"  
      width="100%"  
      trigger="manual"  
      v-model="showPopover"  
      popper-class="select-popover"  
      @before-leave="handleBeforeLeave">  
      <div  
        class="select-dropdown"  
        @scroll="handleScroll"  
        ref="dropdown">  
        <el-option  
          v-for="item in allOptions.slice(0, loadedCount)"  
          :key="item.value"  
          :label="item.label"  
          :value="item.value"  
          @click="selectOption(item.value); showPopover = false;">  
        </el-option>  
      </div>  
    </el-popover>  
  </div>  
</template>  
  
<script>  
export default {  
  data() {  
    return {  
      selected: null,  
      showPopover: false,  
      allOptions: [], // 假设这里有一千条数据  
      visibleOptions: [], // 用于el-select的初始选项(可以留空或放几个引导选项)  
      loadedCount: 0, // 已加载的选项数量  
      pageSize: 20, // 每页加载数量  
    };  
  },  
  methods: {  
    // 假设在某个地方加载了所有选项  
    loadAllOptions() {  
      // 模拟从API加载数据  
      this.allOptions = Array.from({ length: 1000 }, (_, i) => ({  
        value: i,  
        label: `选项 ${i + 1}`  
      }));  
    },  
    handleScroll(event) {  
      const target = event.target;  
      const scrollDistance = target.scrollHeight - target.scrollTop - target.clientHeight;  
      if (scrollDistance < 10) { // 接近底部时加载更多  
        this.loadMoreOptions();  
      }  
    },  
    loadMoreOptions() {  
      const newCount = Math.min(this.loadedCount + this.pageSize, this.allOptions.length);  
      this.loadedCount = newCount;  
    },  
    selectOption(value) {  
      this.selected = value;  
      // 可能需要做一些额外的处理,比如关闭下拉列表  
    },  
    handleBeforeLeave() {  
      // 在关闭popover前可能需要的处理  
    },  
    // 在组件创建或需要时调用  
    mounted() {  
      this.loadAllOptions();  
      this.loadedCount = this.pageSize; // 初始加载一定数量的选项  
    }  
  }  
};  
</script>  
  
<style>  
.select-popover .el-popover__wrap {  
  padding: 0;  
}  
.select-dropdown {  
  max-height: 300px; /* 设置最大高度以产生滚动 */  
  overflow-y: auto;  
}  
</style>

vue3下拉分页

<template>
  <div>
    <!-- 下拉列表 -->
    <el-select v-model="selectedValue" placeholder="请选择" @change="handleChange">
      <el-option
        v-for="item in currentItems"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      />
    </el-select>

    <!-- 分页组件 -->
    <el-pagination
      v-if="totalItems > pageSize"
      layout="prev, pager, next"
      :total="totalItems"
      :page-size="pageSize"
      :current-page="currentPage"
      @current-change="handlePageChange"
    />
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';
import { ElMessage } from 'element-plus';

// 模拟 API 获取数据
const fetchData = (page, pageSize) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const total = 50; // 假设总数据量为 50
      const items = Array.from({ length: pageSize }, (_, index) => ({
        label: `选项 ${index + 1 + (page - 1) * pageSize}`,
        value: index + 1 + (page - 1) * pageSize,
      }));
      resolve({ items, total });
    }, 500);
  });
};

// 设置响应式状态
const selectedValue = ref(null);
const currentPage = ref(1);
const pageSize = ref(10); // 每页显示的数量
const totalItems = ref(0);
const items = ref([]);

// 当前页的项目
const currentItems = computed(() => {
  return items.value;
});

// 获取数据
const getData = async (page) => {
  try {
    const response = await fetchData(page, pageSize.value);
    items.value = response.items;
    totalItems.value = response.total;
  } catch (error) {
    ElMessage.error('数据加载失败');
  }
};

// 页码改变时的处理函数
const handlePageChange = (page) => {
  currentPage.value = page;
  getData(page);
};

// 监听下拉列表选项变化
const handleChange = (value) => {
  console.log('当前选中的值:', value);
};

// 初次加载数据
onMounted(() => {
  getData(currentPage.value);
});
</script>

<style scoped>
/* 添加一些简单的样式 */
</style>

vue3下拉懒加载

//@scroll="handleScroll"----el-select没有监听滚动事件需要自行添加,并且为滚动添加防抖
// let select: any = document.querySelector(".el-select-dropdown__wrap");
 // select.addEventListener("scroll", (event: any) => {
 //   console.log("滚动事件");
   // let timer: any = null;
  //  if (timer) {
  //    clearTimeout(timer);
  //  }
  //  timer = setTimeout(() => {
    //  loadMoreData();
   // }, 5000);
 // });
<template>
  <el-select v-model="selectedValue" placeholder="请选择" @scroll="handleScroll">
    <el-option
      v-for="item in items"
      :key="item.value"
      :label="item.label"
      :value="item.value"
    />
    <el-option v-if="loading" disabled>加载中...</el-option>
  </el-select>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';

// 模拟 API 获取数据
const fetchLazyData = (page, pageSize) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const total = 100; // 假设总数据量为 100
      const items = Array.from({ length: pageSize }, (_, index) => ({
        label: `选项 ${index + 1 + (page - 1) * pageSize}`,
        value: index + 1 + (page - 1) * pageSize,
      }));
      resolve({ items, total });
    }, 500);
  });
};

// 设置响应式状态
const selectedValue = ref(null);
const items = ref([]);
const pageSize = ref(10);
const currentPage = ref(1);
const loading = ref(false);
const totalItems = ref(0);

// 获取数据
const loadMoreData = async () => {
  if (loading.value || items.value.length >= totalItems.value) return;

  loading.value = true;
  try {
    const response = await fetchLazyData(currentPage.value, pageSize.value);
    items.value = [...items.value, ...response.items];
    totalItems.value = response.total;
    currentPage.value += 1;
  } catch (error) {
    ElMessage.error('加载失败');
  } finally {
    loading.value = false;
  }
};

// 处理滚动懒加载
const handleScroll = (event) => {
  const { target } = event;
  if (target.scrollTop + target.clientHeight >= target.scrollHeight - 50) {
    loadMoreData();
  }
};

// 初次加载数据
onMounted(() => {
  loadMoreData();
});
</script>

<style scoped>
/* 添加一些简单的样式 */
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值