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

Livewire模态框中CKEditor无法显示的问题解决求助

问题:Livewire模态框中CKEditor无法正常渲染

我正在开发一款问卷构建器,支持用户根据所选字段类型添加不同问题,问题字段计划用CKEditor实现富文本编辑。
当前问题:点击添加字段按钮弹出模态框时,问题区域只显示普通textarea,CKEditor没正常渲染;但移除模态框外层的@if($isOpen)条件语句后,CKEditor能正常显示。试过多种方案都没解决,希望实现点击“Add”按钮时,模态框里正确加载CKEditor。


现有代码

模态框代码

<div>
@if($isOpen)
    <div class="fixed inset-0 bg-opacity-50 flex items-center justify-center">
        <div class="bg-white p-4 rounded-lg w-1/2">
            <h2 class="text-lg font-bold mb-4">Add {{ ucfirst($fieldType) }}</h2>

            <div>
                <label for="question" class="block mb-2">Question</label>
                <textarea id="question" wire:model="question" class="form-control"></textarea>
            </div>

            @if (in_array($fieldType, ['checkbox', 'radio', 'dropdown']))
                <div class="mt-4">
                    <h3 class="text-sm font-bold">Options</h3>
                    @foreach ($options as $index => $option)
                        <div class="flex items-center mb-2">
                            <input type="text" wire:model="options.{{ $index }}" class="form-control mr-2" placeholder="Option {{ $index + 1 }}">
                            <button wire:click.prevent="removeOption({{ $index }})" class="bg-red-500 text-white px-2 py-1 rounded">Remove</button>
                        </div>
                    @endforeach
                    <button wire:click.prevent="addOption" class="bg-blue-500 text-white px-2 py-1 rounded">Add Option</button>
                </div>
            @endif

            <!-- Modal Actions -->
            <div class="mt-4 flex justify-end">
                <button wire:click.prevent="saveField" class="bg-green-500 text-white px-4 py-2 rounded">Save Field</button>
                <button wire:click.prevent="closeModal" class="bg-gray-500 text-white px-4 py-2 rounded ml-2">Cancel</button>
            </div>
        </div>
    </div>
    <script src="https://cdn.ckeditor.com/ckeditor5/37.0.1/classic/ckeditor.js"></script>
    <script>
    ClassicEditor
        .create(document.querySelector('#question'))
        .catch(error => {
            console.error(error);
        });
    </script>
@endif
</div>

添加字段按钮代码

<div class="field-options w-1/4 bg-gray-100 p-4 rounded-lg space-y-4">
    <button wire:click.prevent="addField('textfield')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Textfield</button>
    <button wire:click.prevent="addField('textbox')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Textbox</button>
    <button wire:click.prevent="addField('checkbox')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Checkbox</button>
    <button wire:click.prevent="addField('radio')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Radio Buttons</button>
    <button wire:click.prevent="addField('dropdown')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Drop Down</button>
    <button wire:click.prevent="addField('file')" class="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600">Image/File Slot</button>
</div>

Livewire方法代码

public function addField($type)
{
    $this->dispatch('openModal', $type);
}

Livewire监听器代码

protected $listeners = ['openModal' => 'open'];

public function open($fieldType)
{
    $this->reset();
    $this->fieldType = $fieldType;
    $this->isOpen = true;  
}

解决方案

问题根源

当@if($isOpen)条件满足时,模态框DOM是动态插入的,此时CKEditor初始化脚本可能在DOM未完全渲染时执行,导致找不到#question元素;另外Livewire的DOM更新机制下,模板内的脚本执行时机无法匹配DOM加载完成的节点。

解决步骤

  1. 把CKEditor的CDN引入放到全局(比如页面layout),避免重复加载。
  2. 通过Livewire事件触发CKEditor初始化,确保DOM渲染完成后再执行初始化逻辑。
  3. 关闭模态框时销毁编辑器实例,防止内存泄漏和重复初始化问题。

修改后的代码

1. 模态框代码修改

<div>
@if($isOpen)
    <div class="fixed inset-0 bg-opacity-50 flex items-center justify-center">
        <div class="bg-white p-4 rounded-lg w-1/2">
            <h2 class="text-lg font-bold mb-4">Add {{ ucfirst($fieldType) }}</h2>

            <div>
                <label for="question" class="block mb-2">Question</label>
                <textarea id="question" wire:model="question" class="form-control"></textarea>
            </div>

            <!-- 选项区域代码保持不变 -->

            <!-- Modal Actions -->
            <div class="mt-4 flex justify-end">
                <button wire:click.prevent="saveField" class="bg-green-500 text-white px-4 py-2 rounded">Save Field</button>
                <button wire:click.prevent="closeModal" class="bg-gray-500 text-white px-4 py-2 rounded ml-2">Cancel</button>
            </div>
        </div>
    </div>
@endif
</div>

<!-- 全局脚本,放到页面底部或layout文件中 -->
<script src="https://cdn.ckeditor.com/ckeditor5/37.0.1/classic/ckeditor.js"></script>
<script>
let editorInstance = null;

// 监听模态框打开事件,初始化编辑器
window.addEventListener('modalOpened', () => {
    if (editorInstance) editorInstance.destroy();
    
    ClassicEditor.create(document.querySelector('#question'))
        .then(editor => {
            editorInstance = editor;
            // 同步编辑器内容到Livewire绑定属性
            editor.model.document.on('change:data', () => {
                document.querySelector('#question').value = editor.getData();
                window.Livewire.dispatch('inputUpdated', { value: editor.getData() });
            });
        })
        .catch(error => console.error(error));
});

// 监听模态框关闭事件,销毁编辑器
window.addEventListener('modalClosed', () => {
    if (editorInstance) {
        editorInstance.destroy();
        editorInstance = null;
    }
});
</script>

2. Livewire组件代码修改

protected $listeners = ['openModal' => 'open', 'inputUpdated' => 'updatedInput'];

public function open($fieldType)
{
    $this->reset();
    $this->fieldType = $fieldType;
    $this->isOpen = true;
    // 触发前端初始化编辑器的事件
    $this->dispatch('modalOpened');
}

public function closeModal()
{
    $this->isOpen = false;
    // 触发前端销毁编辑器的事件
    $this->dispatch('modalClosed');
}

// 同步编辑器内容到组件的question属性
public function updatedInput($value)
{
    $this->question = $value;
}

额外注意事项

  • 确保#question元素ID唯一,避免页面中存在同名元素导致初始化失败。
  • 关闭模态框时必须销毁编辑器实例,防止内存泄漏和下次打开时出现多个编辑器。
  • 如果使用CKEditor其他版本,替换对应CDN链接即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:55:56