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

AngularJS嵌套ng-repeat内容分页适配视口问题求助

基于视口高度的嵌套ng-repeat分页解决方案

我来给你梳理一个适配动态高度的分页方案——毕竟固定slice(0,10)的方式,完全没法应对这种外层项高度不一的嵌套场景(有的日期下节目多,高度就高;有的少,高度就低)。咱们核心思路是先计算每个外层项的实际高度,再根据视口高度动态拆分分页,具体实现如下:

1. 控制器层面的分页逻辑(AngularJS 1.x)

首先在控制器里处理高度计算、分页拆分和窗口 resize 适配:

app.controller('EpgController', function($scope, $window, $timeout) {
    // 假设你的epgDates已经是接口返回的数据源
    $scope.epgDates = [...];
    $scope.currentPage = 1;
    $scope.paginatedItems = [];

    // 获取可用视口高度(记得减去页面固定栏的高度,比如顶部导航、底部状态栏)
    const getUsableViewportHeight = () => {
        return $window.innerHeight - 120; // 这里的120是示例值,根据你的页面调整
    };

    // 计算单个外层项(包含日期标题+内层所有节目)的总高度
    const getItemTotalHeight = (itemEl) => {
        return itemEl.offsetHeight;
    };

    // 核心:根据视口高度拆分epgDates为分页数组
    const splitIntoPages = () => {
        $scope.paginatedItems = [];
        let currentPageGroup = [];
        let currentPageTotalHeight = 0;
        const viewportHeight = getUsableViewportHeight();

        // 必须等DOM渲染完成才能拿到正确的元素高度,所以用$timeout延迟执行
        $timeout(() => {
            const outerItems = document.querySelectorAll('.outer-ng-repeat');
            
            for (let i = 0; i < outerItems.length; i++) {
                const itemHeight = getItemTotalHeight(outerItems[i]);
                
                // 如果当前页加上这个项就超过视口高度,就把当前页存起来,开新页
                if (currentPageTotalHeight + itemHeight > viewportHeight && currentPageGroup.length > 0) {
                    $scope.paginatedItems.push([...currentPageGroup]);
                    currentPageGroup = [];
                    currentPageTotalHeight = 0;
                }
                
                currentPageGroup.push($scope.epgDates[i]);
                currentPageTotalHeight += itemHeight;
            }
            
            // 把最后一组未完成的页加进去
            if (currentPageGroup.length > 0) {
                $scope.paginatedItems.push(currentPageGroup);
            }
            
            // 防止切换窗口后页码超出范围
            if ($scope.currentPage > $scope.paginatedItems.length) {
                $scope.currentPage = 1;
            }
        }, 0);
    };

    // 初始化分页,同时监听窗口大小变化重新计算
    $scope.initPagination = () => {
        splitIntoPages();
        angular.element($window).on('resize', () => {
            $scope.$apply(() => {
                splitIntoPages();
            });
        });
    };

    // 页码切换方法
    $scope.switchPage = (pageNum) => {
        if (pageNum >= 1 && pageNum <= $scope.paginatedItems.length) {
            $scope.currentPage = pageNum;
        }
    };

    // 页面加载完成后触发初始化
    $timeout(() => {
        $scope.initPagination();
    }, 0);
});

2. 修改HTML模板,适配分页数据

把原来的直接遍历epgDates改成遍历当前页的分组数据,同时加上分页控制按钮:

<!-- 分页控制区 -->
<div class="epg-pagination">
    <button ng-disabled="currentPage === 1" ng-click="switchPage(currentPage - 1)">← 上一页</button>
    <span>第 {{currentPage}} 页 / 共 {{paginatedItems.length}} 页</span>
    <button ng-disabled="currentPage === paginatedItems.length" ng-click="switchPage(currentPage + 1)">下一页 →</button>
</div>

<!-- 渲染当前页的嵌套内容 -->
<ul>
    <li class="outer-ng-repeat" ng-repeat="epgDate in paginatedItems[currentPage - 1]">
        <h3>{{epgDate.dateText}}</h3> <!-- 这里替换成你的日期显示字段 -->
        <div class="inner-container">
            <div class="nested-ng-repeat" ng-repeat="epg in epgDate.epg">
                <div class="telecast__name">{{epg.programName}}</div> <!-- 替换成你的节目名称字段 -->
            </div>
        </div>
    </li>
</ul>

3. 关键注意点

  • DOM渲染时机:一定要用$timeout包裹高度计算逻辑,不然DOM还没渲染出来,拿不到正确的元素高度,分页就会出错。
  • 视口高度校准:getUsableViewportHeight里减去的数值,一定要对应你页面上固定元素的高度(比如顶部导航栏占了80px,底部工具栏占了40px,就减120),不然内容会被遮挡或者留白太多。
  • 窗口resize适配:监听窗口大小变化重新计算分页,保证在用户调整窗口尺寸时,分页能自动适配。

4. 备选方案:虚拟滚动

如果分页不是必须的,也可以考虑用虚拟滚动来优化性能——只渲染当前视口内的内容,不用一次性把所有数据都渲染出来。不过虚拟滚动的逻辑会比分页复杂一些,如果不想引入第三方库,自己实现的话需要监听滚动事件,计算元素的位置,动态控制元素的显示/隐藏。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:27:48