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

Laravel+Livewire Jetstream Modal无法显示及Alpine表达式错误修复

Laravel Livewire + Jetstream 模态框无法显示问题修复

问题场景

使用Laravel结合Livewire开发时,采用Jetstream的x-jet-dialog-modal组件,点击upgrade.blade.php中的升级按钮后,模态框无法正常显示,控制台抛出多个Alpine语法相关错误。

控制台错误信息

Alpine Expression Error: Unexpected token ')'
Expression: "{ show: window.Livewire.find('RVerQgFNN56RogBnUr0F').entangle('upgrademodal').defer, focusables() { // All focusable element types... let selector = 'a, button, input:not([type='hidden']), textarea, select, details, [tabindex]:not([tabindex='-1'])' return [...$el.querySelectorAll(selector)] // All non-disabled elements... .filter(el => ! el.hasAttribute('disabled')) }, firstFocusable() { return this.focusables()[0] }, lastFocusable() { return this.focusables().slice(-1)[0] }, nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() }, prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() }, nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) }, prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 }, }"

Alpine Expression Error: show is not defined
Expression: "show"

Uncaught SyntaxError: Unexpected token ')'
Uncaught ReferenceError: show is not defined

修复步骤

1. 确保Livewire组件类定义正确属性

在对应的Livewire组件类(如App\Http\Livewire\UpgradeModal.php)中,必须定义upgrademodal属性,并添加打开模态框的方法:

class UpgradeModal extends Component
{
    public $upgrademodal = false;
    // 其他业务属性:plans、plan_id、plan_name等
    
    // 触发打开模态框的方法
    public function openModal()
    {
        $this->upgrademodal = true;
    }

    // 其他业务方法:selectPlan、payment等
    
    public function render()
    {
        return view('livewire.upgrade-modal');
    }
}

2. 清理模态框视图中的冗余脚本

将视图中的jQuery、Stripe脚本移到项目主布局文件(如resources/views/layouts/app.blade.php)的</body>标签前,避免与Alpine.js冲突。修改后的upgrade-modal.php视图代码:

<div>
    <x-jet-dialog-modal wire:model="upgrademodal" maxWidth="md">
        <x-slot name="title">
            <div class="w-full h-12 flex items-center">
                <h2 class="text-xl font-medium tracking-wider flex items-center space-x-3">
                    <span>Unlock Endless Creativites</span>
                    <img src="{{ asset('studio-asset/svgs/leaf.png') }}" alt="heading image" class="w-8 h-8">
                </h2>
            </div>
        </x-slot>

        <x-slot name="content">
           <div class="w-full space-y-5">
                <div class="w-full flex items-center">
                    <!-- 可添加月度/年度切换逻辑 -->
                </div>
                <div class="w-full space-y-2">
                    @foreach ($this->plans as $plan )
                        <div wire:click="selectPlan({{ $plan->id }})" class="w-full h-20 @if($plan->id == $this->plan_id) bg-green-50 @else border @endif rounded cursor-pointer p-4 flex">
                            <div class="w-10/12 h-full">
                                <div><span class="text-md font-bold tracking-widest">{{ $plan->name }}</span> - <span>{{ App\Http\Livewire\UpgradeModal::totalCredit($plan->id) }}</span> <span class="text-sm text-gray-400">Credits/month</span></div>
                                <div class="space-x-1"><span>US$</span> <span>{{ $plan->price_monthly }}</span><span>/</span> <span>Month</span></div>
                            </div>
                            <div class="w-2/12 h-full flex items-center justify-center">
                               <div class="w-full h-full flex items-center justify-center">
                                @if($plan->id == $this->plan_id)
                                    <div class="w-5 h-5 rounded-full p-1 bg-green-400 flex items-center">
                                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8.922 6.927"><path data-name="Combined Shape" d="M3.261 4.798L7.468.245a.86.86 0 011.2 0 .968.968 0 010 1.3l-4.676 5.06a1 1 0 01-1.468 0L.251 4.147a.968.968 0 010-1.3.86.86 0 011.2 0" fill="#fafafa"></path></svg>
                                    </div>
                                @else
                                    <div class="w-5 h-5 rounded-full border-2"></div>
                                @endif
                               </div>
                            </div>
                        </div>
                    @endforeach
                </div>
                <div class="w-full h-12 flex items-center">
                    <span class="px-5 h-8 flex items-center cursor-pointer bg-yellow-100 rounded ">Have a Promo Code ?</span>
                </div>
           </div>
        </x-slot>

        <x-slot name="footer">
            <div class="w-full h-12 flex items-center justify-end">
                <span wire:click="payment()" wire:loading.class="text-gray-700" wire:loading.attr="disabled" class="px-5 h-10 text-sm tracking-wider flex items-center cursor-pointer bg-indigo-500 rounded text-white">Get Started with {{ $this->plan_name }}</span>
            </div>
        </x-slot>
    </x-jet-dialog-modal>
</div>

3. 迁移Stripe脚本到主布局

将原视图中的Stripe脚本移至app.blade.php末尾:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
$(function() {
    var $form = $(".require-validation");
    
    $('form.require-validation').bind('submit', function(e) {
        var $form = $(".require-validation"),
        inputSelector = ['input[type=email]', 'input[type=password]',
                        'input[type=text]', 'input[type=file]',
                        'textarea'].join(', '),
        $inputs = $form.find('.required').find(inputSelector),
        $errorMessage = $form.find('div.error'),
        valid = true;
        $errorMessage.addClass('hidden');
    
        $('.has-error').removeClass('has-error');
        $inputs.each(function(i, el) {
        var $input = $(el);
        if ($input.val() === '') {
            $input.parent().addClass('has-error');
            $errorMessage.removeClass('hidden');
            e.preventDefault();
        }
        });
    
        if (!$form.data('cc-on-file')) {
        e.preventDefault();
        Stripe.setPublishableKey('pk_test_51JEZdbSCJoZTKKTopB08PolKHDBMgGMsTskcj3Hbdjic5XCn9Z1ovtH0sgUMVaPhOse8CAhMsqzvP2MAwqSGOv8f00gGuc0A7H');
        Stripe.createToken({
            number: $('.card-number').val(),
            cvc: $('.card-cvc').val(),
            exp_month: $('.card-expiry-month').val(),
            exp_year: $('.card-expiry-year').val()
        }, stripeResponseHandler);
        }
    
    });

    function stripeResponseHandler(status, response) {
        if (response.error) {
            $('.error')
                .removeClass('hidden')
                .find('.alert')
                .text(response.error.message);
        } else {
            var token = response['id'];
                
            $form.find('input[type=text]').empty();
            $form.append("<input wire:model='stripeToken' type='hidden' name='stripeToken' value='" + token + "'/>");
            $form.get(0).submit();
        }
    }
});
</script>

4. 确保Alpine.js版本兼容

Jetstream依赖特定版本的Alpine.js,安装官方推荐版本并初始化:

npm install alpinejs@^3.x --save-dev

在resources/js/app.js中添加初始化代码:

import Alpine from 'alpinejs';

window.Alpine = Alpine;

Alpine.start();

5. 清理缓存并重新编译资源

php artisan view:clear
php artisan cache:clear
npm run dev

错误原因总结

  1. 模态框视图中直接引入第三方脚本,导致Alpine.js表达式解析冲突
  2. Jetstream模态框的内部Alpine逻辑因语法错误无法初始化show状态变量
  3. Livewire组件类未正确定义upgrademodal属性,导致双向绑定失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:29:54