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
相关产品推荐
相关产品推荐

