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

Django如何实现初始加载指定数量商品 滚动自动加载更多

Django滚动分页加载商品实现方案

整体实现分为后端分页接口改造、前端交互逻辑两部分,改完即可实现初始加载10条、滚动到底自动追加10条的效果。

后端改造(views.py)

用Django自带的Paginator实现分页,区分初始页面请求和ajax滚动请求,分别返回完整页面和商品卡片片段:

from django.core.paginator import Paginator

def All(request):
    page_size = 10
    # 获取当前页码,默认加载第1页
    page = int(request.GET.get('page', 1))
    # 商品必须加固定排序,避免分页数据错乱
    all_products = product.objects.all().order_by('-id')
    paginator = Paginator(all_products, page_size)
    current_page_products = paginator.page(page)

    # 滚动触发的ajax请求,直接返回商品卡片HTML片段
    if request.headers.get('x-requested-with') == 'XMLHttpRequest':
        return render(request, 'product_items.html', {'p': current_page_products})
    
    # 初始页面请求,返回带第一页商品的完整页面,同时传总页数给前端
    total_pages = paginator.num_pages
    return render(request, 'home.html', {
        'p': current_page_products,
        'total_pages': total_pages
    })

新建templates/product_items.html文件,只存循环渲染的商品卡片代码,供ajax请求返回用:

{% for item in p %}
<div class='card'>
    <img src="{{item.image}}" alt="商品图片">
    <p>{{item.description}}</p>
    <a href="{{item.buy}}" target='_blank' rel='noopener noreferrer'>
        <button><span class="price">${{item.price}}</span> buy</button>
    </a>
</div>
{% endfor %}

前端改造(home.html)

把原来的商品循环部分替换成以下代码,加滚动监听逻辑,自动触发下一页加载:

<div class="grid" id="productGrid">
    {% for item in p %}
    <div class='card'>
        <img src="{{item.image}}" alt="商品图片">
        <p>{{item.description}}</p>
        <a href="{{item.buy}}" target='_blank' rel='noopener noreferrer'>
            <button><span class="price">${{item.price}}</span> buy</button>
        </a>
    </div>
    {% endfor %}
</div>
<!-- 加载状态提示 -->
<div id="loadingTip" style="text-align: center; padding: 20px; display: none;">加载中...</div>

<script>
// 初始化分页参数
let currentPage = 1
const totalPages = {{ total_pages }}
let isLoading = false
const productGrid = document.getElementById('productGrid')
const loadingTip = document.getElementById('loadingTip')

// 监听页面滚动
window.addEventListener('scroll', () => {
    // 已经加载完所有页、或者正在加载中时不触发新请求
    if (currentPage >= totalPages || isLoading) return

    // 距离页面底部200px时提前触发加载,提升体验
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    const windowHeight = window.innerHeight
    const docTotalHeight = document.documentElement.scrollHeight
    if (scrollTop + windowHeight >= docTotalHeight - 200) {
        loadNextPage()
    }
})

// 加载下一页商品
function loadNextPage() {
    isLoading = true
    loadingTip.style.display = 'block'
    currentPage += 1

    // 拉取下一页数据
    fetch(`/all/?page=${currentPage}`, {
        headers: {
            'X-Requested-With': 'XMLHttpRequest'
        }
    })
    .then(res => res.text())
    .then(htmlFragment => {
        // 把新的商品卡片追加到容器末尾
        productGrid.insertAdjacentHTML('beforeend', htmlFragment)
        isLoading = false
        loadingTip.style.display = 'none'
        // 加载完最后一页时显示提示
        if (currentPage >= totalPages) {
            loadingTip.textContent = '已经到底啦'
            loadingTip.style.display = 'block'
        }
    })
    .catch(err => {
        // 加载失败时回退状态
        currentPage -= 1
        isLoading = false
        loadingTip.style.display = 'none'
        console.error('商品加载失败:', err)
    })
}
</script>

注意事项

  • 确认urls.py中All视图对应的路由地址和js里fetch请求的地址一致,路由不是/all/的话自行替换即可
  • 原模板中循环变量和传入的商品列表参数同名均为p,易引发作用域混淆,统一改为item更稳妥
  • 必须加isLoading状态锁,避免滚动过程中重复触发请求,保证同一时间只有一个加载请求在执行
  • 原代码中<img></img>为错误写法,img是自闭合单标签,无需额外闭合标签,补充alt属性更符合规范
  • 原卡片内p标签写了固定id="id",循环渲染后会出现重复id,不符合HTML规范,已移除

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:12:43