React-Quilljs图片缩放与对齐失效:提交API后样式丢失
问题解决:React-QuillJS图片缩放样式丢失
问题根源
你遇到的问题是因为Quill默认的image blot不会保存图片的width/height等行内样式,当通过dangerouslyPasteHTML重新加载HTML内容时,Quill会将图片解析为默认的image embed,导致之前调整的样式丢失。此外blotFormatter调整的样式直接作用在DOM元素上,但默认情况下Quill不会将这些样式同步到可保存的内容结构中,或保存后重新解析时无法识别。
解决方案
1. 自定义支持样式的Image Blot
创建自定义Image Blot,让它能够存储并渲染图片的width、height样式:
import Quill from 'quill'; const Image = Quill.import('formats/image'); class CustomImage extends Image { static blotName = 'image'; static tagName = 'IMG'; static create(value: any) { const node = super.create(value) as HTMLImageElement; if (value.src) node.src = value.src; // 应用保存的样式 if (value.width) node.style.width = value.width; if (value.height) node.style.height = value.height; return node; } static value(node: HTMLImageElement) { return { src: node.src, width: node.style.width, height: node.style.height, }; } } // 注册自定义Blot Quill.register(CustomImage, true);
2. 调整编辑器初始化逻辑
修改组件代码,确保自定义Blot提前注册,同时优化内容保存与加载逻辑:
import { useEffect } from 'react'; import { useQuill } from 'react-quilljs'; import BlotFormatter from 'quill-blot-formatter'; import Quill from 'quill'; // 提前注册自定义Image Blot和blotFormatter模块 const Image = Quill.import('formats/image'); class CustomImage extends Image { static blotName = 'image'; static tagName = 'IMG'; static create(value: any) { const node = super.create(value) as HTMLImageElement; if (value.src) node.src = value.src; if (value.width) node.style.width = value.width; if (value.height) node.style.height = value.height; return node; } static value(node: HTMLImageElement) { return { src: node.src, width: node.style.width, height: node.style.height, }; } } Quill.register(CustomImage, true); Quill.register('modules/blotFormatter', BlotFormatter); export default function TextEditor({ value, onValueText, }) { const { quill, quillRef } = useQuill({ modules: { blotFormatter: {}, toolbar: [['image']] // 显式配置toolbar确保图片按钮可用 }, }); const selectLocalImage = () => { const input = document.createElement('input'); input.setAttribute('type', 'file'); input.setAttribute('accept', 'image/*'); input.click(); input.onchange = async () => { const file = input?.files?.[0]; if (!file) return; const formData = new FormData(); formData.append('file', file); apiClient .uploadImage({ formData }) .then((res: any) => { const range = quill?.getSelection(); if (range && quill) { // 插入带初始样式的图片 quill.insertEmbed( range.index, 'image', { src: `${process.env.NEXT_PUBLIC_CLOUD_FRONT_URL!}/${res.data}`, width: '100%' // 可选默认样式 } ); } }) .catch((err) => { console.log(err); }); }; }; useEffect(() => { if (quill) { // 根据传入value的类型选择加载方式 if (typeof value === 'string') { quill.clipboard.dangerouslyPasteHTML(value || ''); } else { quill.setContents(value); } quill.getModule('toolbar').addHandler('image', selectLocalImage); quill.on('text-change', () => { // 优先保存Delta格式(更可靠),若必须保存HTML也会包含样式 // onValueText(quill.getContents()); onValueText(quill.root.innerHTML); }); } }, [quill, value]); return ( <div> <div ref={quillRef} /> </div> ); }
3. 关键注意事项
- 保存格式推荐:优先使用Quill的Delta格式(
quill.getContents())保存内容,Delta能完整保留所有格式信息;若后端必须接收HTML,自定义Blot会确保样式写入DOM的style属性,重新加载时可被正确解析。 - 模块注册时机:确保自定义Blot和
blotFormatter在Quill初始化前完成注册,避免模块未生效。 - 样式同步:
blotFormatter调整图片样式后,自定义Blot的value方法会自动将样式同步到可保存的内容结构中。
内容的提问来源于stack exchange,提问作者Sadaf Zillani
相关产品推荐
相关产品推荐

