Skip to content

懒加载

Livewire 允许你懒加载那些否则会减慢初始页面加载速度的组件。

懒加载 vs 延迟加载

Livewire 提供了两种延迟组件加载的方式:

  • 懒加载 (lazy):组件在进入视口时加载(当用户滚动到它们时)
  • 延迟加载 (defer):组件在初始页面加载完成后立即加载

两种方法都可以防止慢组件阻塞你的初始页面渲染,但在组件实际加载的时机上有所不同。

基本示例

例如,假设你有一个 revenue 组件,它在 mount() 中包含一个慢速数据库查询:

php
<?php // resources/views/components/⚡revenue.blade.php

use Livewire\Component;
use App\Models\Transaction;

new class extends Component {
    public $amount;

    public function mount()
    {
        // 慢速数据库查询...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }
};
?>

<div>
    本月收入: {{ $amount }}
</div>

没有懒加载,这个组件会延迟整个页面的加载,使你的整个应用程序感觉很慢。

要启用懒加载,你可以将 lazy 参数传递给组件:

blade
<livewire:revenue lazy />

现在,Livewire 不会立即加载组件,而是跳过这个组件,加载没有它的页面。然后,当组件在视口中可见时,Livewire 将发出网络请求以在页面上完全加载这个组件。

懒加载和延迟请求默认是隔离的

与 Livewire 中的其他网络请求不同,懒加载和延迟组件更新在发送到服务器时是相互隔离的。这通过并行加载每个组件来保持快速加载。阅读更多关于捆绑组件 →

渲染占位符 HTML

默认情况下,Livewire 会在组件完全加载之前为你的组件插入一个空的 <div></div>。由于组件最初对用户不可见,当组件突然出现在页面上时可能会令人不适。

为了向用户表明组件正在加载,你可以渲染占位符 HTML,如加载旋转器和骨架占位符。

使用 @placeholder 指令

对于单文件和多文件组件,你可以直接在视图中使用 @placeholder 指令来指定占位符内容:

php
<?php // resources/views/components/⚡revenue.blade.php

use Livewire\Component;
use App\Models\Transaction;

new class extends Component {
    public $amount;

    public function mount()
    {
        // 慢速数据库查询...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }
};
?>

@placeholder
    <div>
        <!-- 加载旋转器... -->
        <svg>...</svg>
    </div>
@endplaceholder

<div>
    本月收入: {{ $amount }}
</div>

@placeholder@endplaceholder 之间的内容将在组件加载时显示,然后在加载完成后被实际组件内容替换。

占位符指令仅适用于基于视图的组件

@placeholder 指令仅适用于基于视图的组件(单文件和多文件组件)。对于基于类的组件,请改用 placeholder() 方法。

占位符和组件必须共享相同的元素类型

例如,如果你的占位符的根元素类型是 'div',你的组件也必须使用 'div' 元素。

使用 placeholder() 方法

对于基于类的组件,或者如果你更喜欢程序化控制,你可以定义一个返回 HTML 的 placeholder() 方法:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Transaction;

class Revenue extends Component
{
    public $amount;

    public function mount()
    {
        // 慢速数据库查询...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }

    public function placeholder()
    {
        return <<<'HTML'
        <div>
            <!-- 加载旋转器... -->
            <svg>...</svg>
        </div>
        HTML;
    }

    public function render()
    {
        return view('livewire.revenue');
    }
}

对于更复杂的加载器(如骨架),你可以从 placeholder() 方法返回一个 view

php
public function placeholder(array $params = [])
{
    return view('livewire.placeholders.skeleton', $params);
}

任何从懒加载组件传入的参数都将作为 $params 参数传递给 placeholder() 方法。

页面加载后立即加载

默认情况下,懒加载组件在进入浏览器视口之前不会完全加载,例如当用户滚动到一个组件时。

如果你想在页面加载后立即加载组件,而不等待它们进入视口,你可以使用 defer 参数:

blade
<livewire:revenue defer />

现在这个组件将在页面准备好后立即加载,而不需要等待它在视口中可见。

你也可以使用 #[Defer] 属性使组件默认延迟加载:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Defer;

#[Defer]
class Revenue extends Component
{
    // ...
}

旧版 on-load 语法

你也可以使用 lazy="on-load",它的行为与 defer 相同。建议新代码使用 defer 参数。

传入 props

一般来说,你可以像对待普通组件一样对待 lazy 组件,因为你仍然可以从外部向它们传递数据。

例如,这是一个你可能从父组件向 Revenue 组件传递时间间隔的场景:

blade
<input type="date" wire:model="start">
<input type="date" wire:model="end">

<livewire:revenue lazy :$start :$end />

你可以像在任何其他组件中一样在 mount() 中接收这些数据:

php
<?php // resources/views/components/⚡revenue.blade.php

use Livewire\Component;
use App\Models\Transaction;

new class extends Component {
    public $amount;

    public function mount($start, $end)
    {
        // 昂贵的数据库查询...
        $this->amount = Transactions::between($start, $end)->sum('amount');
    }
};
?>

@placeholder
    <div>
        <!-- 加载旋转器... -->
        <svg>...</svg>
    </div>
@endplaceholder

<div>
    本月收入: {{ $amount }}
</div>

然而,与普通组件加载不同,lazy 组件必须序列化或"脱水"任何传入的属性,并将它们临时存储在客户端,直到组件完全加载。

例如,你可能想像这样向 revenue 组件传入一个 Eloquent 模型:

blade
<livewire:revenue lazy :$user />

在普通组件中,实际的 PHP 内存中 $user 模型将被传递到 revenuemount() 方法中。然而,因为我们不会在下一个网络请求之前运行 mount(),Livewire 将在内部将 $user 序列化为 JSON,然后在处理下一个请求之前从数据库重新查询它。

通常,这种序列化不应该在你的应用程序中导致任何行为差异。

默认强制懒加载或延迟加载

如果你想强制组件的所有用法都是懒加载或延迟加载的,你可以在组件类上方添加 #[Lazy]#[Defer] 属性:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Lazy;

#[Lazy]
class Revenue extends Component
{
    // ...
}

或者对于延迟加载:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Defer;

#[Defer]
class Revenue extends Component
{
    // ...
}

你可以在渲染组件时覆盖这些默认值:

blade
{{-- 禁用懒加载 --}}
<livewire:revenue :lazy="false" />

{{-- 禁用延迟加载 --}}
<livewire:revenue :defer="false" />

捆绑多个懒加载组件

默认情况下,如果页面上有多个懒加载组件,每个组件将并行发出独立的网络请求。这通常对性能是有利的,因为每个组件独立加载。

然而,如果页面上有很多懒加载组件,你可能想将它们捆绑到单个网络请求中以减少服务器开销。

使用 bundle 参数

你可以使用 bundle: true 参数启用捆绑:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Lazy;

#[Lazy(bundle: true)]
class Revenue extends Component
{
    // ...
}

现在,如果同一页面上有十个 Revenue 组件,当页面加载时,所有十个更新将被捆绑并作为单个网络请求发送到服务器。

使用 bundle 修饰符

你也可以在渲染组件时使用 bundle 修饰符内联启用捆绑:

blade
<livewire:revenue lazy.bundle />

这也适用于延迟组件:

blade
<livewire:revenue defer.bundle />

或者使用属性:

php
<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Defer;

#[Defer(bundle: true)]
class Revenue extends Component
{
    // ...
}

何时使用捆绑

使用捆绑当:

  • 单个页面上有很多(5+)懒加载或延迟组件
  • 组件在复杂性和加载时间上相似
  • 你想减少服务器开销和 HTTP 连接数

不使用捆绑当:

  • 组件的加载时间差异很大(慢组件会阻塞快组件)
  • 你希望组件在各自准备好后立即出现
  • 页面上只有少量懒加载组件

旧版 isolate 语法

你也可以使用 isolate: false,它的行为与 bundle: true 相同。建议新代码使用 bundle 参数,因为它更明确地表达了意图。

全页面懒加载

你可以使用路由方法懒加载或延迟全页面 Livewire 组件。

懒加载全页面

使用 ->lazy() 在组件进入视口时加载:

php
Route::livewire('/dashboard', 'pages::dashboard')->lazy();

延迟全页面

使用 ->defer() 在页面加载后立即加载组件:

php
Route::livewire('/dashboard', 'pages::dashboard')->defer();

禁用懒加载/延迟加载

如果组件默认是懒加载或延迟加载的(通过 #[Lazy]#[Defer] 属性),你可以使用 enabled: false 退出:

php
Route::livewire('/dashboard', 'pages::dashboard')->lazy(enabled: false);
Route::livewire('/dashboard', 'pages::dashboard')->defer(enabled: false);

默认占位符视图

如果你想为所有组件设置默认占位符视图,你可以在 /config/livewire.php 配置文件中引用该视图:

php
'component_placeholder' => 'livewire.placeholder',

现在,当组件被懒加载且没有定义 placeholder() 时,Livewire 将使用配置的 Blade 视图(在这种情况下是 livewire.placeholder)。

为测试禁用懒加载

当对懒加载组件或包含嵌套懒加载组件的页面进行单元测试时,你可能想禁用"懒加载"行为,以便断言最终渲染的行为。否则,这些组件在测试期间将被渲染为它们的占位符。

你可以使用 Livewire::withoutLazyLoading() 测试助手轻松禁用懒加载:

php
<?php

namespace Tests\Feature\Livewire;

use App\Livewire\Dashboard;
use Livewire\Livewire;
use Tests\TestCase;

class DashboardTest extends TestCase
{
    public function test_renders_successfully()
    {
        Livewire::withoutLazyLoading()
            ->test(Dashboard::class)
            ->assertSee(...);
    }
}

现在,当为此测试渲染仪表板组件时,它将跳过渲染 placeholder() 并渲染完整的组件,就好像根本没有应用懒加载一样。

另请参阅