vuejs 中的无限滚动

问题描述 投票:0回答:1

我正在卡片组件中实现无限滚动,其中每行有 3 张卡片,并且在到达页面末尾时,我想为下一页进行 api 调用以显示并显示下一张卡片。这是我的代码实现无限滚动不起作用:

<template>
  <div
    class="container"
    ref="scrollContainer"
    @dragover.prevent="handleDragOverContainer"
    @drop.prevent="handleDrop"
  >
    <div class="card-container">
      <div class="card">
        <AddCourseCard />
      </div>
      <div
        class="card"
        v-for="(element, index) in products"
        :key="index"
        :draggable="true"
        @dragstart="handleDragStart(index)"
        @dragover.prevent="handleDragOverCard(index)"
        @dragend="handleDragEnd"
      >
        <CoursesCard
          :title="element.title"
          :text="element.text"
          :imageSrc="element.imageSrc"
          :productId="element.id"
        />
      </div>
    </div>
  </div>
</template>

<script>
import AddCourseCard from './AddCourseCard.vue'
import CoursesCard from './CourseCard.vue'
import { OfferService } from '../../service/index'
import { GroupState } from '../../composition/groups'
import Draggable from 'vuedraggable'

export default {
  name: 'Learning',
  components: {
    CoursesCard,
    AddCourseCard,
    draggable: Draggable,
  },
  data() {
    return {
      products: [],
      pageNo: 1, // Initialize pageNo
      limit: 10, // Set your desired limit per page
      loading: false,
      isGroupAdmin: GroupState.state.isGroupAdmin,
      dragData: null,
      draggedIndex: null,
      dropTargetIndex: null,
      reachedEnd: false,
      // Flag to prevent multiple requests while loading
      dragOptions: {
        // Specify any options for Vue.Draggable here if needed
        group: 'cards', // Add a group to allow cards to be dragged between different lists
        animation: 200, // Animation duration when items are reordered
      },
      dummyData: [
        {
          title: 'Card 1',
          text: 'Some quick example text for Card 1',
          imageSrc: 'https://picsum.photos/1600/1176/?image=25',
        },
        {
          title: 'Card 2',
          text: 'Some quick example text for Card 2',
          imageSrc: 'https://picsum.photos/1600/1176/?image=26',
        },
        {
          title: 'Card 3',
          text: 'Some quick example text for Card 3',
          imageSrc: 'https://picsum.photos/1600/1176/?image=27',
        },
        {
          title: 'Card 4',
          text: 'Some quick example text for Card 1',
          imageSrc: 'https://picsum.photos/1600/1176/?image=25',
        },
        {
          title: 'Card 5',
          text: 'Some quick example text for Card 2',
          imageSrc: 'https://picsum.photos/1600/1176/?image=26',
        },
        {
          title: 'Card 6',
          text: 'Some quick example text for Card 3',
          imageSrc: 'https://picsum.photos/1600/1176/?image=27',
        },
        // Add more dummy data items as needed
      ],
    }
  },
  mounted() {
    // Call the initial API request when the component is mounted

    this.fetchAllProducts()
    const container = this.$refs.scrollContainer
    if (container) {
      container.addEventListener('scroll', this.handleScroll)
    }
  },
  methods: {
    handleScroll() {
      const container = this.$refs.scrollContainer
      if (!container) return

      // Calculate when to trigger fetching more data based on scroll position
      const scrollPosition = container.scrollTop + container.clientHeight
      const maxScroll = container.scrollHeight

      if (
        scrollPosition >= maxScroll - 100 &&
        !this.loading &&
        !this.reachedEnd
      ) {
        // You can adjust the threshold (100 in this example) to your needs
        this.fetchNextPage()
      }
    },
    async fetchNextPage() {
      // Your existing code to fetch the next page of data
      // ...

      if (this.pagesEnd) {
        this.reachedEnd = true // Set the flag to indicate the end of data
      }
    },
    async fetchAllProducts() {
      if (!this.isGroupAdmin) {
        this.fetchDataFromAPIForGroup()
      } else {
        this.fetchDataFromAPI()
      }
    },
    async fetchDataFromAPI() {
      if (this.loading) return // Prevent multiple requests while loading

      this.loading = true
      try {
        const response = await OfferService.getOfferProductForUser({
          pageNo: this.pageNo,
          limit: this.limit,
        })

        // Append the new data to the existing products array
        this.products = [...this.products, ...response]

        // Increment the pageNo for the next request
        this.pageNo++
      } catch (error) {
        console.error('Error fetching data from API:', error)
      } finally {
        this.loading = false
      }
    },
    async fetchDataFromAPIForGroup() {
      if (this.loading) return // Prevent multiple requests while loading

      this.loading = true
      try {
        const response = await OfferService.getOfferProductForGroup({
          pageNo: this.pageNo,
          limit: this.limit,
        })

        // Append the new data to the existing products array
        this.products = [...this.products, ...response]

        // Increment the pageNo for the next request
        this.pageNo++
      } catch (error) {
        console.error('Error fetching data from API:', error)
      } finally {
        this.loading = false
      }
    },

    handleDragStart(index) {
      this.draggedIndex = index
    },
    handleDragOverCard(index) {
      this.dropTargetIndex = index
    },
    handleDragOverContainer(event) {
      // Prevent the default behavior, which is to not allow dropping
      event.preventDefault()
    },
    handleDrop() {
      if (this.draggedIndex !== null && this.dropTargetIndex !== null) {
        // Splice the dragged card out of the dummyData array
        const draggedCard = this.products.splice(this.draggedIndex, 1)[0]

        // Insert the dragged card at the drop target index
        this.products.splice(this.dropTargetIndex, 0, draggedCard)

        // Reset the dragged and drop target indices
        this.draggedIndex = null
        this.dropTargetIndex = null
      }
    },

    // Handle drag over
    handleDragOver(index) {
      if (!this.dragData) return

      // Prevent the default behavior, which is to not allow dropping
      event.preventDefault()

      // Swap the positions of the dragged item and the drop target
      const temp = this.dummyData[index]
      this.dummyData[index] = this.dragData
      this.dragData = temp
      console.log(this.dummyData)
    },

    // Handle drag end
    handleDragEnd() {
      this.dragData = null
    },
  },
}
</script>

<style scoped>
.container {
  display: flex;
  justify-content: center;
  /* Added to enable scrolling */
  overflow-y: auto;
}

.card-container {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  max-width: 1216px;
  margin: 0 auto;
}

.card {
  flex: 0 0 calc(33.33% - 10px);
  max-width: calc(33.33% - 10px);
  margin-bottom: 20px;
  box-sizing: border-box;
}

@media (max-width: 768px) {
  .card {
    flex: 0 0 calc(50% - 10px);
    max-width: calc(50% - 10px);
  }
}

@media (max-width: 480px) {
  .card {
    flex: 0 0 100%;
    max-width: 100%;
  }
}
</style>

我还添加了样式,以防任何 css 可能成为拦截器,请帮助理解这里的问题,我已经被困了几个小时了

html css typescript vue.js infinite-scroll
1个回答
0
投票

确保 scrollContainer div 具有定义的高度。溢出-y:auto;仅当容器具有最大高度或固定高度时,样式才会创建滚动条。

<div class="container" ref="scrollContainer" style="max-height: 70vh;" @dragover.prevent="handleDragOverContainer" @drop.prevent="handleDrop">

© www.soinside.com 2019 - 2024. All rights reserved.