You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Livewire+Alpine实现标签页时遇$refs.panel未定义错误求助

问题排查:Alpine $refs.panel 未定义错误

错误信息

Alpine Expression Error: can't access property "contains", $refs.panel is undefined
Expression: "! $refs.panel.contains($event.target) && close()"

Uncaught TypeError: can't access property "contains", $refs.panel is undefined

问题场景

使用Livewire和Alpine构建带标签页的页面,切换标签时触发上述错误,已尝试在App Service Provider中定义Livewire JS加载位置,问题未解决。相关代码如下:

<header>
    <div class="bg-primaryBlack flex items-center justify-between px-8">
        <div>
            <a href="/">
                <x-application-logo class="w-28 h-24" />
            </a>
        </div>
        <div>
            <nav>
                <ul class="flex text-primaryWhite font-semibold">
                    <li class="mr-5">
                        <a
                            class="hover:text-gray-400 transition-colors ease-in-out"
                            href="#">Plaques</a>
                    </li>
                    <li class="mr-5">
                        <a
                            class="hover:text-gray-400 transition-colors ease-in-out"
                            href="#">Pens</a>
                    </li>
                    <li>
                        <a
                            class="hover:text-gray-400 transition-colors ease-in-out"
                            href="#">Lichtenberg</a>
                    </li>
                </ul>
            </nav>
        </div>
        {{--Parent--}}
        <div
            x-data="{
            open: false,
            toggle(){
                this.open = this.open ? this.close() : true
            },

            close(focusAfter){
                this.open=false

                focusAfter && focusAfter.focus()
            }
            }"
            @keydown.escape.prevent.stop="close()"
            x-id="['dropdown-button']"
            @focusin.window= "! $refs.panel.contains($event.target) && close()"
            class="relative">

            @if(Auth::user())
                <div class="flex items-center relative">
                    {{-- Button --}}
                    <button
                        x-ref="button"
                        @click="toggle()"
                        type="button"
                        :aria-expanded="open"
                        :aria-controls="$id('dropdown-button')"
                        class="text-primaryWhite text-sm block mr-2"
                        href="{{ route('dashboard') }}">{{ auth()->user()->name }}</button>
                    <x-icons.right-caret class="w-5 h-5 fill-primaryWhite" />
                    <div class="absolute top-0 -left-7">
                        <x-icons.cart class="w-5 h-5 fill-primaryWhite"/>
                        <a class="absolute -top-3 -left-5 text-xs bg-red-400 px-1.5 rounded-full text-primaryWhite font-bold" href="#">5</a>
                    </div>

                </div>
                {{--Panel--}}
                <div
                    x-ref="panel"
                    x-show="open"
                    @click.outside="close($refs.button)"
                    :id="$id('dropdown-button')"
                    style="display:none"
                    class="absolute top-10 right-3 z-10">
                    <ul class="bg-secondaryWhite px-4 text-left py-2 space-y-2 rounded uppercase text-sm">
                        <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                            <x-links.logout/>
                        </li>
                        <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                            <a href="{{ route('dashboard') }}">Dashboard</a>
                        </li>
                        <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                            <a href="#">Cart</a>
                        </li>
                    </ul>
                </div>

            @else
                <a
                    class="font-semibold text-gray-300 mr-4 hover:text-gray-400 transition-colors ease-in-out"
                    href="{{ route('login') }}">Login</a>
                <a
                    class="font-semibold text-gray-300 hover:text-gray-400 transition-colors ease-in-out"
                    href="{{ route('register') }}">Register</a>
            @endif
        </div>
    </div>
</header>

问题原因

绑定了@focusin.window事件的容器,其内部的x-ref="panel"元素仅在用户已登录(Auth::user()为真)时才会渲染。当用户未登录时,页面不存在panel这个引用,标签页切换触发window的focus事件时,Alpine找不到$refs.panel,因此抛出错误。

修复方法

方法1:给focusin事件添加存在性判断

修改@focusin.window的表达式,先确认$refs.panel存在再执行后续逻辑:

@focusin.window=" $refs.panel && ! $refs.panel.contains($event.target) && close()"

方法2:将Alpine逻辑拆分到已登录分支内

把包含下拉菜单逻辑的x-data、事件绑定等代码,移到@if(Auth::user())内部,仅在用户登录时加载这段Alpine逻辑,从根源避免未登录时的引用缺失:

{{-- 移除外层的x-data和相关事件,移到已登录分支里 --}}
@if(Auth::user())
<div
    x-data="{
        open: false,
        toggle(){
            this.open = this.open ? this.close() : true
        },
        close(focusAfter){
            this.open=false
            focusAfter && focusAfter.focus()
        }
    }"
    @keydown.escape.prevent.stop="close()"
    x-id="['dropdown-button']"
    @focusin.window="! $refs.panel.contains($event.target) && close()"
    class="relative">
    {{-- 按钮和面板代码 --}}
    <div class="flex items-center relative">
        {{-- Button --}}
        <button
            x-ref="button"
            @click="toggle()"
            type="button"
            :aria-expanded="open"
            :aria-controls="$id('dropdown-button')"
            class="text-primaryWhite text-sm block mr-2"
            href="{{ route('dashboard') }}">{{ auth()->user()->name }}</button>
        <x-icons.right-caret class="w-5 h-5 fill-primaryWhite" />
        <div class="absolute top-0 -left-7">
            <x-icons.cart class="w-5 h-5 fill-primaryWhite"/>
            <a class="absolute -top-3 -left-5 text-xs bg-red-400 px-1.5 rounded-full text-primaryWhite font-bold" href="#">5</a>
        </div>
    </div>
    {{--Panel--}}
    <div
        x-ref="panel"
        x-show="open"
        @click.outside="close($refs.button)"
        :id="$id('dropdown-button')"
        style="display:none"
        class="absolute top-10 right-3 z-10">
        <ul class="bg-secondaryWhite px-4 text-left py-2 space-y-2 rounded uppercase text-sm">
            <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                <x-links.logout/>
            </li>
            <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                <a href="{{ route('dashboard') }}">Dashboard</a>
            </li>
            <li class="hover:bg-primaryGreen hover:text-primaryWhite px-2 rounded">
                <a href="#">Cart</a>
            </li>
        </ul>
    </div>
</div>
@else
{{-- 未登录的登录/注册链接 --}}
<a
    class="font-semibold text-gray-300 mr-4 hover:text-gray-400 transition-colors ease-in-out"
    href="{{ route('login') }}">Login</a>
<a
    class="font-semibold text-gray-300 hover:text-gray-400 transition-colors ease-in-out"
    href="{{ route('register') }}">Register</a>
@endif

内容的提问来源于stack exchange,提问作者dnoble82581

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:37:29