CKEditor 5 字数统计与字符统计(Word Count)功能全解析:配置、容器注入与实时监听实战
CKEditor 5 字数统计与字符统计Word Count功能全解析配置、容器注入与实时监听实战【免费下载链接】ckeditor5Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.项目地址: https://gitcode.com/GitHub_Trending/ck/ckeditor5Word Count字数统计是 CKEditor 5 中用于实时追踪编辑器内单词数与字符数的功能插件它通过监听文档模型Model数据变化将内容转为纯文本后按特定规则统计字数帮助开发者控制内容篇幅、实现类似120 字限制的输入校验等场景。读完本文你将掌握该插件的完整配置项、两种容器注入方式、update事件与按需精确取值 API并能用一套可运行的代码实现带字符上限的进度环效果。功能概览与统计原理Word Count 插件会统计编辑器中所有模型文本节点ModelText内的单词与字符数量并提供两个可随时读取的响应式属性与一个自更新的 HTML 输出容器。其统计流程分为三步实现位于 packages/ckeditor5-word-count/src/wordcount.ts通过_getText()遍历所有文档根root调用工具函数modelElementToPlainText()将模型数据转换为纯文本实现见 packages/ckeditor5-word-count/src/utils.ts。用正则表达式识别单词得到words计数。去除纯文本中的换行符后按长度得到characters计数。该功能在ckeditor/ckeditor5-word-count包中实现版本对应仓库当前发布版本见 packages/ckeditor5-word-count/package.json。从源码中的统计示例可以看出其精确规则模型内容单词数字符数说明paragraphfoo/paragraphparagraphbar/paragraph27每个块以换行分隔换行计入纯文本但不计入字符数paragraph$text boldtruefoo/$textbar/paragraph16加粗等格式标记不参与统计paragraph*^%)/paragraph05纯符号不算单词paragraphfoo(bar)/paragraph18括号内文字并入前一个词paragraph12345/paragraph15数字串计为一个单词单词识别依赖 Unicode 属性正则当运行环境支持\p{L}任意语言的字母与\p{N}任意脚本的数字时使用/([\p{L}\p{N}]\S?)/gu否则回退到/([a-zA-Z0-9À-ž]\S?)/guwordcount.ts因此中文、日文、阿拉伯文等多语言内容也能被正确统计。快速开始安装与基础接入首先按照 安装指南 完成编辑器集成然后将WordCount加入插件列表它不需要工具栏按钮属无 UI 功能import { ClassicEditor, WordCount } from ckeditor5; ClassicEditor .create( { licenseKey: YOUR_LICENSE_KEY, // 或 GPL。 plugins: [ WordCount, /* ... */ ], wordCount: { // 配置项见下文。 } } ) .then( /* ... */ ) .catch( /* ... */ );提示WordCount在源码中标为 premium 插件isPremiumPlugin返回true见 wordcount.ts需要有效的商业许可证评估或个人使用时也可使用GPL作为licenseKey。官方 Demo 使用的页面结构非常简单——编辑器与统计容器是两个相互独立的divdiv ideditor pHello world./p /div div idword-count/div通过插件暴露的wordCountContainer属性拿到自更新容器并挂载到页面上ClassicEditor .create( { // 配置细节。 } ) .then( editor { const wordCountPlugin editor.plugins.get( WordCount ); const wordCountWrapper document.getElementById( word-count ); wordCountWrapper.appendChild( wordCountPlugin.wordCountContainer ); } );当你在编辑器中增删内容时#word-count容器内的数字会实时变化。配置容器两种注入方式wordCountContainer属性在首次访问时才会创建视图View多次访问返回同一个元素源码见 wordcount.ts。插件生成的默认输出结构如下div classck ck-word-count div classck-word-count__wordsWords: %%/div div classck-word-count__charactersCharacters: %%/div /div除手动appendChild外第二种方式是在初始化配置中通过config.wordCount.container指定一个页面元素插件会在init()阶段自动把容器追加进去见 wordcount.tsClassicEditor .create( { wordCount: { container: document.getElementById( container-for-word-count ) } } );如果你的页面布局不允许直接使用默认的Words:/Characters:文案结构可以通过监听update事件完全自定义渲染方式详见下文实时监听小节。配置项详解插件的全部配置定义在 packages/ckeditor5-word-count/src/wordcountconfig.ts 的WordCountConfig接口中并通过类型增强augmentation.ts注册到编辑器全局配置wordCount键下。displayWords / displayCharacters隐藏单个计数器config.wordCount.displayWords设为false时隐藏单词计数器容器只保留字符部分div classck ck-word-count div classck-word-count__charactersCharacters: 28/div /divconfig.wordCount.displayCharacters设为false时隐藏字符计数器容器只保留单词部分div classck ck-word-count div classck-word-count__wordsWords: 4/div /div两个选项均默认开启配置未定义时按显示处理。注意容器视图在首次访问时构建因此该配置需在创建编辑器时确定隐藏选项只会影响wordCountContainer输出的 HTML不影响words/characters属性与update事件的数值。onUpdate内容统计变化时执行回调ClassicEditor .create( { // ... 其他配置 ... wordCount: { onUpdate: stats { // 打印当前内容统计。 console.log( Characters: ${ stats.characters }\nWords: ${ stats.words } ); } } } ) .then( /* ... */ ) .catch( /* ... */ );回调收到{ words, characters }对象。源码中该回调是通过监听插件自身的update事件转发的wordcount.ts。注意出于性能考虑回调会被节流throttle触发因此其中拿到的数值可能不是最新的。如果需要精确值请直接访问WordCount#characters和WordCount#words属性——这两个属性在构造器中被定义为 getter每次访问都会实时重新计算不依赖节流事件wordcount.ts适合用于表单校验、提交前检查等场景。实时监听update 事件与按需精确取值除config.wordCount.onUpdate外也可以直接订阅插件的update事件editor.plugins.get( WordCount ).on( update, ( evt, stats ) { // 打印当前内容统计。 console.log( Characters: ${ stats.characters }\nWords: ${ stats.words } ); } );从源码看统计的刷新链路为模型change:data事件 → 250ms 节流throttle( ..., 250 )见 wordcount.ts→_refreshStats()重算words/characters并触发update事件。测试用例 packages/ckeditor5-word-count/tests/wordcount.js 中对此有明确验证连续两次修改内容后等待约 300msupdate事件只触发一次节流合并且words、characters均为可观察observable属性可通过change:words/change:characters事件订阅。两者的适用场景节流后的update事件 /onUpdate适合驱动进度环、字数提示等 UI减少高频重绘。直接访问words/characters属性适合需要此刻绝对准确的判断如发布前校验、后端提交。另外_getText()会遍历所有文档根并用换行分隔wordcount.ts这意味着该插件天然支持 多根编辑器MultiRootEditor 场景多个根的内容会被合并统计。实战带 120 字符软限制的发帖编辑器官方 Demo 展示了如何组合onUpdate、SVG 进度环与 CSS 类实现一个带字符上限的帖子编辑器。当内容接近或超过 120 字符时进度环和背景会变色提示超过上限时发送按钮被禁用。核心 JS 逻辑const maxCharacters 120; const container document.querySelector( .demo-update ); const progressCircle document.querySelector( .demo-update__chart__circle ); const charactersBox document.querySelector( .demo-update__chart__characters ); const wordsBox document.querySelector( .demo-update__words ); const circleCircumference Math.floor( 2 * Math.PI * progressCircle.getAttribute( r ) ); const sendButton document.querySelector( .demo-update__send ); BalloonEditor .create( { root: { element: document.querySelector( #demo-update__editor ) }, // 编辑器配置。 wordCount: { onUpdate: stats { const charactersProgress stats.characters / maxCharacters * circleCircumference; const isLimitExceeded stats.characters maxCharacters; const isCloseToLimit !isLimitExceeded stats.characters maxCharacters * .8; const circleDashArray Math.min( charactersProgress, circleCircumference ); // 根据已输入字符数设置进度环的描边长度。 progressCircle.setAttribute( stroke-dasharray, ${ circleDashArray },${ circleCircumference } ); // 显示当前字符数超限时显示还需删掉多少个字符。 if ( isLimitExceeded ) { charactersBox.textContent -${ stats.characters - maxCharacters }; } else { charactersBox.textContent stats.characters; } wordsBox.textContent Words in the post: ${ stats.words }; // 接近上限时添加告警样式类。 container.classList.toggle( demo-update__limit-close, isCloseToLimit ); // 超过上限时添加超限样式类背景变红。 container.classList.toggle( demo-update__limit-exceeded, isLimitExceeded ); // 超过上限时禁用发送按钮。 sendButton.toggleAttribute( disabled, isLimitExceeded ); } } } );配套的 HTML 结构与样式进度环通过stroke-dasharray呈现比例.demo-update__limit-close将环变为橙色.demo-update__limit-exceeded将编辑区背景与环变为红色style .demo-update { border: 1px solid var(--ck-color-base-border); border-radius: var(--ck-border-radius); box-shadow: 2px 2px 0px hsla( 0, 0%, 0%, 0.1 ); margin: 1.5em 0; padding: 1em; } .demo-update h3 { font-size: 18px; font-weight: bold; margin: 0 0 .5em; padding: 0; } .demo-update .ck.ck-editor__editable_inline { border: 1px solid hsla( 0, 0%, 0%, 0.15 ); transition: background .5s ease-out; min-height: 6em; margin-bottom: 1em; } .demo-update__controls { display: flex; flex-direction: row; align-items: center; } .demo-update__chart { margin-right: 1em; } .demo-update__chart__circle { transform: rotate(-90deg); transform-origin: center; } .demo-update__chart__characters { font-size: 13px; font-weight: bold; } .demo-update__words { flex-grow: 1; opacity: .5; } .demo-update__limit-close .demo-update__chart__circle { stroke: hsl( 30, 100%, 52% ); } .demo-update__limit-exceeded .ck.ck-editor__editable_inline { background: hsl( 0, 100%, 97% ); } .demo-update__limit-exceeded .demo-update__chart__circle { stroke: hsl( 0, 100%, 52% ); } .demo-update__limit-exceeded .demo-update__chart__characters { fill: hsl( 0, 100%, 52% ); } /style div classdemo-update h3Post editor with word count/h3 div iddemo-update__editor pTourists frequently admit that a hrefhttps://en.wikipedia.org/wiki/Taj_MahalTaj Mahal/a simply cannot be described with words./p /div div classdemo-update__controls span classdemo-update__words/span svg classdemo-update__chart viewbox0 0 40 40 width40 height40 xmlnshttp://www.w3.org/2000/svg circle strokehsl(0, 0%, 93%) stroke-width3 fillnone cx20 cy20 r17 / circle classdemo-update__chart__circle strokehsl(202, 92%, 59%) stroke-width3 stroke-dasharray134,534 stroke-linecapround fillnone cx20 cy20 r17 / text classdemo-update__chart__characters x50% y50% dominant-baselinecentral text-anchormiddle/text /svg button typebutton classdemo-update__sendSend post/button /div /div这段代码可直接复用到你的项目中将BalloonEditor换成其他编辑器类型如ClassicEditor同样适用。Common API 速查WordCount插件对外提供的核心 API 汇总如下详见 packages/ckeditor5-word-count/src/wordcount.tsAPI类型说明wordCountContainer属性HTMLElement自更新容器元素随内容变化刷新数字可通过displayWords/displayCharacters隐藏其中部分计数器words可观察属性number当前单词数直接访问即精确计算characters可观察属性number当前字符数直接访问即精确计算update事件统计更新后触发参数为{ words, characters }节流触发config.wordCount.onUpdate配置回调通过配置注册的等价回调config.wordCount.container配置HTMLElement自动注入容器的目标元素config.wordCount.displayWords/displayCharacters配置boolean控制输出容器中对应计数器的显示此外插件还导出了内部工具modelElementToPlainText()以_modelElementToPlainText名义导出见 packages/ckeditor5-word-count/src/index.ts如需在自定义逻辑中复用模型转纯文本能力可以参考它。相关功能CKEditor 5 中与字数统计搭配使用效果更佳的生产力功能还包括拼写与语法检查在输入过程中追踪并纠正可能的错误自动保存Autosave自动保存内容避免意外丢失自动格式化Autoformat使用 Markdown 语法加速编辑流程自动文本替换Autocorrect将预定义的输入片段自动转换为改进形式。开发调试时官方推荐使用 CKEditor 5 Inspector 查看编辑器内部数据模型、选区与命令状态配合本文的update事件观察统计更新时机可以更直观地理解节流行为。小结Word Count 是 CKEditor 5 中实现内容篇幅控制的基础功能模型层统计逻辑纯文本转换 Unicode 正则分词 换行分隔保证了多语言与多根文档场景下的准确性wordCountContainer与config.wordCount.container两种注入方式覆盖了不同页面布局需求update事件250ms 节流适合驱动 UI 反馈而words/characters属性提供按需的精确取值。结合本文的 120 字符限制示例你可以直接构建字数提示、字符上限校验、发布按钮禁用等完整的写作辅助体验。【免费下载链接】ckeditor5Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.项目地址: https://gitcode.com/GitHub_Trending/ck/ckeditor5创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考