Laravel 8 解决Quilljs编辑器内容存库失败及回显问题的方法
Quill编辑器内容存取实现方案
你遇到的拿不到编辑器内容的核心原因是:Quill 初始化后只是在指定的div容器上做富文本渲染,这个div不属于表单的原生可提交元素,所以表单默认提交时根本不会把div里的内容带到后端,自然通过
$request取不到值。要实现内容存库、回显,只需要做两层简单适配就行。
第一步:调整Blade模板的表单结构
原来的代码缺少和编辑器一一对应的真实可提交字段,需要给每个Quill渲染容器搭配一个隐藏input,让这个input承担表单值提交的作用。改造后的模板示例:
<!-- 确保所有编辑器区块都在form标签内部 --> <form method="POST" action="{{ route('test.store') }}"> @csrf <div class="card-body"> <div class="row"> <div class="col-md-12"> <div class="form-group"> <label for="test">Information</label> <!-- Quill 富文本渲染容器 --> <div id="test" style="height: 200px;"></div> <!-- 对应编辑器的隐藏提交字段,name 和后端接收字段、数据库字段名完全保持一致 --> <input type="hidden" name="test" id="test_input"> </div> </div> <!-- 剩下两个编辑器按照同样逻辑,分别添加独立渲染容器 + 对应name的隐藏input即可 --> </div> </div> <button type="submit" class="btn btn-primary">提交</button> </form>
第二步:初始化Quill并做内容同步
引入Quill的样式与脚本后,在页面底部编写初始化逻辑,实现两个核心能力:编辑器内容变化时实时同步到隐藏input、表单提交前做一次全量同步兜底,避免内容漏传。
对应的JS代码:
// 配置编辑器映射关系,key是Quill容器的id,value是对应隐藏input的id const editorMap = { 'test': 'test_input', // 剩下两个编辑器按格式补全,比如 'intro': 'intro_input', 'detail': 'detail_input' }; // 批量初始化Quill实例 const editorInstances = {}; Object.keys(editorMap).forEach(containerId => { const editor = new Quill(`#${containerId}`, { theme: 'snow', // 按自身需求配置工具栏选项 modules: { toolbar: [ [{ 'header': [1, 2, false] }], ['bold', 'italic', 'underline'], ['image', 'code-block'] ] } }); editorInstances[containerId] = editor; // 监听编辑器内容变化,实时同步到对应的隐藏input editor.on('text-change', () => { const inputDom = document.getElementById(editorMap[containerId]); // 存轻量的展示用HTML结构,直接取编辑器渲染的HTML就行 inputDom.value = editor.root.innerHTML; // 如果需要后续在同一个Quill实例里精确编辑、保留所有格式位置,换成Quill原生Delta结构存储: // inputDom.value = JSON.stringify(editor.getContents()); }); }); // 表单提交前做兜底同步,避免最后一次内容修改因为事件触发时序问题漏传 document.querySelector('form').addEventListener('submit', () => { Object.keys(editorMap).forEach(containerId => { const editor = editorInstances[containerId]; const inputDom = document.getElementById(editorMap[containerId]); inputDom.value = editor.root.innerHTML; }); });
注意:数据库对应字段要设置为
TEXT或者LONGTEXT类型,不能用短字符串类型,否则长内容会被截断无法正常存储。
第三步:后端控制器适配
原有控制器逻辑只需要做少量修正即可正常接收到编辑器内容:
- 修正原代码里的语法错误:
$request-validate少了箭头操作符,要写成$request->validate()才能正常运行。 - 确保验证规则的字段名和隐藏input的name完全匹配。
- 对应模型的
$fillable属性里加上编辑器对应的字段,避免批量赋值被拦截。
public function store(Request $request) { $validated = $request->validate([ 'test' => 'nullable|string', // 其他两个编辑器字段按照同样规则补全 ]); Testtable::create($validated); return redirect()->route('home')->with('success', 'You successfully add a new Product!'); }
第四步:已存储内容的回显
打开编辑页面时,把数据库存储的内容传给前端,在Quill初始化完成后填充到对应容器即可:
- 控制器返回编辑视图时,把模型数据传给视图:
public function edit(Testtable $testtable) { return view('edit', compact('testtable')); }
- 视图内把初始内容注入到JS中,避免跨域或格式问题:
<script> const initialContent = { 'test': @json(old('test', $testtable->test ?? '')) // 其他字段按同样逻辑补全 }; </script>
- 在Quill初始化完成后,补充内容填充逻辑:
Object.keys(editorMap).forEach(containerId => { const editor = editorInstances[containerId]; const content = initialContent[containerId]; if (!content) return; // 如果存的是HTML结构,用这个方法填充 editor.clipboard.dangerouslyPasteHTML(content); // 如果存的是Delta结构化数据,换这个方法填充 // const delta = JSON.parse(content); // editor.setContents(delta); });
常见踩坑提醒
- 不要直接把Quill的渲染容器当成表单提交字段,它只是展示用DOM,本身没有表单值属性。
- 不要把Quill的工具栏单独拆分到渲染容器外部,否则会出现工具条和编辑区分离的问题。
- 确保form标签内没有遗漏
@csrf指令,否则提交会触发419鉴权错误。
内容的提问来源于stack exchange,提问作者Cookie
相关产品推荐
相关产品推荐

