Livewire wire:show 指令完全指南:用 CSS 控制元素显示隐藏,告别服务器往返
2026/9/20 23:44:02 网站建设 项目流程

Livewire wire:show 指令完全指南:用 CSS 控制元素显示隐藏,告别服务器往返

【免费下载链接】livewireA full-stack framework for Laravel that takes the pain out of building dynamic UIs.项目地址: https://gitcode.com/gh_mirrors/li/livewire

wire:show是 Livewire 提供的响应式显示/隐藏指令,它通过切换元素的 CSSdisplay属性来控制可见性,而不是像 Blade 的@if那样把元素从 DOM 中彻底移除。本文基于 docs/wire-show.md 展开,结合仓库前端源码与浏览器测试,讲解wire:show的基本用法、过渡动画配合、表达式书写规则以及底层实现原理,帮助你用零网络往返的方式实现弹窗、错误提示、条件区域等常见 UI 交互。

@if的本质区别:CSS 隐藏 vs DOM 移除

理解wire:show的价值,首先要对比它和 Blade@if的差异:

  • @if是服务端渲染期的分支:条件为假时,元素根本不会出现在最终 HTML 中;条件变化必须发起一次服务器往返重新渲染整个组件。
  • wire:show是客户端的响应式切换:元素始终留在页面 DOM 中,只是通过 CSSdisplay: none被隐藏。切换可见性不需要服务器往返,因而动画更平滑、交互更即时。

这一点在原文档中明确说明,也是wire:show适合构建弹窗、折叠面板、错误提示等高频切换场景的根本原因。

基本用法:构建一个"新建文章"弹窗

原文档给出的典型场景是"新建文章(Create Post)"模态框。组件端用一个布尔属性showModal控制弹窗开关,并在保存成功后将其复位:

use Livewire\Component; use App\Models\Post; class CreatePost extends Component { public $showModal = false; public $content = ''; public function save() { Post::create(['content' => $this->content]); $this->reset('content'); $this->showModal = false; } }

视图端把wire:show="showModal"放在弹窗外层,用 Alpine 的x-on:click配合$wire.showModal = true直接修改组件属性——这个赋值发生在浏览器端,不会触发请求:

<div> <button x-on:click="$wire.showModal = true">New Post</button> <div wire:show="showModal"> <form wire:submit="save"> <textarea wire:model="content"></textarea> <button type="submit">Save Post</button> </form> </div> </div>

交互链路是:点击"New Post"按钮 →$wire.showModal = true在客户端立即生效 → 弹窗无服务器往返地出现;提交表单触发save()服务端方法 → 保存成功后$this->showModal = false→ 下一次响应回传时弹窗隐藏、表单内容被reset('content')清空。

结合 Alpine.js 过渡动画实现平滑显隐

因为wire:show只切换 CSSdisplay属性,元素本身始终存在于 DOM 中,所以 Alpine 的x-transition指令可以与之无缝配合。在原文档示例中,只需在带wire:show的元素上追加x-transition.duration.500ms,即可获得淡入淡出加缩放的过渡效果:

<div> <button x-on:click="$wire.showModal = true">New Post</button> <div wire:show="showModal" x-transition.duration.500ms> <form wire:submit="save"> <textarea wire:model="content"></textarea> <button type="submit">Save Post</button> </form> </div> </div>

x-transition是 Alpine 内置指令,支持.duration.500ms.opacity.scale.origin-top等大量修饰符组合(仓库本身即依赖 Alpine.js,见 package.json 与 js/index.js 的集成方式),读者可按需查阅 Alpine 官方过渡指令文档。

表达式书写规则:属性名、!取反与$errors

wire:show的值是一段"响应式表达式",在浏览器端被实时求值。可以从仓库测试中提炼出以下关键规则:

1. 直接引用组件属性

wire:show="showModal"中裸写属性名即可,Livewire 会自动把它解析为组件上的属性(见下文实现原理)。

2. 支持!逻辑取反

测试 SupportWireShow/BrowserTest.php 验证了两种写法都合法:

{{-- 无空格取反 --}} <div wire:show="!show">Hello</div> {{-- 取反符号与表达式之间允许空格 --}} <div wire:show="! show">Hello</div>

3. 可结合 Livewire 的魔术属性

例如在 SupportMagicErrors/BrowserTest.php 中,wire:show被用来按校验错误状态显示提示区域:

