有不同的“无限滚动”或所谓的“feed”方法。用户需求和可接受响应负载大小将决定您选择哪种方法。
在性能与易用性之间似乎需要做出妥协。
1. 添加资源
这种方法是传统的向底部追加方法,当用户到达当前滚动高度的底部时,将会发起另一个API调用来“继续堆积”内容。它具有处理跨设备陷阱的最有效解决方案的优点。
正如您提到的那样,这种解决方案的缺点来自于大量的负载在用户粗心地滚动内容时涌入内存。这里没有节流机制。
<div infinite-scroll='getMore()' infinite-scroll-distance='0'>
<ul>
<li ng-repeate="item in items">
{{item}}
</li>
</ul>
</div>
var page = 1;
$scope.getMore() = function(){
$scope.items.push(API.returnData(i));
page++;
}
2. 使用节流方式追加资源
在这里,我们建议用户可以继续在无限追加的动态流中显示更多结果,但是他们必须进行节流或“手动”调用更多数据的请求。相对于用户将要滚动浏览的内容大小,这变得繁琐。
如果每个有效负载返回了大量内容,则用户将不得不较少点击“获取更多”按钮。当然,这是以返回更大有效负载为代价的。
<div>
<ul>
<li ng-repeate="item in items">
{{item}}
</li>
</ul>
</div>
<div ng-click='getMore()'>
Get More!
</div>
var page = 1;
$scope.getMore() = function(){
$scope.items.push(API.returnData(i));
page++;
}
3. 虚拟滚动
这是一种最后也是最有趣的无限滚动方式。其思想是仅在浏览器内存中存储一定范围内的渲染结果版本。也就是说,复杂的DOM操作仅作用于您配置中指定的当前范围。然而,这种方法也有自己的缺陷。
最大的问题是跨设备兼容性。
如果您的手持设备具有达到设备宽度的虚拟滚动窗口 --- 它最好小于页面的总高度,因为您将永远无法滚动过此“feed”及其自己的滚动条。您会被“卡住”在页面中间,因为您的滚动将始终作用于虚拟滚动 feed 而不是包含 feed 的实际页面。
接下来是可靠性。如果用户手动从低索引拖动滚动条到极高索引,您将强制浏览器非常快地运行这些指令,在测试中,这导致我的浏览器崩溃。这可以通过隐藏滚动条来解决,但当然用户也可以通过非常快速地滚动来调用相同的情况。
这里是演示
来源
"出于SEO的原因,初始页面必须是静态的。重要的是框架能够从现有内容开始,最好不需要太多的修改。"
所以你的意思是在提供内容之前,希望页面在服务器端进行预渲染?这种方法在2000年代初期效果很好,但现在大多数人都在向单页应用程序风格转变。有很好的理由:
您发送给用户的初始种子作为引导来获取API数据,使您的服务器工作量大大减少。
延迟加载资源和异步网络服务调用使感知的加载时间比传统的“先在服务器上渲染所有内容,然后将其返回给用户”的方法快得多。
通过使用页面预渲染/缓存引擎来保留您的SEO,该引擎位于Web服务器的前面,仅对Web爬虫响应您的“完全渲染版本”。这个概念在这里很好地解释了。
我们希望在feed中已经加载lightbox所需的数据,以便过渡更快。一些数据已经存在(标题、描述、照片、喜欢数/书签数、评论数),但还有其他数据需要加载到详细视图中-评论、类似的帖子、谁喜欢这个等等。
如果您的初始负载不包含每个“feed id”的子数据点,并且需要使用其他API请求来加载它们到您的lightbox中-那么您正在做正确的事情。这是完全合法的用例。您将为单个API调用争论50-100ms,这对您的最终用户来说是无法感知的延迟。如果您绝对需要将附加负载与您的feed一起发送,则不会获得太多好处。
在feed或详细lightbox中发生的帖子更改应该很容易地反映在另一个中(例如,如果我从feed中喜欢它,如果我去lightbox,我应该看到那个喜欢和新的喜欢计数器数字-或相反)。
你在这里混合使用技术 --- "赞"按钮是对Facebook的API调用。是否将这些更改传播到同一页上其他Facebook“赞”按钮的实例取决于Facebook处理方式,我相信快速谷歌可以帮助你解决问题。
然而特定于您网站的数据 --- 有几种不同的用例:
- 假设我更改了lightbox中的标题,并且还希望更改传播到当前显示的Feed中。如果您的“保存编辑操作”POST到服务器,则成功回调可以触发使用websocket更新新值。此更改将传播到不仅是您的屏幕,而且其他人的屏幕。
- 您还可以谈论双向数据绑定(AngularJS非常擅长此项功能)。通过双向数据绑定,您从Web服务获取的“模型”或数据可以绑定到视图中的多个位置。这样,当您编辑页面的某一部分与共享同一模型时,其他部分将实时更新。这发生在任何HTTP请求之前,因此是完全不同的用例。
我们希望将我们的移动站点(目前使用Sencha Touch)迁移到同一代码库,以便于共享通用部分,从而使移动站点和主站点之间更加接近特性平衡。
您应该真正关注现代响应式CSS框架,例如Bootstrap和Foundation。使用响应式Web设计的重点在于您只需要构建一次网站即可适应所有不同的屏幕尺寸。
如果您谈论功能模块化,AngularJS是最好的选择。其想法是您可以将网站组件导出为可用于另一个项目的模块。这也可以包括视图。如果您使用响应式框架构建了视图,那么猜猜——您现在可以在任何地方使用它。
1)在通过模板渲染其他页面时,初始页面加载是否可能存在问题?
如上所述,最好摆脱这种方法。如果您绝对需要它,模板引擎并不关心您的有效负载是在服务器端还是客户端呈现的。链接到部分页面将同样可访问。
2) 对于页面的不同部分使用多个数据源是否有问题 - 例如,主要帖子部分来自嵌入式JSON数据和来自动态加载的“查看更多” ,而附加详细信息将来自不同的ajax调用。
再次强调,这正是该行业正在发展的方向。您将通过使用初始静态引导程序来获取所有外部API数据来节省“感知”和“实际”加载时间 --- 这也将使您的开发周期更快,因为您正在分离完全独立的关注点。您的API不应关心您的视图,您的视图也不应关心您的API。思路是当您将它们分解成较小的部分时,您的API和前端代码都可以变得模块化/可重用。
3) 虽然双向绑定很酷,但由于渲染的项目数量,我担心在我们的情况下可能会产生负面影响。我们需要进行双向绑定的元素数量相对较少。
我还将结合您在下面留下的评论来回答这个问题:
感谢您的回答!您能否澄清一下 - 看起来1)和2)只涉及如何实现无限滚动,而不是可能出现的性能问题。似乎3)以类似于最近版本的Sencha Touch的方式解决了这个问题,这可能是一个好的解决方案。
您将遇到的性能问题完全是主观的。我试图在讨论中概述性能考虑因素,例如节流,因为节流可以大大减少服务器承受的压力以及每个新结果集附加到DOM时用户浏览器所需执行的工作量。
无限滚动,经过一段时间后,将耗尽用户浏览器的内存。我可以告诉您的是,这是不可避免的,但只有通过测试,您才能知道具体情况。根据我的经验,我可以告诉您,用户的浏览器可以处理大量的滚动,但是,每个结果集的有效负载大小以及您在所有结果上运行的指令的大小是完全主观的。在我描述的第三个选项中,有一些解决方案仅呈现在范围数据集上,但也有其局限性。
API返回的数据大小不应超过1-2KB,并且查询返回时间应该只需要50-200毫秒。如果未达到这些速度,也许是时候重新评估查询或通过使用子ID查询其他端点来缩小结果集的大小了。请保留HTML标签。