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

Livewire+Choices.js+AlpineJS报$nextTick重定义错误

问题根源

你遇到的Uncaught TypeError: Cannot redefine property: $nextTick错误和Choices组件崩溃,是多个逻辑错误叠加导致的:

  • 触发报错的直接原因:全局变量污染。你先将window.choices赋值为Choices构造函数,后续初始化实例时未做变量声明,直接给choices赋值(非严格模式下会自动挂载到window),把构造函数覆盖为实例,污染全局作用域,触发Alpine/Livewire的内部属性校验失败。
  • wire:model绑定错误:多选框被错误绑定到存储选项列表的$options属性上,而非存储选中值的$selectedOptions,选中选项时会直接篡改选项列表数据,触发组件异常重渲染。
  • 缺少实例销毁和重渲染同步逻辑:Livewire每次DOM重绘后,旧的Choices实例没有被销毁,Choices生成的自定义DOM不会和原生select同步,重复初始化、残留事件监听会导致状态完全错乱。
  • 双向绑定断裂:Choices选中值变化时没有同步给Livewire,Livewire更新选中值后也没有同步回Choices实例。

修复方案

1. 修正Livewire组件类代码

移除冗余监听,修正事件派发逻辑,选中值更新时再通知前端同步:

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class ChoicesLivewire extends Component
{
    /**
     * @var array
     */
    public array $options;

    /**
     * @var array
     */
    public array $selectedOptions = [];

    public function mount()
    {
        $collection = [
            1 => 'Architektur',
            2 => 'Bauwirtschaft',
            3 => 'Straßenbau',
            4 => 'Tiefbau',
        ];

        $this->options = $collection;
        $this->selectedOptions = [2];
    }

    public function updatedSelectedOptions()
    {
        $this->dispatchBrowserEvent('choices:sync', ['currentSelects' => $this->selectedOptions]);
    }

    public function render()
    {
        return view('livewire.choices-livewire');
    }
}

2. 修正Blade模板代码

修正wire:model绑定目标,调整Alpine绑定逻辑,不需要手动给option加selected属性,Livewire会自动处理:

<div x-data="initChoices()">
    <select 
        wire:model="selectedOptions" 
        x-ref="multipleSelect"
        x-init="init"
        multiple
    >
        @foreach($options as $key => $option)
            <option value="{{$key}}">{{$option}}</option>
        @endforeach
    </select>

    @dump($selectedOptions)
</div>

3. 修正JS初始化代码

避免全局污染,增加实例销毁、双向同步、重渲染适配逻辑:

import Choices from "choices.js";

document.addEventListener('alpine:init', () => {
    Alpine.data('initChoices', () => ({
        choicesInstance: null,
        init() {
            // 存在旧实例先销毁,避免重复初始化
            if (this.choicesInstance) {
                this.choicesInstance.destroy();
            }

            // 初始化Choices
            this.choicesInstance = new Choices(this.$refs.multipleSelect, {
                itemSelectText: '',
                removeItems: true,
                removeItemButton: true,
            });

            // 设置初始选中值
            this.choicesInstance.setChoiceByValue(this.$wire.entangle('selectedOptions').value.map(String));

            // 监听Choices值变化,自动同步到Livewire,不需要手动写set逻辑
            this.$refs.multipleSelect.addEventListener('change', () => {
                this.choicesInstance.setChoiceByValue(this.$wire.selectedOptions.map(String));
            });

            // 监听后端值更新事件,同步Choices选中状态
            window.addEventListener('choices:sync', (event) => {
                this.choicesInstance.setChoiceByValue(event.detail.currentSelects.map(String));
            });

            // Livewire DOM更新完成后重建实例,避免DOM和实例脱节
            this.$wire.on('dom-diffed', () => {
                if (this.choicesInstance) {
                    this.choicesInstance.destroy();
                    this.init();
                }
            });
        }
    }))
})

如果你使用的Alpine版本低于3.x,把alpine:init事件替换为livewire:load即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:09:12