You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue多分类新闻列表实现无限滚动分页的方案咨询

问题:多分类新闻数据的无限滚动分页优化

1. API响应数据结构

{
    "Business": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "Entertainment": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "Health": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "Science": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "Sports": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "Technology": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "US": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ],
    "World": [
        {
            "link": "...",
            "og": "...",
            "source": "...",
            "source_icon": "...",
            "title": "..."
        }
    ]
}

2. 现有Vue实现代码

import { ref, onMounted } from 'vue';
import axios from 'axios';
import { NewsResponse } from '@/utils';

const baseURL = '...';

const isLoading = ref<boolean>(true);
const newsFeed = ref<NewsResponse>();

onMounted(() => {
  fetchNewsFeed();
});

const fetchNewsFeed = () => {
  axios.get(baseURL)
    .then((res) => {
      newsFeed.value = res.data;
      isLoading.value = false;
      console.log('api response\n',newsFeed.value);
      
    })
    .catch((err) => {
      console.log(err);
    })
}

3. 需求与问题

当前用嵌套v-for渲染数据正常,但每个分类有46-50条数据,导致页面过长。希望实现每行4个元素、初始展示12条的无限滚动分页,但不确定如何处理这种多数组结构。

4. 已尝试的扁平化方案

let tmpCat = [];
let tmpItems = [];
Object.entries(rawData).forEach((cat, i) => {
  tmpCat.push(cat[0]);
  cat[1].forEach((item) => {
    item['category'] = tmpCat[i];
    tmpItems.push(item);
  })
});

优化建议

1. 简化扁平化实现

你的思路没问题,但可以用数组原生方法简化代码,避免冗余的临时数组,逻辑更清晰:

// 直接通过flatMap一步完成分类遍历和条目映射
const flattenedNews = Object.entries(rawData).flatMap(([category, items]) => {
  // 用扩展运算符避免修改原数据(如果不需要保留原数据也可以直接赋值)
  return items.map(item => ({ ...item, category }));
});

flatMap会自动将二维数组扁平化,比手动forEach+push更高效,代码更简洁。

2. 无限滚动分页实现步骤

(1)状态管理

添加响应式变量控制展示数量:

const displayCount = ref(12); // 初始展示12条
const flattenedNews = ref([]); // 存储扁平化后的所有数据

(2)滚动监听逻辑

监听页面滚动,到达底部时加载更多:

const handleScroll = () => {
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
  const clientHeight = document.documentElement.clientHeight || window.innerHeight;

  // 距离底部100px时触发加载,同时判断是否还有未展示数据
  if (scrollTop + clientHeight >= scrollHeight - 100 && displayCount.value < flattenedNews.value.length) {
    displayCount.value += 12; // 每次加载12条
  }
};

// 挂载时添加监听,卸载时移除
onMounted(() => {
  window.addEventListener('scroll', handleScroll);
});
onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll);
});

(3)模板渲染

对扁平化数组做切片渲染,配合CSS实现每行4个布局:

<template>
  <div class="news-grid" v-if="!isLoading">
    <div 
      v-for="(item, index) in flattenedNews.slice(0, displayCount.value)" 
      :key="index" 
      class="news-item"
    >
      <div class="category-tag">{{ item.category }}</div>
      <a :href="item.link" class="news-title">{{ item.title }}</a>
      <!-- 其他内容:来源、封面图等 -->
    </div>
  </div>
  <div v-else>加载中...</div>
</template>

<style scoped>
.news-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  padding: 20px;
}
.news-item {
  border: 1px solid #eee;
  padding: 12px;
  border-radius: 8px;
}
/* 响应式适配,小屏幕调整列数 */
@media (max-width: 1024px) {
  .news-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
</style>

3. 额外优化点

  • 如果API支持分页,可以考虑后端分页,避免一次性加载大量数据;
  • 可以使用VueUse的useInfiniteScroll工具函数,简化滚动监听逻辑;
  • 为flattenedNews添加类型定义,符合TypeScript规范。

内容的提问来源于stack exchange,提问作者newbiedev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:14:51