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

Laravel Livewire中Summernote编辑器重渲染失效及模态框加载问题求助

Laravel Livewire 与 Summernote 兼容问题解决方案

问题1:模态框中Summernote无法加载

原因:模态框由Livewire动态渲染,页面初始化时的Summernote脚本不会对后续生成的DOM元素生效。
解决:监听模态框的显示事件,在模态框完全显示后重新初始化Summernote;同时封装初始化函数避免重复实例化。

问题2:非模态框场景下Summernote值变为null

原因:Livewire的wire:model绑定的是textarea原生value,但Summernote编辑器内容不会自动同步到该属性,导致Livewire无法获取值。
解决:监听Summernote的内容变更事件,通过Livewire JS API将编辑器内容同步到组件的long_des属性。

问题3:表单验证失败后Summernote编辑器模板消失

原因:验证失败后Livewire会重新渲染表单DOM,原Summernote实例被销毁,新生成的textarea未重新初始化编辑器。
解决:给Summernote容器添加wire:ignore标记,阻止Livewire重新渲染该区域;同时监听Livewire的验证事件,重新初始化编辑器并回填组件的long_des值。


具体代码修改

1. Blade视图修改

给Summernote容器添加wire:ignore,并确保模态框结构可被JS监听:

<form wire:submit.prevent>
    @csrf
    <div class="my-3">
        <label for="title" class="label">Title:</label>
        <input wire:model="title" class="form-control @error('title') is-invalid @enderror" type="text" value="{{ old('title') }}" placeholder="Title">
        @error('title') <span class="text-danger">{{ $message }}</span> @enderror
    </div>

    <div class="my-3">
        <label for="short_des" class="label">Short Description:</label>
        <input wire:model="short_des" class="form-control @error('short_des') is-invalid @enderror" type="text" value="{{ old('short_des') }}" placeholder="Short Description">
        @error('short_des') <span class="text-danger">{{ $message }}</span> @enderror
    </div>

    <!-- 添加wire:ignore阻止Livewire重新渲染编辑器区域 -->
    <div class="my-3" wire:ignore>
        <label for="long_des" class="label">Long Description:</label>
        <textarea wire:model="long_des" id="summernote" class="form-control summernote @error('long_des') is-invalid @enderror" cols="30" rows="10" placeholder="Details...">{{ old('long_des') }}</textarea>
        @error('long_des') <span class="text-danger">{{ $message }}</span> @enderror
    </div>

    <div class="my-3">
        <label for="cover_image" class="cover_image">Cover Image:</label>
        <input wire:model="cover_image" class="form-control  @error('cover_image') is-invalid @enderror" type="file">
        @error('cover_image') <span class="text-danger">{{ $message }}</span> @enderror
    </div>
    <button wire:click='addPortfolio' type="submit" class="btn btn-primary my-3">Add Portfolio</button>
</form>

<!-- 预览模态框示例 -->
<div class="modal fade" id="previewModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Portfolio Preview</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <div wire:ignore>
                    <label class="label">Long Description:</label>
                    <textarea id="modal-summernote" class="form-control summernote" cols="30" rows="10"></textarea>
                </div>
            </div>
        </div>
    </div>
</div>

2. Summernote初始化脚本修改

封装初始化函数,添加事件监听实现值同步与DOM更新后的重新初始化:

// 封装Summernote初始化逻辑
function initSummernote(selector, content = '') {
    // 先销毁已有实例,避免重复初始化冲突
    $(selector).summernote('destroy');
    $(selector).summernote({
        height: 300,
        codemirror: {
            mode: 'text/html',
            htmlMode: true,
            lineNumbers: true,
            theme: 'monokai',
        },
        callbacks: {
            // 初始化时回填内容
            onInit: function() {
                if (content) $(this).summernote('code', content);
            },
            // 内容变更时同步到Livewire组件
            onChange: function(contents) {
                const wireModel = $(this).attr('wire:model');
                if (wireModel) {
                    Livewire.dispatch('updateSummernoteValue', {
                        property: wireModel,
                        value: contents
                    });
                }
            }
        }
    });
}

$(document).ready(function() {
    // 初始化主编辑器
    initSummernote('#summernote', @json($long_des));

    // 监听模态框显示事件,初始化模态框内的编辑器
    $('#previewModal').on('shown.bs.modal', function() {
        initSummernote('#modal-summernote', @json($long_des));
    });

    // 监听Livewire验证失败事件,重新初始化编辑器
    Livewire.on('messageSent', function() {
        const component = Livewire.find(@json($this->id));
        initSummernote('#summernote', component.long_des);
    });

    // 监听组件重置事件,清空编辑器
    Livewire.on('resetPage', function() {
        initSummernote('#summernote', '');
    });
});

3. Livewire组件修改

添加事件监听,接收前端传来的Summernote内容更新:

<?php

namespace App\Livewire\Backend\Portfolio;

use App\Models\Portfolio;
use Livewire\Attributes\Layout;
use Livewire\Component;
use Livewire\WithFileUploads;
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class PortfolioComponent extends Component
{
    use WithFileUploads;
    #[Layout('livewire.layout.backend')]

    public $title;
    public $short_des;
    public $long_des;
    public $cover_image, $update_cover_image;
    public $portfolio;
    public $id;
    public $deleteModal;
    public $previewModel;
    public $status;
    public $edit;


    public function mount(){
        $this->portfolio  = Portfolio::latest()->get();
        // 监听前端的内容同步事件
        $this->listen('updateSummernoteValue', function($data) {
            if ($data['property'] === 'long_des') {
                $this->long_des = $data['value'];
            }
        });
    }


    public function addPortfolio(){
        $this->validate([
            'title' => 'required',
            'short_des' => 'required|max:100',
            'long_des' => 'required',
            'cover_image' => 'required|file|mimes:jpg,jpeg,png|max:2048',
        ]);

        $portfolio = new Portfolio();
        $portfolio->title = $this->title;
        $portfolio->short_des = $this->short_des;
        $portfolio->long_des = $this->long_des;

        // 图片保存逻辑不变
        if($this->cover_image){
            $manager = new ImageManager(new Driver());
            $img = hexdec(uniqid()) . '.' . $this->cover_image->extension();
            $path ='/images/portfolio/'.$img; 
            $manager->read($this->cover_image)->resize(144, 217)->save(public_path('/images/portfolio/').$img);
            $portfolio->cover_image = $path;
        }
        $portfolio->status = 'active';
        $portfolio->save();
        
        // 触发重置事件通知前端
        $this->dispatch('resetPage');
        $this->resetPage();
        session()->flash('success','Portfolio added successfully!');
    }

    public function show($id){
        $this->id = $id;
        $portfolio = Portfolio::findOrFail($this->id);
        $this->title = $portfolio->title;
        $this->short_des = $portfolio->short_des;
        $this->long_des = $portfolio->long_des;
        $this->cover_image = $portfolio->cover_image;
        $this->status = $portfolio->status;
        $this->previewModel = true;
    }

    public function resetPage(){
        $this->reset(['title',
                    'short_des',
                    'long_des',
                    'cover_image',
                    'update_cover_image',
                    'deleteModal',
                    'id',
                    'previewModel',
                    'status',
                    'edit'
                ]);
    }

    public function render()
    {
        return view('livewire.backend.portfolio.portfolio-component');
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:59:51