Vue3 + ts+ elementUi 实现后台数据渲染到下拉框选项中,滑动加载更多数据效果

前言

功能需求:下拉框中分页加载后端接口返回的人员数据,实现滑动加载更多数据效果,并且可以手动搜索定位数据,此项目使用Vue3 + ts+ elementUi 实现

实现

把此分页滑动加载数据功能封装成vue中的hooks,文件命名为useMoreUser.ts

import {ref,reactive,nextTick} from 'vue'

export  const useMoreUser = () => {
  const selectMoreData = reactive({
    page: 0, //当前页
    loading: false, //loading
    hasMore: true, //判断是否还有更多数据
    selectValue: '', //下拉框选中数据
    selectOptions: [] //下拉框选项
  })
  // 人员列表加载数据列表【newPage: 页数,name: 搜索条件】
  const loadDataList = async (newPage: number, name?: string = '' ) => {
    try {
      selectMoreData.loading = true;
      //后端接口,入参为搜索条件人员姓名,页数
      let res = await getUserList(name, newPage); 
      if (newPage === 1) { //初始化
        selectMoreData.selectOptions = [];
      }
      //存储后端接口返回数据
      selectMoreData.selectOptions.push(...res.rows);
      //判断是否还有更多数据
      selectMoreData.hasMore = selectMoreData.selectOptions.length < res.total;
      selectMoreData.page = newPage;
    } catch (err) {
      console.error(err);
    } finally {
      selectMoreData.loading = false;
    }
  };

  //加载更多数据
  const handleLoadMore = async (newPage: number,  name?: string = '' ) => {
    await loadDataList(newPage,name);
  };

  //返回下拉框选项
  const getList = ()=>{
    return selectMoreData.selectOptions;
  }
  //导出数据方法等
  return {selectMoreData,getList, loadDataList, handleLoadMore}
}

再继续封装下拉框选项组件 option.vue

<!-- 监听 el-select 的滚动,并提供触底加载数据的回调 -->
<template>
    <el-option ref="el" class="el-select-loading" value="">
        <template v-if="hasMore">
            <el-icon class="el-select-loading__icon"><Loading /></el-icon>
            <span class="el-select-loading__tips">{{ loadingText || "正在加载" }}</span>
        </template>
        <template v-else>{{ noMoreText || "到底了~" }}</template>
    </el-option>
</template>

<script setup lang="ts">
  import { onMounted, onUnmounted, ref } from "vue";
  import { ElOption } from "element-plus";

  interface Props {
    // 当前页码
    page: number;
    // 是否加载中,用来过滤重复的加载
    loading: boolean;
    // 加载中的提示文案
    loadingText?: string;
    // 是否有更多数据可加载
    hasMore: boolean;
    // 没有更多数据的提示文案
    noMoreText?: string;
  }

  const props = defineProps<Props>();

  interface Emits {
    (event: "loadMore", data: number): any;
  }

  const emit = defineEmits<Emits>();

  const el = ref<typeof ElOption>();
  const observer = ref<IntersectionObserver>();

  // 组件加载成功,监听滚动
  onMounted(() => {
    if (!el.value) {
      return;
    }
    const callback: IntersectionObserverCallback = (entries) => {
      if (props.loading || !props.hasMore || !entries[0].isIntersecting) {
        return;
      }
      emit("loadMore", props.page + 1);
    };
    const options: IntersectionObserverInit = {
      root: el.value.$el.parentElement?.parentElement,
      rootMargin: "0px 0px 0px 0px",
    };
    observer.value = new IntersectionObserver(callback, options);
    observer.value.observe(el.value.$el);
  });

  // 组件卸载成功,取消滚动监听
  onUnmounted(() => {
    if (!el.value) {
      return;
    }
    observer.value?.unobserve(el.value.$el);
  });
</script>

<style lang="scss" scoped>

    .el-select-loading {
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: initial;
        pointer-events: none;
        color: var(--el-color-info);
        font-size: 12px;

        &__icon {
            font-size: 16px;
            animation: rotate 1.5s linear infinite;
        }

        &__tips {
            margin-left: 6px;
        }

        @keyframes rotate {
            from {
                transform: rotate(0deg);
            }
            to {
                transform: rotate(360deg);
            }
        }
    }
