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

Django社交平台Feed无限滚动功能实现求助

实现Feed无限滚动方案

后端调整(Django视图)

修改你的views.py,让Feed视图支持AJAX请求,返回分页的帖子HTML片段和是否还有下一页的标记:

from django.core.paginator import Paginator
from django.shortcuts import render
from django.http import JsonResponse
from .models import Post  # 替换成你的帖子模型

def feed(request):
    # 按创建时间倒序获取帖子列表
    post_list = Post.objects.all().order_by('-created_at')
    # 保持每页6条的分页规则
    paginator = Paginator(post_list, 6)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)
    
    # 判断是否为AJAX请求,返回JSON格式的分页数据
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        posts_html = render(request, 'post_item.html', {'posts': page_obj}).content.decode()
        return JsonResponse({
            'html': posts_html,
            'has_next': page_obj.has_next()
        })
    
    # 非AJAX请求返回完整页面
    return render(request, 'feed.html', {'page_obj': page_obj})

分离帖子模板片段

新建post_item.html模板,单独渲染单条帖子的HTML结构,方便后端返回片段给前端追加:

{% for post in posts %}
<div class="post-item">
    {% if post.image %}
        <img src="{{ post.image.url }}" alt="{{ post.caption }}">
    {% elif post.video %}
        <video src="{{ post.video.url }}" controls></video>
    {% endif %}
    <p class="post-caption">{{ post.caption }}</p>
    <!-- 替换成你现有帖子的其他元素,比如点赞、评论按钮等 -->
</div>
{% endfor %}

然后修改feed.html,将原有帖子列表部分替换为引用这个片段:

<div id="feed-container">
    {% include 'post_item.html' with posts=page_obj %}
</div>
<!-- 加载提示,初始隐藏 -->
<div id="loading" style="text-align: center; padding: 1rem; display: none;">加载中...</div>

前端滚动监听逻辑

在feed.html中添加JavaScript,实现滚动到底部自动加载下一页:

const feedContainer = document.getElementById('feed-container');
const loading = document.getElementById('loading');
let currentPage = 1;
let isLoading = false;
let scrollTimeout;

// 判断是否滚动到接近底部(提前100px触发,提升用户体验)
function isNearBottom() {
    return window.innerHeight + window.scrollY >= document.body.offsetHeight - 100;
}

// 防抖处理,避免滚动时频繁触发请求
function debounce(func, delay) {
    return function() {
        if (scrollTimeout) clearTimeout(scrollTimeout);
        scrollTimeout = setTimeout(func, delay);
    }
}

// 加载下一页内容
async function loadNextPage() {
    if (isLoading) return;
    isLoading = true;
    loading.style.display = 'block';
    currentPage++;

    try {
        const res = await fetch(`/feed/?page=${currentPage}`, {
            headers: {'X-Requested-With': 'XMLHttpRequest'}
        });
        const data = await res.json();
        
        // 将新帖子HTML追加到容器末尾
        feedContainer.insertAdjacentHTML('beforeend', data.html);
        loading.style.display = 'none';
        isLoading = false;

        // 如果没有下一页,移除滚动监听
        if (!data.has_next) {
            window.removeEventListener('scroll', debouncedScroll);
        }
    } catch (err) {
        console.error('加载失败:', err);
        loading.textContent = '加载失败,点击重试';
        loading.style.display = 'block';
        // 添加点击重试功能
        loading.onclick = () => {
            loading.textContent = '加载中...';
            loadNextPage();
        };
        isLoading = false;
    }
}

// 绑定防抖后的滚动事件
const debouncedScroll = debounce(() => {
    if (isNearBottom()) loadNextPage();
}, 200);

window.addEventListener('scroll', debouncedScroll);

// 页面加载完成后,检查是否已在底部(处理初始内容不足一页的情况)
window.addEventListener('load', () => {
    if (isNearBottom()) loadNextPage();
});

注意事项

  • 确保post_item.html的样式和原有Feed中的帖子完全一致,避免追加后出现样式错乱
  • 根据你的帖子模型字段,调整模板和视图中的字段名(比如图片/视频字段名)
  • 测试分页逻辑,确认最后一页不会重复加载
  • 可以根据需求调整提前触发加载的距离(当前为100px)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:22:44