Skip to content
全部文档

懒加载

Livewire 允许你懒加载那些会拖慢首屏加载的组件。

Lazy 与 Defer

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()
    {
        // Slow database query...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }
};
?>

<div>
    Revenue this month: {{ $amount }}
</div>

若不使用懒加载,该组件会拖慢整页加载,让整个应用感觉很慢。

要启用懒加载,可以向组件传入 lazy 参数:

blade
<livewire:revenue lazy />

现在,Livewire 不会立即加载该组件,而是跳过它,先加载不含该组件的页面。随后,当组件进入视口可见时,Livewire 会发起网络请求,把该组件完整加载到页面上。

INFO

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

与 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()
    {
        // Slow database query...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }
};
?>

@placeholder
    <div>
        <!-- Loading spinner... -->
        <svg>...</svg>
    </div>
@endplaceholder

<div>
    Revenue this month: {{ $amount }}
</div>

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

TIP

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

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

WARNING

占位内容与组件必须使用相同的元素类型

例如,若占位内容的根元素类型是 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()
    {
        // Slow database query...
        $this->amount = Transaction::monthToDate()->sum('amount');
    }

    public function placeholder()
    {
        return <<<'HTML'
        <div>
            <!-- Loading spinner... -->
            <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
{
    // ...
}

TIP

旧版 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)
    {
        // Expensive database query...
        $this->amount = Transactions::between($start, $end)->sum('amount');
    }
};
?>

@placeholder
    <div>
        <!-- Loading spinner... -->
        <svg>...</svg>
    </div>
@endplaceholder

<div>
    Revenue this month: {{ $amount }}
</div>

不过,与普通组件加载不同,lazy 组件必须把传入的属性序列化(或「脱水」),并临时存放在客户端,直到组件完全加载。

例如,你可能想这样把一个 Eloquent 模型传给 revenue 组件:

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
{{-- Disable lazy loading --}}
<livewire:revenue :lazy="false" />

{{-- Disable deferred loading --}}
<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 连接数

不宜使用捆绑的情况:

  • 各组件加载时间差异很大(慢组件会阻塞快组件)
  • 希望组件各自就绪后尽快出现
  • 页面上只有少数几个懒加载组件

TIP

旧版 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)。

在测试中禁用懒加载

对懒加载组件或含嵌套懒加载组件的页面做单元测试时,你可能希望禁用「lazy」行为,以便断言最终渲染结果。否则,测试中这些组件会渲染为占位内容。

你可以用 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() // [tl! highlight]
            ->test(Dashboard::class)
            ->assertSee(...);
    }
}

现在,该测试渲染 dashboard 组件时会跳过 placeholder(),直接渲染完整组件,就像根本未应用懒加载一样。

另见