<div wire:show="$errors.has('email')" dusk="email-error"> <!-- 邮箱校验失败时显示的提示 --> </div>

$errors是 Livewire 暴露的魔术属性,这里演示了wire:show不仅限于简单布尔属性,还可以接受更复杂的表达式。

4. 不能用来调用服务端方法

wire:show属于响应式绑定,其表达式只在浏览器端求值,不会发起网络请求。测试test_wire_show_does_not_call_server_methods(见 SupportWireShow/BrowserTest.php)专门验证了这一点:把服务端方法名visible直接写进wire:show="visible"不会触发调用。这与 js/$wire.js 中"无法从 wire:text、wire:show、wire:bind 这类响应式绑定中调用服务器方法"的警告一致。

源码级原理:wire:show如何变成 Alpine 的x-show

从实现看,wire:show是 Livewire 对 Alpinex-show指令的一层封装。核心代码位于 js/directives/wire-show.js:

import { evaluateReactiveExpression } from '../evaluator' import Alpine from 'alpinejs' Alpine.interceptInit(el => { for (let i = 0; i < el.attributes.length; i++) { if (el.attributes[i].name.startsWith('wire:show')) { let { name, value } = el.attributes[i] let modifierString = name.split('wire:show')[1] let expression = value.trim() Alpine.bind(el, { ['x-show' + modifierString]() { return evaluateReactiveExpression(el, expression) } }) } } })

这段代码揭示了三个重要事实:

  1. 指令名拼接name.split('wire:show')[1]会把wire:show之后的部分原样拼到x-show后面。因此wire:show.important="show"实际编译为 Alpine 的x-show.important。测试test_wire_show_supports_the_important_modifier(SupportWireShow/BrowserTest.php)验证了.important修饰符生效时会生成display: none !important;的内联样式。原文档称该指令"没有修饰符",但从当前仓库实现看,修饰符会被透传给 Alpine 的x-show机制。

  2. 响应式求值:表达式通过evaluateReactiveExpression求值,而不是普通的 action 求值。在 js/evaluator.js 中,evaluateReactiveExpression会设置一个"正在求值响应式表达式"的深度标记,配合contextualizeExpression(js/evaluator.js)把裸写的标识符自动加上$wire.前缀——这就是wire:show="showModal"中直接写属性名即可的原因。

  3. Alpine 作用域隔离contextualizeExpression会收集元素到组件根节点之间已有的 Alpine 作用域键并跳过前缀化处理,避免把外层 Alpine 变量误解析成组件属性(见 js/evaluator.js 的getAlpineScopeKeys),保证表达式解析不会跨组件边界泄漏。

行为验证:仓库测试覆盖了哪些场景

src/Features/SupportWireShow/BrowserTest.php 作为 Dusk 浏览器测试,完整覆盖了wire:show的核心行为,可作为理解语义的权威参考:

测试方法验证的行为
test_wire_show_toggles_element_visibility属性为true时元素可见,点击切换后隐藏
test_wire_show_does_not_display_elements_when_property_is_initially_false初始为false时元素不显示,切换后出现
test_wire_show_supports_the_not_operator_before_the_expression支持!show取反写法
test_wire_show_supports_the_not_operator_with_a_space_before_the_expression支持! show(带空格)写法
test_wire_show_supports_the_important_modifier.important修饰符生效,生成display: none !important;
test_wire_show_does_not_call_server_methods表达式不会触发服务端方法调用,不会产生请求

这些测试还演示了与wire:click="$toggle('show')"的配合方式:$toggle是 Livewire 内置的魔术方法,可以在服务端翻转布尔属性,适合作为切换按钮的语义化写法。

参考语法速查

wire:show="expression"
  • 表达式:组件属性名、!取反表达式、或$errors等魔术属性表达式,在浏览器端实时求值;
  • 修饰符:原文档标注该指令无专属修饰符;从源码实现看,修饰符会被透传给 Alpine 的x-show(如.important),行为与 Alpine 一致;
  • 网络行为:纯客户端响应式绑定,求值不产生服务器请求;
  • 过渡动画:与 Alpinex-transition直接叠加使用即可获得平滑显隐效果。

【免费下载链接】livewireA full-stack framework for Laravel that takes the pain out of building dynamic UIs.项目地址: https://gitcode.com/gh_mirrors/li/livewire

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询