恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Livewire 组件事件监听全解析:`[On]` 属性从入门到源码级原理

  • 首页
  • 资讯中心
  • /
  • Livewire 组件事件监听全解析:`[On]` 属性从入门到源码级原理

相关资讯

MMPose 133关键点全身姿态估计三步快速跑通 2026/9/20 12:55:34
Python 3.12 装不上 RapidOCR?两步搞定 rapidocr_api 安装顺序 2026/9/20 12:50:34
NumPy 核心 C 实现原理深度解析:内存模型、迭代器、广播与 ufunc 全流程 2026/9/20 12:50:34

最新资讯

抖音无水印批量下载:3 种任务的完整操作指南
职场AI工具选型指南:豆包、元宝、DeepSeek、Kimi、WorkBuddy分工与协作
如何配置 PT-Plugin-Plus:PT下载插件从安装到一键下载种子的完整指南
京东云 Kubernetes + Traefik 实战,这次用 TaoToken 让 Codex 走通 Ingress 404 排查
FreeRTOS 实时操作系统:如何借助 150+ 个官方 Demo 工程快速搭起你的多任务框架
昇腾分布式训练核心:HCCL架构、调优与故障排查实战

今日推荐

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Livewire 组件事件监听全解析:`[On]` 属性从入门到源码级原理

