VUE 弹框内容懒加载-真实项目

发布于:2024-04-22 ⋅ 阅读:(180) ⋅ 点赞:(0)

背景:VUE 页面,点击按钮,弹框,内容从接口获取,数据量比较大,鼠标滑到页面最底部,调取一次接口,分批加载;

demo:

<template>
  <div>
    <!-- 触发弹框的按钮 -->
    <el-button @click="dialogVisible = true">打开弹框</el-button>

    <!-- 数据加载中的提示 -->
    <el-loading v-if="loading" lock text="数据加载中,请稍候..."></el-loading>

    <!-- 弹框 -->
    <el-dialog
      :visible.sync="dialogVisible"
      title="大批量数据列表"
      @before-close="handleClose"
    >
      <div class="data-list" ref="dataList" @scroll="handleScroll">
        <!-- 使用 v-for 渲染数据列表 -->
        <div v-for="(item, index) in items" :key="index" class="data-item">
          {{ item }}
        </div>
      </div>

      <!-- 分页控件,点击加载更多 -->
      <el-button
        slot="footer"
        size="small"
        @click="loadMore"
        :disabled="loading"
        >加载更多</el-button
      >
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false, // 控制弹框显示
      loading: false, // 数据加载中
      items: [], // 数据列表
      currentPage: 1, // 当前页码
      pageSize: 200, // 每页数据量
      hasMore: true, // 是否还有更多数据
    };
  },
  methods: {
    // 加载更多数据
    loadMore() {
      console.log("调取loadMore方法");
      if (!this.hasMore) return;

      this.loading = true;
      this.currentPage++;

      // 模拟从接口获取数据
      this.fetchData(this.currentPage, this.pageSize)
        .then((data) => {
          this.items = this.items.concat(data);
          this.loading = false;

          // 判断是否还有更多数据
          if (data.length < this.pageSize) {
            this.hasMore = false;
          }
        })
        .catch((error) => {
          console.error("加载数据失败", error);
          this.loading = false;
        });
    },
    // 关闭弹框前的回调
    handleClose() {
      this.items = []; // 清空数据列表
      this.currentPage = 1;
      this.hasMore = true;
      this.loading = false; // 确保关闭弹框时停止加载
    },
    // 模拟获取数据的方法
    fetchData(page, pageSize) {
      return new Promise((resolve, reject) => {
        // 这里应该是调用你的 API 获取数据
        // 以下是一个模拟的数据响应示例
        const mockData = new Array(pageSize)
          .fill(null)
          .map((_, index) => `Item ${(page - 1) * pageSize + index + 1}`);
        setTimeout(() => {
          resolve(mockData);
        }, 1000);
      });
    },
    // 监听滚动事件,当滚动到底部时加载更多数据
    // handleScroll() {
    //   if (this.$refs.dataList && this.$refs.dataList.scroll) {
    //     const scrollContainer = this.$refs.dataList.scroll;
    //     if (
    //       scrollContainer.scrollTop + scrollContainer.clientHeight >=
    //       scrollContainer.scrollHeight - 10
    //     ) {
    //       this.loadMore();
    //     }
    //   }
    // },
    // 监听滚动事件,当滚动到底部时加载更多数据
    handleScroll(event) {
      // 获取滚动容器的引用
      const scrollContainer = event.target || this.$refs.dataList;

      // 确保 scrollContainer 是一个有效的 DOM 元素
      if (!scrollContainer) return;

      // 计算滚动位置
      const isAtBottom =
        scrollContainer.scrollTop + scrollContainer.clientHeight >=
        scrollContainer.scrollHeight - 10;

      // 只有在滚动到底部时才调用 loadMore 方法
      if (isAtBottom && this.hasMore) {
        console.log('zoujinqu')
        this.loadMore();
      }
    },
  },
  mounted() {
    // 监听滚动事件,当滚动到底部时加载更多数据
    // this.$refs.dataList.addEventListener('scroll', this.handleScroll);
    this.$nextTick(() => {
      if (this.$refs.dataList) {
        this.$refs.dataList.addEventListener("scroll", this.handleScroll);
      }
    });
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听
    if (this.$refs.dataList) {
      this.$refs.dataList.removeEventListener("scroll", this.handleScroll);
    }
  },
};
</script>

