DEMOS / Live Component

无限滚动 - 1/2

无限滚动允许用户在向下滚动页面时持续加载内容。此演示的 第一部分 展示了如何使用 LiveComponent新项目追加到页面。

ux.symfony.com
🐻
1.99
🐨
2.99
🐼
3.99
🦥
4.99
🦦
5.99
🦨
6.99
🦘
7.99
🐾
8.99
🐓
9.99
🐣
10.99

此组件非常标准:页面编号作为 LiveProp,用于加载下一页的 LiveAction,以及用于检索页面结果的 getItems 方法。

调用时,LiveAction 只需递增页码并再次渲染,显示下一页的结果。

但是...我们如何 保留 之前的结果而不是 替换 它们呢?

// ... use statements hidden - click to show
use App\Service\EmojiCollection; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; use Symfony\UX\LiveComponent\Attribute\LiveAction; use Symfony\UX\LiveComponent\Attribute\LiveProp; use Symfony\UX\LiveComponent\ComponentToolsTrait; use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent('ProductGrid')]
class ProductGrid
{
    use ComponentToolsTrait;
    use DefaultActionTrait;

    private const PER_PAGE = 10;

    #[LiveProp]
    public int $page = 1;

    public function __construct(private readonly EmojiCollection $emojis)
    {
    }

    #[LiveAction]
    public function more(): void
    {
        ++$this->page;
    }

    public function hasMore(): bool
    {
        return \count($this->emojis) > ($this->page * self::PER_PAGE);
    }

    public function getItems(): array
    {
        $emojis = $this->emojis->paginate($this->page, self::PER_PAGE);
        $colors = $this->getColors();

        $items = [];
        foreach ($emojis as $i => $emoji) {
            $items[] = [
                'id' => $id = ($this->page - 1) * self::PER_PAGE + $i,
                'emoji' => $emoji,
                'color' => $colors[$id % \count($colors)],
            ];
        }

        return $items;
    }

    public function getColors(): array
    {
        return [
            '#fbf8cc', '#fde4cf', '#ffcfd2',
            '#f1c0e8', '#cfbaf0', '#a3c4f3',
            '#90dbf4', '#8eecf5', '#98f5e1',
            '#b9fbc0', '#b9fbc0', '#ffc9c9',
            '#d7ffc9', '#c9fffb',
        ];
    }
}

解决方案涉及使用 data-live-ignore 属性,以及在 ProductGrid 组件中使用一些小技巧。

您只需要在 HTML 中模拟先前结果的存在。带有 data-live-ignore 属性和前一页 ID (在 🦊 下方) 的空 div 足以欺骗 LiveComponent,使其认为先前的结果仍然存在,并且无法修改。

然后,LiveComponent 将继续添加新结果,而不是替换结果!

<div class="ProductGrid" {{ attributes }}>

    <div id="results" style="display: flex; gap: 1rem; flex-direction: column;" class="p-4">

        {% if page > 1 %}
            {# 🦊 #}
            {# Adding a fake "previous page" div is enough to trick the system #}
            {# It must have the same ID than the original page #}
            <div class="ProductGrid_page" id="page--{{ page - 1 }}" data-live-ignore="true"></div>
        {% endif %}

        {# Current page #}
        <div class="ProductGrid_page" id="page--{{ page }}" data-live-ignore="true">
            {% for item in this.items %}
                <article class="ProductGrid_item" style="--color: {{ item.color }};">
                    <div class="ProductGrid_media">
                        <svg><use href="#svg-tshirt"/></svg>
                        <span>{{ item.emoji }}</span>
                    </div>
                    <data class="ProductGrid_price" value="{{ item.id }}" data-currency="$">
                        {{ item.id + 1 }}<small>.99</small>
                    </data>
                </article>
            {% endfor %}
        </div>

        <div style="display: grid; place-content: center;padding-block: 2rem;">
            {% if this.hasMore %}
                <button data-action="live#action" data-live-action-param="more" class="ProductGrid_more">
                    Load More
                </button>
            {% else %}
                <span class="code">The End</span>
            {% endif %}
        </div>

    </div>

</div>
作者 smnandre
发布时间 2024-06-07