发布时间:2026/9/20 12:55:34
Livewire 组件事件监听全解析:`[On]` 属性从入门到源码级原理 后端前端【免费下载链接】livewireA full-stack framework for Laravel that takes the pain out of building dynamic UIs.项目地址https://gitcode.com/gh_mirrors/li/livewire点击查看免费下载#[On]是 Livewire 提供的 PHP 8 属性Attribute让组件能够监听其他组件、浏览器乃至 Laravel Echo 派发的事件并在事件触发时自动调用指定方法。本文以 docs/attribute-on.md 为主线结合仓库内 src/Features/SupportEvents 的源码实现与浏览器测试完整讲解#[On]的用法、参数传递、动态事件名、浏览器事件监听、模板内监听等场景并深入剖析事件从派发到触发的底层链路。读完本文你将能够在自己的 Livewire 应用中熟练搭建松耦合的组件间通信并理解其背后的工作机制。认识#[On]属性#[On]是 Livewire 暴露给开发者的公开属性类位于 src/Attributes/On.php其实现非常薄——它继承自Livewire\Features\SupportEvents\BaseOn并声明了属性的使用规则?php // src/Attributes/On.php namespace Livewire\Attributes; use Attribute; use Livewire\Features\SupportEvents\BaseOn; #[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] class On extends BaseOn { // }从源码结构可以确认两个关键信息可重复使用IS_REPEATABLE同一个方法上可以叠加多个#[On]实现一个方法监听多个事件可作用于类与方法TARGET_CLASS | TARGET_METHOD#[On]既可以挂在方法上也可以挂在组件类上挂在类上时事件触发后默认调用$refresh详见下文BaseOn::boot()的分析。真正的逻辑在父类 src/Features/SupportEvents/BaseOn.php 中。它的boot()方法会在组件启动时把事件名注册进组件的listenersFromAttributes存储区?php // src/Features/SupportEvents/BaseOn.php public function boot() { foreach (Arr::wrap($this-event) as $event) { $this-storePush( listenersFromAttributes, $this-getName() ?? $refresh, $event, ); } }注意两点构造函数接收的$event经过Arr::wrap()包装说明你甚至可以传入一个数组来批量注册监听$this-getName() ?? $refresh则表明——当属性挂在类级别方法名未知时事件触发的默认动作是刷新组件$refresh这与 Livewire 内置的$refresh魔法动作一致。基本用法声明事件监听器把#[On]放在任何你想要在事件派发时被调用的方法上方即可?php // resources/views/components/⚡dashboard.blade.php use Livewire\Attributes\On; use Livewire\Component; new class extends Component { #[On(post-created)] // [tl! highlight] public function updatePostList($title) { session()-flash(status, New post created: {$title}); } };当另一个组件派发post-created事件时updatePostList()方法会被自动调用。务必导入属性类使用#[On()]前必须添加use Livewire\Attributes\On;导入语句否则 PHP 会把它当作普通注释监听不会生效。这一点在 docs/events.md 中同样被明确强调。事件被触发时会发起一次网络请求Livewire 请求并把随事件携带的数据作为参数传给监听方法。因此updatePostList($title)能直接接收到派发时传入的title值。派发事件dispatch()方法要触发监听器使用组件上的dispatch()方法?php // resources/views/components/post/⚡create.blade.php use Livewire\Component; use App\Models\Post; new class extends Component { public $title ; public function save() { $post Post::create([title $this-title]); $this-dispatch(post-created, title: $post-title); // [tl! highlight] return redirect(/posts); } };post-created事件会触发所有标记了#[On(post-created)]的方法。从源码看dispatch()由 src/Features/SupportEvents/HandlesEvents.php 中的 trait 提供?php // src/Features/SupportEvents/HandlesEvents.php public function dispatch($event, ...$params) { $event new Event($event, $params); store($this)-push(dispatched, $event); return $event; }每次调用dispatch()都会创建一个 Event 对象并压入组件 store 的dispatched队列返回的$event对象支持链式调用如-to()、-self()见下文。在组件脱水dehydrate阶段SupportEvents.php 会把这些事件序列化进响应的dispatcheseffect由前端 supportListeners.js 最终以浏览器事件的形式派发出去。向监听器传递数据事件可以携带任意数量的命名参数// 派发多个参数 $this-dispatch(post-updated, id: $post-id, title: $post-title);// 监听并接收参数 #[On(post-updated)] public function handlePostUpdate($id, $title) { // 使用 $id 和 $title... }命名参数会按名称映射到监听方法的形参上。前端 JS 事件监听器则通过event.detail访问同样的数据参见 docs/events.md 中$dispatch与 Alpine 的示例。此外Event.php 中还预留了几个特殊参数名ref、component、el、self以及向后兼容的to它们会被从普通参数中剥离用于把事件定向派发到特定组件、ref 或 DOM 元素而不是作为业务数据传给监听方法。动态事件名按模型 ID 精确监听你可以把组件属性嵌入事件名实现作用域化的监听?php // resources/views/components/post/⚡show.blade.php use Livewire\Attributes\On; use Livewire\Component; use App\Models\Post; new class extends Component { public Post $post; #[On(post-updated.{post.id})] // [tl! highlight] public function refreshPost() { $this-post-refresh(); } };如果$post-id是3该组件只会监听post-updated.3事件忽略对其他文章的更新。对应的派发方写法是在事件名中做字符串插值$this-dispatch(post-updated.{$post-id});动态占位符的解析实现在 SupportEvents.phpgetComponentListeners()收集监听器后会调用replaceDynamicPlaceholders()用正则/\{(.*)\}/U匹配{...}片段并通过 Laravel 的data_get()从组件上取出对应属性值static function replaceDynamicPlaceholders($event, $component) { return preg_replace_callback(/\{(.*)\}/U, function ($matches) use ($component) { return data_get($component, $matches[1], function () use ($matches) { throw new \Exception(Unable to evaluate dynamic event name placeholder: .$matches[0]); }); }, $event); }可以看到占位符支持data_get的点语法如post.id会读取组件属性post的id如果占位符无法求值会抛出Unable to evaluate dynamic event name placeholder异常——这是排查动态事件名写错时的关键线索。一个方法监听多个事件得益于#[On]的IS_REPEATABLE特性单个方法可以叠加多个监听#[On(post-created)] #[On(post-updated)] #[On(post-deleted)] public function refreshStats() { // 任何帖子变化时刷新统计 }post-created、post-updated、post-deleted中任意一个被派发refreshStats()都会被调用。这在统一刷新统计面板这类场景中非常实用。监听浏览器事件JavaScript 派发#[On]也能监听由浏览器 JavaScript 派发的事件#[On(user-logged-in)] public function handleUserLogin() { // 处理登录... }// 从 JavaScript 中派发 window.dispatchEvent(new CustomEvent(user-logged-in));之所以可行是因为 Livewire 的事件系统底层就是原生浏览器事件。前端 supportListeners.js 会为每个监听器注册两层监听全局window监听任何window.addEventListener(name, handler)捕获到同名事件后调用component.$wire.call(__dispatch, name, e.detail || {})把事件交给服务端处理e.detail即CustomEvent携带的数据组件根元素监听用于处理不冒泡的定向派发如dispatch()-to()/dispatch()-self()产生的非 bubbling 事件。同时代码中还有component.isLazy判断——懒加载组件在真正完成挂载前不会响应事件监听器会在组件清理时通过window.removeEventListener自动注销避免内存泄漏。__dispatch到达服务端后由 SupportEvents.php 的call()钩子处理先校验事件名是否在监听列表内再解析出对应方法并调用。若事件无人监听会抛出Livewire\Exceptions\EventHandlerDoesNotExist异常对应源码 EventHandlerDoesNotExist.php。替代方案在模板中直接监听子组件事件除了属性方式你也可以在 Blade 模板里直接对子组件监听事件livewire:post.edit saved$refresh /这行代码监听post.edit子组件派发的saved事件事件触发时刷新父组件。也可以调用具体方法并传递事件数据livewire:post.edit savedhandleSave($event.id) /若子组件派发了命名参数例如$this-dispatch(saved, postId: 1)在模板中可以通过$event.detail.postId的形式取用参见 docs/events.md 中的savedclose($event.detail.postId)示例。这种模板内监听适合父子组件间的定向通信与#[On]的全局广播式监听互为补充。何时使用#[On]#[On]适合以下场景一个组件需要响应另一个组件中的动作实现实时通知或实时更新构建通过事件通信的松耦合组件监听浏览器事件或 Laravel Echo 事件外部数据发生变化时刷新数据。需要提醒的是如果只是子组件调用父组件方法Livewire 还提供了更直接的$parent方式在模板中wire:click$parent.showCreatePostForm()事件并非唯一选择详见 docs/events.md 的提示。实战示例实时通知铃铛下面是一个完整的通知铃铛组件它监听两条事件分别实现未读数的自增与清零?php // resources/views/components/⚡notification-bell.blade.php use Livewire\Attributes\On; use Livewire\Component; new class extends Component { public $unreadCount 0; public function mount() { $this-unreadCount auth()-user()-unreadNotifications()-count(); } #[On(notification-sent)] // [tl! highlight] public function incrementCount() { $this-unreadCount; } #[On(notifications-read)] // [tl! highlight] public function resetCount() { $this-unreadCount 0; } }; ?button classrelative svg!-- 铃铛图标 --/svg if($unreadCount 0) span classabsolute -top-1 -right-1 bg-red-500 text-white rounded-full px-2 py-1 text-xs {{ $unreadCount }} /span endif /button应用中任意位置的组件都可以派发事件来更新角标// 应用中的任何位置 $this-dispatch(notification-sent);当用户阅读完通知时另一个组件派发notifications-read角标即被清零。两个监听器互不耦合这正是事件驱动架构带来的灵活性。底层链路一次事件派发如何被#[On]接收把前面各节串起来一次完整的事件生命周期如下对应源码路径均可点击查阅派发组件调用dispatch(post-created, title: $title)HandlesEvents.php 创建Event对象并存入组件 store 的dispatched队列脱水SupportEvents.php 的dehydrate()把dispatched序列化为响应的dispatcheseffect同时把监听器列表来自类属性$listeners与#[On]属性注册的listenersFromAttributes合并而成见getComponentListeners()作为listenerseffect 下发前端注册supportListeners.js 收到listenerseffect 后在window上注册原生事件监听触发任何代码Livewire 派发、Alpine$dispatch、原生CustomEvent派发同名事件后前端调用component.$wire.call(__dispatch, name, e.detail)服务端回调SupportEvents.php 的call()钩子校验事件存在性不存在则抛EventHandlerDoesNotExist、执行监听方法上的#[Authorize]鉴权检查若有最后通过wrap($this-component)-$method(...$params)调用被#[On]标记的方法并返回结果。如果监听方法被标记为#[Renderless]则事件处理后不会触发组件重渲染——仓库测试 BrowserTest.php 中的test_dont_call_render_on_renderless_event_handler验证了该行为。同文件还覆盖了事件在 mount 期间派发、嵌套组件监听器清理、监听器请求失败不产生未处理的 Promise 拒绝等多个边界场景可作为深入理解事件机制的参考用例。测试事件派发与监听在 Livewire 测试中你可以用assertDispatched()断言组件派发了某个事件Livewire::test(CreatePost::class) -call(save) -assertDispatched(post-created);也可以在测试环境中直接派发事件验证监听器行为Livewire::test(Dashboard::class) -assertSee(Posts created: 0) -dispatch(post-created) -assertSee(Posts created: 1);更完整的测试示例可参考 docs/events.md 的 Testing dispatched events 章节。参考属性签名#[On( string $event, )]参数类型默认值说明$eventstring必填要监听的事件名称支持{property}动态占位符此外两点进阶提示定向派发dispatch()返回的Event对象支持链式-to(component: Dashboard::class)或-to(self: true)把事件只派发给特定组件或仅自身配合#[On]可实现精确的一对一通信实现见 Event.php 的serialize()Laravel Echo 集成#[On]同样可监听echo:前缀的实时事件如#[On(echo:orders,OrderShipped)]适合 WebSocket 实时推送场景。更多关于事件派发、定向派发与 Laravel Echo 的完整说明请继续阅读仓库内的 Events 文档。赞分享后端前端【免费下载链接】livewireA full-stack framework for Laravel that takes the pain out of building dynamic UIs.项目地址https://gitcode.com/gh_mirrors/li/livewire点击查看免费下载相关推荐新手快速上手FreeLLMAPI从安装到第一个免费AI回复的完整图文教程新手快速上手FreeLLMAPI从安装到第一个免费AI回复的完整图文教程 FreeLLMAPI 是一款 免费 LLM API 路由工具 把 Google、G后端API网关LLM 网关大模型ToolJet Map 组件深度解析属性、事件、组件特定动作与源码级实现原理ToolJet Map 组件深度解析属性、事件、组件特定动作与源码级实现原理 本文以 ToolJet 的 Map地图组件为主线完整覆盖其属性配置、事件体低代码后端前端AI 应用MCP 服务Vant AddressList 地址列表组件完全指南属性、事件、插槽与源码级原理解析Vant AddressList 地址列表组件完全指南属性、事件、插槽与源码级原理解析 AddressList地址列表是 Vant 移动端 Vue 组件库前端UI组件上一篇WeChatMsg 原理揭秘微信聊天记录如何导出成 HTML、Word、CSV还能生成年度聊天报告下一篇【亲测免费】 Python Google Search API 教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号