编程

Livewire v3 新特性和更新

1226 2022-11-23 12:00:44

上周三在 Laracon 线上大会, Caleb Porzio 进行了一个名为"Livewire 的未来"的演讲,展示了 Livewire v3 计划带来的新特性。本文将和大家一起探讨这些特性。

基于 Alpine 的全新内核

Livewire 对整个内核都进行了重写。新内核对 Alpine 依赖更多,使用 Morph、History 及其他其驱动的插件,这意味着 Livewire 有了更好的 diffing、特性,可以编译得更快,Livewire 和 Alpine 之间的重复也会更少。

同时也带来了一些新的特性。

Livewire scripts、 styles 和 Alpine 自动注入 

使用 Composer 安装 Livewire v2 后,你需要手动添加 @livewireStyles, @livewireScripts 及 Alpine 到你的布局中。而对于 Livewire v3,你只需安装 Livewire,其他步骤会被自动注入,包括 Alpine!

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="//unpkg.com/alpinejs" defer></script> 
    @livewireStyles
    @livewireScripts
</head>
<body>
    ...
</body>
</html>

热加载无需编译

Livewire v3 会包含无需 bulid 热加载的功能。只需在编辑器中保存文件,可以在不用破坏组件状态的情况下,马上在浏览器中看到对应的变化!

wire:transition

Alpine 有 transition 有了一段时间了, Livewire v3 将有一个叫 wier:transition 的组建,对 x-transition 进行包装使用。可以将 wire:transition 添加到任何要展示或者隐藏的元素中。由于 wire:transition 底层使用的是 x-transition,因此也支持像 .opacity 和 .duration 这样的修饰符。

在 PHP 类中写 JavaScript 函数

Livewire v3 支持直接在后端 Livewire 组件中直接写 JavaScript 函数。要添加 js 函数到组件,要在函数上面加上 /** @js */ 注释,然后使用 PHP HEREDOC 语法返回 JavaScript 代码,并在前端调用。JavaScrpt 代码无需发送任何请求到后端即可执行。

<?php
 
namespace App\Http\Livewire;
 
class Todos extends \Livewire\Component
{
    /** @prop */
    public $todos;
 
    /** @js  */
    public function clear()
    {
        return <<<'JS'
            this.todo = '';
        JS;
    }
}

 

<div>
    <input wire:model="todo" />
 
    <button wire:click="clear">Clear</button> 
</div>

/** @locked */ 属性

Livewire v3 将支持锁定(loced)属性 - 即不能从前端更新的属性。在组件的属性上方添加 /** @locked / 注释,如果有人尝试通过前端更新属性,Livewire 会抛出异常。

<?php
 
namespace App\Http\Livewire;
 
class Todos extends \Livewire\Component
{
    /** @locked  */
    public $todos = [];
}

wire:model 默认延迟加载

Livewire 第一版发行时,主要目的在于以真正实时的感觉编写像搜索那样的组件,因此每次输入改变的时候自动发送更新到服务器就显得合理。而现在,我们用 Livewire 构建各种各样的应用。随着 Livewire 及其用法的改进,我们意识到对于 95% 的表单而言 ”deferred" 延迟加载行为是合理的,因此在 V3 中 deferred 功能变成了默认。这能够减少发送到服务器的非必要请求并改善性能。

如果输入框需要“实时(live)”功能,你可以使用 wire:model.live 启用该功能。

注意:这是 v2 升级到 v3 的破坏性改变。

批量请求

在 Livewire v2 中,如果你有多个组件使用 wire:poll 或发送\监听事件,这些组件每个都会单独发送请求到服务器。在 Livewire v3 中,有智能的批量请求,因此wire:poll、事件、监听或者方法调用时,如果有需要可以并入一个请求,减少请求发送量改善性能。

查询属性

在Livewire v2中使用嵌入组件时,如果父组件的属性更新了,子组件的数据不会自动同步。虽然可以使用事件监听手动解决,不过不是很理想。对于 v3,如果需要发送数据给子组件,在子组件属性上面添加  /** @prop */ 注释,然后在父组件中更新,子组件就会自动更新。

<?php
 
namespace App\Http\Livewire;
 
class TodosCount extends \Livewire\Component
{
    /** @prop */
    public $todos;
 