<style scoped>
.data-list {
  max-height: 500px; /* 设置一个固定高度 */
  overflow-y: auto; /* 允许垂直滚动 */
}
.data-item {
  padding: 8px;
  border-bottom: 1px solid #eee;
}
</style>

真实项目:

弹框内容是分接口给的数据,分批次加载(其实跟分页是一回事),鼠标滑到最底部,调取一次接口,加载一次数据。

<template>
  <div>
    <div style="position: relative; transition: all ease 0.5s">
      <el-table :data="defectList" style="width: 100%">
        <el-table-column prop="logFileName" label="日志信息" :show-overflow-tooltip="true" width="140">
          <template slot-scope="scope">
            <span class="color-list cursor" @click="logInfo(scope.row.logFileId)">{{ scope.row.logFileName }}</span>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <el-dialog title="日志详情" :visible.sync="dialogVisible" width="800px" :before-close="closeDialog">
      <div class="data-list" ref="dataList" @scroll="handleScroll">
        <div>
          {{ logDataInfo }}
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { warn, downloadFetchFiles } from '@/utils/common'
import API from '@/api'
import { Base64 } from 'js-base64'

export default Vue.extend({
  components: {},
  props: {
    defectList: {
      type: Array,
      default: () => []
    },
    total: {
      type: Number,
      default: 0
    },
    onPageChange: {
      type: Function,
      default: () => {}
    }
  },
  data() {
    return {
      selectedRow: null,
      dialogVisible: false,
      logDataInfo: '',
      loading: false,
      hasMore: true,
      currentPage: 1, // 当前页数
      pageSize: 50000 // 每页数量,
    }
  },
  mounted() {
    this.$nextTick(() => {
      if (this.$refs.dataList) {
        this.$refs.dataList.addEventListener('scroll', this.handleScroll)
      }
    })
  },
  methods: {
    logInfo(id: string) {
      localStorage.setItem('IDD', id)
      this.dialogVisible = true
      this.loadMore()
    },
    // 加载数据
    async loadMore() {
      try {
        if (this.loading || !this.hasMore) return // 如果正在加载或没有更多数据了,则不再发送请求

        let id = localStorage.getItem('IDD')
        if(this.currentPage - 1 >= this.logTotal) {
          return false;
        }
        const response = await API.Defect.logDetailsData({
          page: this.currentPage,
          pageSize: this.pageSize,
          fileId: id
        })
        const data = Base64.decode(response.data.list)
        if (data) {
          this.logDataInfo = data
          this.currentPage++ // 当前页数加一
        } else {
          this.hasMore = false // 没有更多数据了
        }
      } catch (error) {
        warn(error, true)
      }
    },
    // 监听滚动事件,当滚动到底部时加载更多数据
    handleScroll(event: any) {
      // 获取滚动容器的引用
      const scrollContainer = event.target || this.$refs.dataList

      // 确保 scrollContainer 是一个有效的 DOM 元素
      if (!scrollContainer) return

      // 计算滚动位置
      const isAtBottom = scrollContainer.scrollTop + scrollContainer.clientHeight >= scrollContainer.scrollHeight - 10

      if (isAtBottom && this.hasMore) {
        console.log('zoujinqu')
        this.loadMore()
      }
    },
    closeDialog() {
      this.dialogVisible = false
      this.dataList = []
      this.loading = false
      this.hasMore = true
      this.currentPage = 1
    }
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听
    if (this.$refs.dataList) {
      this.$refs.dataList.removeEventListener('scroll', this.handleScroll)
    }
  }
})
</script>


网站公告

今日签到

点亮在社区的每一天
去签到