https://ux.symfony.com/foo
那么... 它如何工作呢?
让我们关注两个方面。但首先,你滚动
到最后了吗?
您可能错过了一些关于性能的重要细节... 🍿
Morphin' 技巧
这个技巧与 1/2 部分
的 "无限滚动" LiveComponent 演示中使用的技巧非常相似。
之前的结果
🐯 对于上一页的结果,我们添加一个与上一页最后一个项目对应的伪造项目,具有相同的 id
。这允许在现有元素之后添加新元素。
1<div class="ProductGrid" {{ attributes.defaults(stimulus_controller('appear')) }}>
2
3 <div id="results" style="display: flex; gap: 1rem; flex-direction: column;" class="p-4">
4 <div class="ProductGrid_items">
5
6 {# 🐯- Last result from previous page #}
7 {% if page > 1 %}
8 <article id="item--{{ page - 1 }}-{{ per_page }}"></article>
9 {% endif %}
当前页面的结果
🦊 对于当前页面的结果,我们同时使用 id
和 data-live-ignore
。这允许保留 DOM 中之前的元素。
11 {# 🦊 - Current page #}
12 {% for item in this.items %}
13 <article
14 id="item--{{ page }}-{{ loop.index }}"
15 class="ProductGrid_item"
16 data-live-ignore
17 style="--i: {{ item.id }};"
18 >
19 <div class="ProductGrid_media">
下一页
🐼 最后,对于下一页的结果,我们添加带有 id
的占位符。
这与 "上一页" 技巧相结合,强制执行下一个元素的插入顺序
... 中间没有 div!
31 {# 🐼 - Next page #}
32 {% for i in 1..per_page %}
33 <article id="item--{{ page + 1 }}-{{ i }}"
34 class="ProductGrid_item"
35 style="--i: {{ (page * per_page) + i - 1 }};"
Intersection Observer
我们希望在用户滚动到页面底部时自动加载下一个结果。
我们创建一个小的 Stimulus 控制器,利用 IntersectionObserver
API 在其目标元素在视口中变为可见时触发自定义的 appear
事件。
通过创建一个专用的控制器,我们可以使逻辑与产品网格分离。并且我们可以在其他组件中重用它!
import { Controller } from '@hotwired/stimulus';
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['loader'];
loaderTargetConnected(element) {
this.observer ??= new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.dispatchEvent(new CustomEvent('appear', {detail: {entry}}));
}
});
});
this.observer?.observe(element);
}
loaderTargetDisconnected(element) {
this.observer?.unobserve(element);
}
}
LiveComponent + Stimulus
现在我们将 appear
控制器添加到我们的 ProductGrid
组件中,这要归功于 stimulus_controller
方法。
1<div class="ProductGrid" {{ attributes.defaults(stimulus_controller('appear')) }}>
2
3 <div id="results" style="display: flex; gap: 1rem; flex-direction: column;" class="p-4">
事件 -> LiveAction
最后,我们将 loader
目标添加到我们为下一页添加的第一个 "item" 占位符中。
🦁 当 appear
事件被触发时,我们配置该事件调用 live controller
的 more
action。
这样做,我们可以在下一页的第一个项目可见时加载下一页。
无需 "加载更多" 按钮!
32 {% for i in 1..per_page %}
33 <article id="item--{{ page + 1 }}-{{ i }}"
34 class="ProductGrid_item"
35 style="--i: {{ (page * per_page) + i - 1 }};"
36
37 {# 🦁 - The trigger #}
38 {% if loop.first %}
39 data-appear-target="loader"
40 data-action="appear->live#action"
41 data-live-action-param="debounce(750)|more"
42 {% endif %}
43
44 >
45 <div class="ProductGrid_media">
作者 smnandre
发布于 2024-06-07