</style>

最后到咱们真正使用页面index.vue,封装时候有些费事,但是使用起来就简单了
template部分

 <el-select class="customSelect" filterable remote :remote-method="remoteMethod"
                         v-model="user" placeholder="请选择人员"
                         style="width: 100%">
                <el-option
                    v-for="item in selectMoreData.selectOptions"
                    :key="item.userId"
                    :label="`${item.userName}`"
                    :value="item.userId"
                >
                  <span style="float: left">{{ `${item.userName}` }</span>
                </el-option>
                <ElSelectLoading
                    :page="selectMoreData.page"
                    :loading="selectMoreData.loading"
                    :hasMore="selectMoreData.hasMore"
                    @loadMore="handleLoadMore"
                />
              </el-select>

script部分

<script lang="ts" setup>
import {ref, reactive, onUnmounted, onMounted, nextTick, computed, watch} from 'vue'
import ElSelectLoading from "@/components/Option/option.vue";
import {useMoreUser} from '@/hooks/useMoreUser.ts'
const {selectMoreData, loadDataList, handleLoadMore} = useMoreUser();

const user = ref('');
const remoteMethod = (query: string) => {
  loadDataList(1, query);
}
</script>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近在使用 Vue3 和 TypeScript 开发项目时,遇到了一个需要进行文件上传的场景,于是就使用了 Element-Plus 的上传组件来完成这个功能。 Element-Plus 是基于 Vue3 的 UI 组件库,提供了一些比较常用的组件,其包括了文件上传组件。在使用文件上传组件时,需要传入文件上传的API地址和文件上传的前缀,可以通过props属性进行传值。例如: ``` <el-upload :action="url" :auto-upload="false" :before-upload="beforeUpload" :file-list="fileList" list-type="text" ref="upload" :on-success="handleSuccess" :on-error="handleError" > <el-button type="primary" :loading="uploading" size="small" > 上传文件 </el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload> ``` 其,`:action` 表示文件上传的 API 地址,`:before-upload` 表示文件上传之前的钩子函数,用于限制上传文件类型和大小,`:file-list` 表示已上传的文件列表,`:on-success` 和 `:on-error` 表示上传成功和上传失败的回调函数。 在使用 TypeScript 进行开发时,需要对元素进行类型定义,以便更好地使用。例如,定义一个类型为 `FileList` 的变量 fileList,就可以在上传组件使用: ``` const fileList: Ref<UploadFile[]> = ref([]); <el-upload ... :file-list="fileList" ... > </el-upload> ``` 这里,`Ref<UploadFile[]>` 表示定义一个 `Ref` 类型的变量 fileList,其值为 `UploadFile` 类型的数组。 在上传文件时,在 `before-upload` 钩子函数,可以限制上传文件的格式和大小。例如: ``` beforeUpload(file: File) { const isJPG = file.type === 'image/jpeg' const isPNG = file.type === 'image/png' const isLt2M = file.size / 1024 / 1024 < 2 if (!isJPG && !isPNG || !isLt2M) { this.$message.error('上传文件只能是 JPG/PNG 格式,且不超过 2MB!') } else { this.uploading = true return true } } ``` 这里,判断文件的类型是否为 jpg/png,判断文件的大小是否小于 2MB。如果不满足条件,就会弹出提示,否则开始上传。 在上传成功和上传失败的回调函数,可以对上传结果进行处理。例如: ``` handleSuccess(response: UploadSuccessResponse, file: UploadFile) { this.uploading = false this.fileList.push(file) this.$message.success('上传成功') }, handleError(error: Error, response: UploadFile, file: UploadFile) { this.uploading = false this.$message.error('上传失败') } ``` 这里,当上传成功时,将文件添加到已上传的文件列表,并弹出提示;当上传失败时,弹出提示。 综上所述,实现 Vue3 TS Element-Plus 文件上传的主要步骤包括:引入 Element-Plus 组件库,传入 API地址和前缀,进行类型定义,限制上传文件类型和大小,处理上传结果等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值