    public function render()
    {
        return <<<'HTML'
            <div>
                Todos: {{ count($todos) }}
            </div>
        HTML;
    }
}

/** @modelable */ 属性

Livewire v2 的另一个痛点是,从父组件"modelling" 属性到子组件。比如说你需要一个<livewire:todo-input /> 组件。要传入一个值并使其值在子组件中改变时,在父组件中自动更新,是不容易的事。在 V3 中,你可以在使用该组件使添加 wire:model,然后在该组件内部,添加一个 /** @modelable */ 注释到你储存相应数据的属性上面,剩下的就交给 Livewire 处理。

<?php
 
namespace App\Http\Livewire;
 
class Todos extends \Livewire\Component
{
    public $todo = '';
 
    public $todos = [];
 
    public function add() ...
 
    public function render()
    {
        return <<<'HTML'
            <div>
                <livewire:todo-input wire:model="todo" /> 
                <ul>
                    @foreach ($todo as $todos)
                        <li>{{ $todo }}</li>
                    @endforeach
                </ul>
            </div>
        HTML;
    }
}
<?php
 
namespace App\Http\Livewire;
 
class TodoInput extends \Livewire\Component
{
    /** @modelable  */
    public $value = '';
 
    public function render()
    {
        return <<<'HTML'
            <div>
                <input wire:model="value">
            </div>
        HTML;
    }
}

使用 $parent 访问父组件的数据和方法

Livewire v3 中将会有一个访问父组件数据和方法的新方式。可以使用 $parent 属性访问调用父组件的方法。

<?php
 
namespace App\Http\Livewire;
 
class TodoInput extends \Livewire\Component
{
    /** @modelable  */
    public $value = '';
 
    public function render()
    {
        return <<<'HTML'
            <div>
                <input
                    wire:model="value"
                    wire:keydown.enter="$parent.add()"
                >
            </div>
        HTML;
    }
}

@teleport

Livewire v3 也引入了新的 @teleport 模板指令,让你可以传送一小段代码,并在其他DOM 组件中渲染。这个功能有时可以在使用modal模态框及sildeout滑块中避免z-index问题。

<div>
    <button wire:click="showModal">Show modal</button>
 
    @teleport('#footer')
        <x-modal wire:model="showModal">
            <!-- ... -->
        </x-modal>
    @endteleport
</div>

惰性组件

Livewire v3 将引入惰性组件。有些组件可能因为耗时的查询或者在不总是打开的slideout滑块中渲染而需要花费一些时间,你可能需要一直等到它渲染完。在 Livewire v3 中,只需在渲染的组件中添加一个 lazy 属性,它就不会一开始就被渲染。当它进入视窗后,Livewire 会发送请求去渲染。你也可以在组件中实现 placeholder 方法添加一些占位内容。

<div>
    <button wire:click="showModal">Show modal</button>
 
    @teleport('#footer')
        <x-modal wire:model="showModal">
            <livewire:example-component lazy /> 
        </x-modal>
    @endteleport
</div>
<?php
 
namespace App\Http\Livewire;
 
class ExampleComponent extends \Livewire\Component
{
    public static function placeholder()
    {
        return <<<'HTML'
            <x-spinner />
        >>>
    }
 
    public function render() /** [tl! collapse:7] */
    {
        return <<<'HTML'
            <div>
                Todos: {{ count($todos) }}
            </div>
        HTML;
    }
}

wire:navigate

在 Livewire v3,你可以将 wire:navigate 添加到任何的<a>标签中,当点击时,Livewire 会在后台获取该页面,然后迅速将 DOM 交给你的应用,像SPA单页应用一样。 如果你也添加了 .prefetch 修饰符,Livewire 会预先获取链接内容,使之更快。

<a href="/example" wire:navigate.prefetch>Example Page</a>

@persist

V3 引入的另外一个很酷的模板指令是 @persist。与wire:navigation 一起联合使用 @persist,能让你应用的一部分在页面改变时保持不变。比如podcast播放器可以在你页面切换的时候继续保持播放。

<!DOCTYPE html>
<html lang="en">
<body>
    <x-podcast-header />
 
    <x-podcast-body>
        {{ $slot }}
    </x-podcast-body>
 
    @persist('player')
        <x-podcast-player />
    @endpersist
</body>
</html>

新的 laravel-livewire.com 网站设计

Livewire 网站和文档也进行了全新的设计!