Next.js集成React Quill出现Tab重复触发问题如何修复
Next.js下react-quill按Tab键重复缩进问题修复
问题表现
在Next.js项目中安装使用react-quill,基础富文本功能可正常运行,但按下Tab键时会触发多次重复缩进,效果如下:
初始问题代码如下:
import { useState } from "react"; import dynamic from "next/dynamic"; const ReactQuill = dynamic(() => import("react-quill"), { ssr: false }); import "react-quill/dist/quill.snow.css"; function App() { const [value, setValue] = useState(""); const modules = { toolbar: [ [{ header: "1" }, { header: "2" }, { font: [] }], [{ size: [] }], ["bold", "italic", "underline", "strike", "blockquote"], [ { list: "ordered" }, { list: "bullet" }, { indent: "-1" }, { indent: "+1" }, ], ["link", "image", "video"], ["clean"], ], clipboard: { matchVisual: false, }, }; return ( <div> <ReactQuill value={value} onChange={setValue} theme='snow' modules={modules} /> </div> ); } export default App;
问题原因
两个核心问题导致该bug:
- modules配置直接写在组件函数内部,每次输入触发组件重渲染时都会生成全新的modules对象,导致Quill重复初始化模块、重复绑定Tab键事件监听,一次按键会触发多次缩进逻辑
- Quill默认的Tab键事件绑定没有阻止冒泡,在Next.js的SSR/CSR混合渲染场景下容易出现事件重复触发的问题
修复方案
按以下两点调整代码即可解决:
- 将modules配置移到组件外部(或用useMemo缓存),避免重渲染时重复初始化模块
- 新增keyboard模块配置,手动接管Tab、Shift+Tab的缩进逻辑,阻止默认事件冒泡
修复后的完整代码:
import { useState } from "react"; import dynamic from "next/dynamic"; const ReactQuill = dynamic(() => import("react-quill"), { ssr: false }); import "react-quill/dist/quill.snow.css"; // 移到组件外部,避免重渲染生成新配置 const modules = { toolbar: [ [{ header: "1" }, { header: "2" }, { font: [] }], [{ size: [] }], ["bold", "italic", "underline", "strike", "blockquote"], [ { list: "ordered" }, { list: "bullet" }, { indent: "-1" }, { indent: "+1" }, ], ["link", "image", "video"], ["clean"], ], clipboard: { matchVisual: false, }, // 新增键盘事件配置,接管Tab逻辑 keyboard: { bindings: { tab: { key: 9, handler(range) { // 执行单次缩进 this.quill.format("indent", "+1", true, "user"); // 阻止默认逻辑和事件冒泡,避免重复触发 return false; }, }, "shift tab": { key: 9, shiftKey: true, handler(range) { // 执行单次反向缩进 this.quill.format("indent", "-1", true, "user"); return false; }, }, }, }, }; function App() { const [value, setValue] = useState(""); return ( <div> <ReactQuill value={value} onChange={setValue} theme="snow" modules={modules} /> </div> ); } export default App;
调整后按Tab/Shift+Tab只会触发单次缩进/反向缩进,不会再出现重复缩进的问题。
内容的提问来源于stack exchange,提问作者Ferdinand Felix
相关产品推荐
相关产品推荐

