ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

在 Next.js 中集成 Quill 富文本编辑器:with-quill-js 官方示例全解析

在 Next.js 中集成 Quill 富文本编辑器:with-quill-js 官方示例全解析 在 Next.js 中集成 Quill 富文本编辑器with-quill-js 官方示例全解析【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.jsQuill 是一款功能强大的所见即所得富文本编辑器但它的实现依赖浏览器 DOM API无法直接服务端渲染SSR。本指南以仓库内 examples/with-quill-js 官方示例为骨架讲解如何借助react-quill封装层与next/dynamic的ssr: false机制在 Next.js 中安全地按需加载并渲染 Quill 编辑器。阅读完你将掌握富文本编辑器与 Next.js 结合的经典模式、工具栏与格式白名单的配置方法以及底层next/dynamic禁用 SSR 的实现原理。示例概览与文件结构examples/with-quill-js 是一个极简的 Pages Router 示例全部代码只有三个文件pages/index.js首页组件负责用next/dynamic包装react-quill并配置编辑器的工具栏与格式pages/_app.js在全局入口导入 Quill 的主题样式quill.snow.csspackage.json声明依赖与dev/build/start脚本。其中 package.json 的核心依赖仅四项dependencies: { next: latest, react: ^18.2.0, react-dom: ^18.2.0, react-quill: ^1.3.3 }即编辑器本体react-quill对 Quill 的 React 封装加上框架自身。Quill 的 JavaScript 与 CSS 并不在服务端加载而是完全由浏览器侧按需取用这正是本示例要演示的关键点。一键初始化示例应用示例 README 给出的标准用法是使用create-next-app拉取模板。在仓库根目录下或任意空目录中执行以下任一命令即可完成引导npx create-next-app --example with-quill-js with-quill-js-appyarn create next-app --example with-quill-js with-quill-js-apppnpm create next-app --example with-quill-js with-quill-js-app以上三种方式分别对应 npm、Yarn、pnpm效果一致都会以with-quill-js-app为目录名从当前仓库的examples/with-quill-js模板拷贝出完整项目并安装依赖。初始化完成后即可进入目录运行npm run dev # 开发模式等价于 next npm run build # 生产构建等价于 next build npm run start # 启动生产服务等价于 next start如果你的目标是仅在本仓库内查看实现而不实际运行直接阅读 pages/index.js 与 pages/_app.js 两个文件即可理解全部集成逻辑。核心实现用 next/dynamic 规避 SSR 限制Quill 不支持 SSR 的原因README 明确指出Quill does not support SSR, so its only loaded and rendered in the browser.Quill 不支持 SSR因此它只在浏览器中加载和渲染。Quill 在初始化时会直接操作document、访问window并测量 DOM 尺寸、监听选区变化这些行为在 Node.js 服务端渲染环境中都不存在。若在服务端直接import react-quill轻则出现 hydration 不一致服务端输出空内容、客户端再补齐重则直接抛错。因此正确姿势是让 Quill 完全跳过服务端执行。next/dynamicssr: false的免 SSR 封装pages/index.js 的第一段代码正是解决方案import dynamic from next/dynamic; const QuillNoSSRWrapper dynamic(() import(react-quill), { ssr: false, loading: () pLoading .../p, });这里dynamic(() import(react-quill))将react-quill从静态导入改写为动态导入配合{ ssr: false }告知 Next.js该模块只在客户端加载。loading回调则指定了动态模块尚未就绪时的占位内容这里是一段 Loading ... 文本。从源码层面看这个行为由 packages/next/src/shared/lib/dynamic.tsx 中的noSSR辅助函数保证当运行在客户端typeof window ! undefined时直接以正常的 Loadable 逻辑初始化组件当运行在服务端isServerSide为真时不会触发模块加载而是渲染一个仅包含loading占位符的组件并立即返回。也就是说服务端 HTML 中只会有pLoading .../p占位真正的 Quill DOM 完全由浏览器端接管构建。这从框架底层印证了 README 的结论——Quill 永远不会进入服务端渲染管线。值得一提的还有loading回调的完整签名。依据同一源码文件中的DynamicOptionsLoadingProps类型定义dynamic.tsxloading 组件实际会收到{ error, isLoading, pastDelay, retry, timedOut }五个字段示例里省略参数直接渲染p是合法的简写你可以在需要错误重试提示时使用这些字段。编辑器配置工具栏、剪贴板与格式白名单包装好的QuillNoSSRWrapper在首页组件中被渲染为受控编辑器export default function Home() { return QuillNoSSRWrapper modules{modules} formats{formats} themesnow /; }modules定制工具栏与剪贴板行为modules对象同文件内定义控制编辑器功能模块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: { // toggle to add extra line breaks when pasting HTML: matchVisual: false, }, };参数含义逐项拆解toolbar一个二维数组每个一维子数组在界面上渲染为一组按钮分组[{ header: 1 }, { header: 2 }, { font: [] }]下拉选择header指定标题级别1 为h1、2 为h2font: []使用 Quill 默认字体下拉[{ size: [] }]字号下拉[bold, italic, underline, strike, blockquote]粗体、斜体、下划线、删除线、引用块按钮[{ list: ordered }, { list: bullet }, { indent: -1 }, { indent: 1 }]有序/无序列表与缩进增减[link, image, video]插入链接、图片、视频[clean]一键清除格式。clipboard.matchVisualQuill 剪贴板模块的选项。示例注释说明了用途——默认情况下粘贴 HTML 时 Quill 会尽量还原视觉换行matchVisual: false则关闭该行为。需要粘贴多产生额外换行场景时可将其改为true体验差异。formats格式白名单const formats [ header, font, size, bold, italic, underline, strike, blockquote, list, bullet, indent, link, image, video, ];formats数组声明编辑器允许识别和保留哪些格式化类型与toolbar一一对应。它既是校验白名单也会影响dangerouslyPasteHTML/ 粘贴等场景下内容被如何解析。若工具栏新增了按钮例如color或align务必同步将其格式名加入此数组否则相关样式不会被正确应用。theme 与样式导入组件上的themesnow指定 Quill 的 Snow 主题。主题对应的样式文件在 pages/_app.js 中全局导入import react-quill/dist/quill.snow.css;由于 Next.js 内置 CSS 与 Sass 支持Pages Router 下全局样式只能在_app.js引入CSS 导入放在应用入口是推荐且必要的做法示例中_app.js本身只做了样式导入 透传Component与pageProps两件事。与框架机制的对应关系及扩展方向为什么必须走dynamic而非静态 import若将react-quill改为顶层静态import该模块会随首屏 bundle 一并进入服务端渲染图触发前文描述的 SSR 问题。而next/dynamic同时提供了代码分割code splitting与运行时豁免runtime bailout两项能力Quill 的体积被切到独立 chunk仅在浏览器需要时才下载执行。这也是仓库内另一个动态加载示例 examples/with-dynamic-import/app/page.tsx 所强调的通用模式。在仓库的测试集中同样能看到该语义在 Pages Router 下的广泛使用例如 test/production/pages-dir/production/fixture/pages/dynamic/no-ssr.js 与 test/production/pages-dir/production/fixture/pages/dynamic/no-ssr-custom-loading.js 分别验证了{ ssr: false }的免渲染输出与自定义 loading 占位行为可以作为深入理解该选项的对照用例。表单场景的实战延伸本示例中的QuillNoSSRWrapper是非受控使用未传入value/onChange。在实际业务中若要接入表单与提交逻辑可扩展为受控组件新增useState保存 HTML 内容将内容作为value传入并通过onChange回调更新状态提交时再把该 HTML 交由后端存储或用于预览渲染。需要时也可以用dynamic包一层受控编辑器组件与页面组件解耦。小结本示例展示了将浏览器专用库以 Quill 为代表接入 Next.js 的标准三步法封装用next/dynamic(() import(react-quill), { ssr: false })生成仅客户端加载的组件包装器必要时通过loading提供占位反馈配置通过modules工具栏、剪贴板与formats格式白名单定制编辑器行为并通过theme选择主题皮肤样式在 pages/_app.js 中全局引入对应主题 CSS。其底层保障来自 packages/next/src/shared/lib/dynamic.tsx 的noSSR逻辑服务端只渲染 loading 占位、绝不初始化模块客户端才真正挂载编辑器从而同时规避 SSR 崩溃并实现按需加载。任何同样依赖 DOM 的三方库如代码高亮、图表、拖拽库都可套用这一模式这也是该示例在官方 examples 集合中被长期保留的价值所在。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表