Laravel 11+Livewire 3.5中wire:poll引发页面变白问题
问题:Livewire添加wire:poll后页面变白
使用Laravel 11 + Livewire 3.5开发,通过php artisan make:livewire TvDisplay创建组件。给需要更新的元素加上wire:poll后,页面会在2.5秒后完全变白,而非仅更新目标组件。移除wire:poll后页面刷新正常,添加后到轮询时间点就出现变白问题。
控制器代码
<?php namespace App\Livewire; use Livewire\Component; use App\Models\Ticket; use Illuminate\Support\Facades\Log; class TvDisplay extends Component { public $calledTicket; public $upcomingTickets; protected $listeners = ['ticketUpdated' => 'updateTickets']; public function mount() { $this->updateTickets(); } public function updateTickets() { $this->calledTicket = Ticket::where('served', 1)->latest()->first(); $this->upcomingTickets = Ticket::where('served', 0)->orderBy('created_at', 'asc')->take(10)->get(); } public function render() { return view('livewire.tv-display'); } }
视图代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TV Display</title> <style> body { background: url('storage/img/background.png') no-repeat center center fixed; background-size: cover; font-family: Arial, sans-serif; margin: 0; padding: 0; overflow: hidden; /* Remove a barra de rolagem */ } .container { color: white; height: 100vh; display: flex; flex-direction: row; } .left-panel { width: 28%; height: 100%; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; padding: 20px; text-align: center; margin-top: 90px; /* Ajuste conforme necessário */ } .left-panel h1, .left-panel h2 { margin-top: 0; } .table-container { max-width: 100%; display: flex; flex-direction: column; align-items: center; /* Centraliza o conteúdo da tabela */ } .video-panel { width: 66.67%; height: 100%; display: flex; justify-content: center; align-items: center; } .video-panel video { width: 98%; height: auto; max-width: 100%; } table { width: 100%; margin-top: 20px; border-collapse: collapse; text-align: center; /* Centraliza o texto nas células */ } th, td { padding: 10px; font-size: 2.1em; /* Aumentando o tamanho da fonte */ } thead { background-color: #f2f2f279; } .called-ticket { width: 100%; height: 130px; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color:#f2f2f279; /* Retângulo branco com opacidade baixa */ margin-bottom: 20px; font-size: 2.3em; /* Aumentando o tamanho da fonte */ padding: 10px; /* Adicionando padding para melhor visualização */ } .called-ticket h2 { margin: 0; } .called-ticket h3 { margin: 10px 0 0 0; font-size: 1.1em; /* Ajuste o tamanho da fonte conforme necessário */ } </style> </head> <body> <div class="container" > <!-- Divisão da Tabela e Texto --> <div class="left-panel"> <div class="table-container"> <h1>Senha chamada</h1> <div class="called-ticket" wire:poll> @if ($calledTicket) <h2>{{ $calledTicket->queue->name }} - {{ $calledTicket->sequential }}</h2> @if ($calledTicket->user && $calledTicket->user->servicePost) <h3>{{ $calledTicket->user->servicePost->name }}</h3> @else <h3>--</h3> @endif @else <h2>--</h2> <h3>--</h3> @endif </div wire:poll> <table> <thead> <tr> <th>Fila</th> </tr> </thead> <tbody> @foreach ($upcomingTickets as $ticket) <tr> <td >{{ $ticket->queue->name }} - {{ $ticket->sequential }}</td> </tr> @endforeach </tbody> </table> </div> </div> <!-- Divisão do Vídeo --> <div class="video-panel"> <video autoplay muted loop> <source src="{{ asset('storage/tv/SPC.mp4') }}" type="video/mp4"> </video> </div> </div> </body> </html>
问题原因
- 视图结构不符合Livewire规范:当前组件视图包含完整的HTML文档结构(
<html>、<head>、<body>),但Livewire组件视图应该仅为内容片段。当wire:poll触发更新时,Livewire会尝试替换整个组件内容,导致页面DOM结构混乱,最终出现页面变白。 - wire:poll语法错误:视图中错误地在闭合标签上重复写了
wire:poll,正确写法是仅在起始标签添加该属性。
解决方案
1. 拆分视图结构
将完整的HTML骨架移到父视图,组件视图仅保留业务内容:
修改后的组件视图(livewire.tv-display)
<div class="container"> <!-- Divisão da Tabela e Texto --> <div class="left-panel"> <div class="table-container"> <h1>Senha chamada</h1> <div class="called-ticket" wire:poll.5s> @if ($calledTicket) <h2>{{ $calledTicket->queue->name }} - {{ $calledTicket->sequential }}</h2> @if ($calledTicket->user && $calledTicket->user->servicePost) <h3>{{ $calledTicket->user->servicePost->name }}</h3> @else <h3>--</h3> @endif @else <h2>--</h2> <h3>--</h3> @endif </div> <table> <thead> <tr> <th>Fila</th> </tr> </thead> <tbody> @foreach ($upcomingTickets as $ticket) <tr> <td>{{ $ticket->queue->name }} - {{ $ticket->sequential }}</td> </tr> @endforeach </tbody> </table> </div> </div> <!-- Divisão do Vídeo --> <div class="video-panel"> <video autoplay muted loop> <source src="{{ asset('storage/tv/SPC.mp4') }}" type="video/mp4"> </video> </div> </div>
创建父视图(tv-display.blade.php)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TV Display</title> <style> /* 原视图中的CSS样式全部移到这里 */ body { background: url('storage/img/background.png') no-repeat center center fixed; background-size: cover; font-family: Arial, sans-serif; margin: 0; padding: 0; overflow: hidden; } .container { color: white; height: 100vh; display: flex; flex-direction: row; } .left-panel { width: 28%; height: 100%; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; padding: 20px; text-align: center; margin-top: 90px; } .left-panel h1, .left-panel h2 { margin-top: 0; } .table-container { max-width: 100%; display: flex; flex-direction: column; align-items: center; } .video-panel { width: 66.67%; height: 100%; display: flex; justify-content: center; align-items: center; } .video-panel video { width: 98%; height: auto; max-width: 100%; } table { width: 100%; margin-top: 20px; border-collapse: collapse; text-align: center; } th, td { padding: 10px; font-size: 2.1em; } thead { background-color: #f2f2f279; } .called-ticket { width: 100%; height: 130px; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color:#f2f2f279; margin-bottom: 20px; font-size: 2.3em; padding: 10px; } .called-ticket h2 { margin: 0; } .called-ticket h3 { margin: 10px 0 0 0; font-size: 1.1em; } </style> @livewireStyles </head> <body> @livewire('tv-display') @livewireScripts </body> </html>
2. 更新路由指向父视图
// routes/web.php Route::get('/tv-display', function () { return view('tv-display'); });
3. 修正wire:poll语法
确保wire:poll仅添加在起始标签,可通过.5s指定轮询间隔(避免默认2.5秒过于频繁):
<div class="called-ticket" wire:poll.5s> <!-- 内容 --> </div>
4. 优化数据查询(可选)
在控制器中使用预加载避免N+1查询:
public function updateTickets() { $this->calledTicket = Ticket::with(['queue', 'user.servicePost']) ->where('served', 1) ->latest() ->first(); $this->upcomingTickets = Ticket::with('queue') ->where('served', 0) ->orderBy('created_at', 'asc') ->take(10) ->get(); }
内容的提问来源于stack exchange,提问作者Henrique Postalli
相关产品推荐
相关产品推荐

