主题
从 v3 升级到 v4
Livewire v4 引入了多项改进和优化,同时尽可能保持向后兼容性。本指南将帮助你从 Livewire v3 升级到 v4。
Livewire v4 目前处于 beta 阶段
Livewire v4 仍在积极开发中,尚未稳定。建议在升级生产应用程序之前在开发环境中进行充分测试。beta 版本之间可能会发生破坏性更改。
平滑的升级路径
大多数应用程序可以以最小的更改升级到 v4。破坏性更改主要是配置更新和方法签名更改,这些只影响高级用法。
安装
更新你的 composer.json 以要求 Livewire v4 beta:
bash
composer require livewire/livewire:^4.0@beta更新后,清除应用程序的缓存:
bash
php artisan config:clear
php artisan view:clear在 GitHub 上查看所有更改
要全面了解 v3 和 v4 之间的所有代码更改,你可以在 GitHub 上查看完整的差异:Compare 3.x to main →
高影响更改
这些更改最有可能影响你的应用程序,应仔细审查。
配置文件更新
多个配置键已被重命名、重组或具有新的默认值。更新你的 config/livewire.php 文件:
TIP
你可以查看在 Github 上完整的 v4 配置文件: livewire.php →
重命名的配置键
布局配置:
php
// Before (v3)
'layout' => 'components.layouts.app',
// After (v4)
'component_layout' => 'layouts::app',布局现在默认使用 layouts:: 命名空间,指向 resources/views/layouts/app.blade.php。
占位符配置:
php
// Before (v3)
'lazy_placeholder' => 'livewire.placeholder',
// After (v4)
'component_placeholder' => 'livewire.placeholder',更改的默认值
智能 wire:key 行为:
php
// Now defaults to true (was false in v3)
'smart_wire_keys' => true,这有助于防止在深层嵌套组件中出现 wire:key 问题。注意:你仍然需要在循环中手动添加 wire:key,这个设置不会消除这个要求。
新配置选项
组件位置:
php
'component_locations' => [
resource_path('views/components'),
resource_path('views/livewire'),
],定义 Livewire 查找单文件和多文件(基于视图)组件的位置。
组件命名空间:
php
'component_namespaces' => [
'layouts' => resource_path('views/layouts'),
'pages' => resource_path('views/pages'),
],创建自定义命名空间用于组织基于视图的组件(例如,<livewire:pages::dashboard /> )。
Make 命令默认值:
php
'make_command' => [
'type' => 'sfc', // Options: 'sfc', 'mfc', or 'class'
'emoji' => true, // Whether to use ⚡ emoji prefix
],配置默认组件格式和 emoji 使用。将 type 设置为 'class' 以匹配 v3 行为。
CSP 安全模式:
php
'csp_safe' => false,启用内容安全策略模式以避免 unsafe-eval 违规。启用时,Livewire 使用 Alpine CSP 构建。注意:此模式限制指令中的复杂 JavaScript 表达式(如 wire:click="addToCart($event.detail.productId)" )或全局引用(如 window.location)。
路由更改
对于全页面组件,推荐的路由方法已更改:
php
// Before (v3) - still works but not recommended
Route::get('/dashboard', Dashboard::class);
// After (v4) - recommended for all component types
Route::livewire('/dashboard', Dashboard::class);
// For view-based components, you can use the component name
Route::livewire('/dashboard', 'pages::dashboard');使用 Route::livewire() 现在是首选方法,并且是单文件和多文件组件作为全页面组件正确工作所必需的。
中等影响更改
这些更改可能会影响你应用程序的某些部分,具体取决于你使用的功能。
性能改进
Livewire v4 包含对请求处理系统的重大性能改进:
- 非阻塞轮询:
wire:poll不再阻塞其他请求或被其他请求阻塞 - 并行实时更新:
wire:model.live请求现在并行运行,允许更快的输入和更快的结果
这些改进自动发生——你的代码不需要任何更改。
方法签名更改
如果你正在扩展 Livewire 的核心功能或直接使用这些方法,请注意这些签名更改:
流式传输:
stream() 方法参数顺序已更改:
php
// Before (v3)
$this->stream(to: '#container', content: 'Hello', replace: true);
// After (v4)
$this->stream(content: 'Hello', replace: true, el: '#container');如果你使用命名参数(如上所示),请注意 to: 已被重命名为 el:。如果你使用位置参数,你需要更新为以下内容:
php
// Before (v3) - positional parameters
$this->stream('#container', 'Hello');
// After (v4) - positional/named parameters
$this->stream('Hello', el: '#container');组件挂载(内部):
如果你正在扩展 LivewireManager 或直接调用 mount() 方法:
php
// Before (v3)
public function mount($name, $params = [], $key = null)
// After (v4)
public function mount($name, $params = [], $key = null, $slots = [])此更改添加了在挂载组件时传递插槽的支持,通常不会影响大多数应用程序。
低影响更改
这些更改只影响使用高级功能或自定义的应用程序。
JavaScript 弃用
弃用: $wire.$js() 方法
用于定义 JavaScript 操作的 $wire.$js() 方法已被弃用:
js
// Deprecated (v3)
$wire.$js('bookmark', () => {
// Toggle bookmark...
})
// New (v4)
$wire.$js.bookmark = () => {
// Toggle bookmark...
}新语法更简洁、更直观。
弃用: 没有前缀的 $js
在脚本中使用没有 $wire.$js 或 this.$js 前缀的 $js 已被弃用:
js
// Deprecated (v3)
$js('bookmark', () => {
// Toggle bookmark...
})
// New (v4)
$wire.$js.bookmark = () => {
// Toggle bookmark...
}
// Or
this.$js.bookmark = () => {
// Toggle bookmark...
}旧语法仍然有效
$wire.$js('bookmark', ...) 和 $js('bookmark', ...) 都将在 v4 中继续工作以保持向后兼容性,但你应该在方便时迁移到新语法。
弃用: commit 和 request 钩子
commit 和 request 钩子已被弃用,以支持提供更细粒度控制和更好性能的新拦截器系统。
旧钩子仍然有效
弃用的钩子将在 v4 中继续工作以保持向后兼容性,但你应该在方便时迁移到新系统。
从 commit 钩子迁移
旧的 commit 钩子:
js
// OLD - Deprecated
Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
respond(() => {
// Runs after response received but before processing
})
succeed(({ snapshot, effects }) => {
// Runs after successful response
})
fail(() => {
// Runs if request failed
})
})应该替换为新的 interceptMessage:
js
// NEW - Recommended
Livewire.interceptMessage(({ component, message, onFinish, onSuccess, onError, onFailure }) => {
onFinish(() => {
// Equivalent to respond()
})
onSuccess(({ payload }) => {
// Equivalent to succeed()
// Access snapshot via payload.snapshot
// Access effects via payload.effects
})
onError(() => {
// Equivalent to fail() for server errors
})
onFailure(() => {
// Equivalent to fail() for network errors
})
})从 request 钩子迁移
旧的 request 钩子:
js
// OLD - Deprecated
Livewire.hook('request', ({ url, options, payload, respond, succeed, fail }) => {
respond(({ status, response }) => {
// Runs when response received
})
succeed(({ status, json }) => {
// Runs on successful response
})
fail(({ status, content, preventDefault }) => {
// Runs on failed response
})
})应该替换为新的 interceptRequest:
js
// NEW - Recommended
Livewire.interceptRequest(({ request, onResponse, onSuccess, onError, onFailure }) => {
// Access url via request.uri
// Access options via request.options
// Access payload via request.payload
onResponse(({ response }) => {
// Equivalent to respond()
// Access status via response.status
})
onSuccess(({ response, responseJson }) => {
// Equivalent to succeed()
// Access status via response.status
// Access json via responseJson
})
onError(({ response, responseBody, preventDefault }) => {
// Equivalent to fail() for server errors
// Access status via response.status
// Access content via responseBody
})
onFailure(({ error }) => {
// Equivalent to fail() for network errors
})
})关键差异
- 更细粒度的错误处理:新系统将网络失败 (
onFailure) 与服务器错误 (onError) 分开 - 更好的生命周期钩子:消息拦截器提供额外的钩子,如
onSync、onMorph和onRender - 取消支持:消息和请求都可以被取消/中止
- 组件作用域:消息拦截器可以使用
$wire.intercept(...)限定为特定组件
有关新拦截器系统的完整文档,请参阅 JavaScript 拦截器文档。
v4 中的新功能
Livewire v4 引入了几个强大的新功能,你可以立即开始使用:
组件功能
单文件和多文件组件
v4 在传统的基于类的方法之外引入了新的组件格式。单文件组件将 PHP 和 Blade 合并在一个文件中,而多文件组件将 PHP、Blade、JavaScript 和测试组织在一个目录中。
默认情况下,基于视图的组件文件以 ⚡ emoji 为前缀,以便在编辑器和搜索中与常规 Blade 文件区分开来。这可以通过 make_command.emoji 配置禁用。
bash
php artisan make:livewire create-post # Single-file (default)
php artisan make:livewire create-post --mfc # Multi-file
php artisan livewire:convert create-post # Convert between formats插槽和属性转发
组件现在支持插槽和使用 的自动属性包转发,使组件组合更加灵活。
基于视图的组件中的 JavaScript
基于视图的组件现在可以包含 <script> 标签而无需 @script 包装器。这些脚本作为单独的缓存文件提供,以获得更好的性能和自动的 $wire 绑定:
blade
<div>
<!-- Your component template -->
</div>
<script>
// $wire is automatically bound as 'this'
this.count++ // Same as $wire.count++
// $wire is still available if preferred
$wire.save()
</script>Islands(岛屿)
Islands 允许你在组件内创建独立更新的隔离区域,在不创建单独子组件的情况下显著提高性能。
blade
@island(name: 'stats', lazy: true)
<div>{{ $this->expensiveStats }}</div>
@endislandIslands 还支持从组件操作进行命令式渲染和流式传输。
加载改进
延迟加载
除了懒加载(基于视口)之外,组件现在可以延迟到初始页面加载后立即加载:
blade
<livewire:revenue defer />php
#[Defer]
class Revenue extends Component { ... }捆绑加载
控制多个懒加载/延迟组件是并行加载还是捆绑在一起加载:
blade
<livewire:revenue lazy.bundle />
<livewire:expenses defer.bundle />php
#[Lazy(bundle: true)]
class Revenue extends Component { ... }异步操作
使用 .async 修饰符或 #[Async] 属性并行运行操作而不阻塞其他请求:
blade
<button wire:click.async="logActivity">Track</button>php
#[Async]
public function logActivity() { ... }新指令和修饰符
wire:sort - 拖放排序
内置支持可拖放排序列表:
blade
<ul wire:sort="updateOrder">
@foreach ($items as $item)
<li wire:sort:item="{{ $item->id }}" wire:key="{{ $item->id }}">{{ $item->name }}</li>
@endforeach
</ul>wire:intersect - 视口交叉
当元素进入或离开视口时运行操作,类似于 Alpine 的 x-intersect:
blade
<!-- Basic usage -->
<div wire:intersect="loadMore">...</div>
<!-- With modifiers -->
<div wire:intersect.once="trackView">...</div>
<div wire:intersect:leave="pauseVideo">...</div>
<div wire:intersect.half="loadMore">...</div>
<div wire:intersect.full="startAnimation">...</div>
<!-- With options -->
<div wire:intersect.margin.200px="loadMore">...</div>
<div wire:intersect.threshold.50="trackScroll">...</div>可用修饰符:
.once- 仅触发一次.half- 等待直到一半可见.full- 等待直到完全可见.threshold.X- 自定义可见百分比 (0-100).margin.Xpx或.margin.X%- 交叉边距
wire:ref - 元素引用
轻松引用和与模板中的元素交互:
blade
<div wire:ref="modal">
<!-- Modal content -->
</div>
<button wire:click="$js.scrollToModal">Scroll to modal</button>
<script>
this.$js.scrollToModal = () => {
this.$refs.modal.scrollIntoView()
}
</script>.renderless 修饰符
直接从模板跳过组件重新渲染:
blade
<button wire:click.renderless="trackClick">Track</button>这是不需要更新 UI 的操作的 #[Renderless] 属性的替代方案。
.preserve-scroll 修饰符
在更新期间保持滚动位置以防止布局跳动:
blade
<button wire:click.preserve-scroll="loadMore">Load More</button>data-loading 属性
每个触发网络请求的元素都会自动接收一个 data-loading 属性,使使用 Tailwind 设置加载状态样式变得容易:
blade
<button wire:click="save" class="data-loading:opacity-50 data-loading:pointer-events-none">
Save Changes
</button>JavaScript 改进
$errors 魔术属性
从 JavaScript 访问组件的错误包:
blade
<div wire:show="$errors.has('email')">
<span wire:text="$errors.first('email')"></span>
</div>$intercept 魔术方法
从 JavaScript 拦截和修改 Livewire 请求:
blade
<script>
this.$intercept('save', ({ ... }) => {
// ...
})
</script>从 JavaScript 定向 Island
直接从模板触发 island 渲染:
blade
<button wire:click.append="loadMore" wire:island="stats">
Load more
</button>获取帮助
如果你在升级过程中遇到问题:
- 查看文档以获取详细的功能指南
- 访问 GitHub discussions 获取社区支持