TOAST UI Editor 工具栏定制完全指南:从默认选项到自定义按钮与状态联动
TOAST UI Editor 工具栏定制完全指南从默认选项到自定义按钮与状态联动【免费下载链接】tui.editor Markdown WYSIWYG Editor. GFM Standard Chart UML Extensible.项目地址: https://gitcode.com/gh_mirrors/tu/tui.editorTOAST UI Editor以下简称“编辑器”以 Markdown 与 WYSIWYG 双模式为核心而工具栏正是这两类编辑体验的交互枢纽在 Markdown 语法不直观的所见即所得模式中绝大多数操作都依赖工具栏完成。本文将围绕官方文档《Toolbar》展开完整讲解toolbarItems二维数组配置、内建按钮定制、popup弹层选项、el自定义元素、state状态联动与onUpdated回调并深入仓库源码验证其底层实现帮助你掌握从“组合默认按钮”到“编写完整自定义工具栏插件”的全套能力。工具栏选项Toolbar Option编辑器内置了 bold、italic、strike 等总计 16 种工具栏元素。在不指定任何选项时默认工具栏配置如下const options { // ... toolbarItems: [ [heading, bold, italic, strike], [hr, quote], [ul, ol, task, indent, outdent], [table, image, link], [code, codeblock], [scrollSync], ], }从示例代码可以看到编辑器的工具栏选项以二维数组的形式定义第一层数组的每个元素是一个工具栏分组group分组内的工具栏元素则作为内层数组的元素。各元素按照定义顺序在分组内渲染而工具栏分组之间以|分隔线符号隔开渲染。16 种内建工具栏元素速查结合 toolbarItemFactory.ts 中的createDefaultToolbarItemInfo实现默认支持的 16 种元素及其默认绑定的命令、tooltip 与 state 如下表所示元素名默认命令command默认 tooltipen状态stateheading弹层插入标题HeadingsheadingboldboldBoldstrongitalicitalicItalicemphstrikestrikeStrikestrikehrhrLinethematicBreakquoteblockQuoteBlockquoteblockQuoteulbulletListUnordered listbulletListolorderedListOrdered listorderedListtasktaskListTasktaskListtable弹层插入表格Insert tabletableimage弹层插入图片Insert image—link弹层插入链接Insert link—codecodeCodecodecodeblockcodeBlockInsert CodeBlockcodeBlockindentindentIndentindentoutdentoutdentOutdentoutdentscrollSynctoggleScrollSync——注scrollSync是一个特殊的切换式元素其内部渲染为复选框 开关switch而非按钮相关实现见 toolbarItemFactory.ts同时它并非总是显示——当编辑器处于 WYSIWYG 模式或预览样式为tab时scrollSync会被隐藏见 toolbar.ts。此外超过一行显示宽度的元素会自动收进 “More更多” 下拉工具栏中见 toolbar.ts。重新组合默认工具栏如果想修改默认工具栏的构成只需在创建编辑器时传入toolbarItems选项const editor new Editor({ el: document.querySelector(#editor), toolbarItems: [ [heading, bold], [ul, ol, task], [code, codeblock], ], });执行上面的示例代码后工具栏会按新配置渲染为三个分组。从源码上看toolbarItems的类型为(string | ToolbarItemOptions)[][]见 editor.d.ts即每个元素既可以是内建按钮的字符串名称也可以是一个自定义选项对象——这正是接下来要讲的定制入口。工具栏按钮定制Toolbar Button Customizing单纯组合默认元素只能满足基础需求。当需要自己创建并添加工具栏按钮时编辑器提供两大类型的定制选项一是复用内建按钮 UI仅重定义图标、tooltip 或弹层行为二是完全自定义 DOM 元素。内建按钮元素定制Button Element Customizing这种方式仍然使用编辑器内建的按钮渲染逻辑只覆盖按钮的图标、tooltip 或 popup 行为。对应的选项接口如下名称类型说明namestring工具栏元素的唯一名称必填。tooltipstring可选。鼠标悬停在工具栏元素上时显示的提示文字。textstring可选。需要在工具栏按钮元素上显示的文本。classNamestring可选。应用到工具栏元素上的 class。styleObject可选。应用到工具栏元素上的行内样式。commandstring可选。点击工具栏按钮时要执行的命令。与popup选项互斥。popupPopupOptions可选。点击工具栏按钮时希望弹出的弹层。与command选项互斥。const editor new Editor({ el: document.querySelector(#editor), toolbarItems: [ [{ name: myItem, tooltip: myItem, command: bold, text: , className: toastui-editor-toolbar-icons, style: { backgroundImage: none, color: red } }] ], // ... });运行上面的示例后会生成一个同时应用了className与style的工具栏按钮按钮包含文本节点点击时执行bold命令。从实现层面看这类定制走的是 toolbarButton.ts 中的ToolbarButtonComp按钮渲染为button元素text作为按钮文本className与style直接拼入 class 与行内样式点击时如果存在command就调用execCommand(command)否则走弹层分支createPopupInfo见 toolbarButton.ts。需要特别注意的是text只影响按钮文本而不会替换图标字体示例中通过backgroundImage: none去掉图标字体背景、再用文本代替图标是一种常见的定制手法。popup 选项自定义弹层如果希望点击按钮时不是执行命令而是弹出自己定义的弹层则使用popup选项。其接口如下名称类型说明bodyHTMLElement要渲染的弹层 DOM 节点必填。classNamestring可选。应用到弹层元素上的 class。styleObject可选。应用到弹层元素上的样式。配置好的弹层节点会在点击工具栏时自动显示在屏幕上点击其他区域时自动消失。以编辑器的 color-syntax颜色选择插件代码为参考对应仓库实现见 color-syntax/src/index.ts 与 index.tsconst container document.createElement(div); // ... const button createApplyButton(i18n.get(OK)); button.addEventListener(click, () { // ... eventEmitter.emit(command, color, { selectedColor }); eventEmitter.emit(closePopup); }); container.appendChild(button); const colorPickerToolber { name: color, tooltip: Text color, className: some class, popup: { className: some class, body: container, style: { width: auto }, }, };示例代码将弹层要展示的元素放入变量container。该元素包含一个按钮点击时执行color命令并关闭弹层。这里展示了自定义弹层与编辑器通信的两条关键途径需要执行命令时通过eventEmitter.emit(command, color, { selectedColor })发出command事件需要关闭弹层时发出closePopup事件。从底层实现看自定义弹层最终会渲染为CustomPopupBody由createPopupInfo(customPopupBody, ...)处理见 toolbarItemFactory.ts而弹层的打开/关闭状态由 Toolbar 组件的showPopup状态统一管理点击弹层外部区域会触发hidePopup见 toolbar.ts。color-syntax 插件的完整示例可对照 color-syntax 插件源码 学习。工具栏元素定制Toolbar Item Customizing如果不使用内建按钮 UI而是希望完全自己控制渲染元素则需要指定el选项const myCustomEl document.createElement(span); myCustomEl.textContent ; myCustomEl.style cursor: pointer; background: red; myCustomEl.addEventListener(click, () { editor.exec(bold); }); const editor new Editor({ el: document.querySelector(#editor), toolbarItems: [ [{ name: myItem, tooltip: myItem, el: myCustomEl, }] ], // ... });由于el选项接收的是一个完整的 DOM 元素因此点击行为、style、class 等都必须由开发者自行设置。运行示例后工具栏会渲染出自定义的元素点击执行bold命令。在实现上带el的工具栏项会渲染为CustomToolbarItem它把自定义元素appendChild进一个带toolbar-item-wrapperclass 的容器中并自动为其挂上 tooltip 与 popup 事件监听见 customToolbarItem.ts。分组渲染时ToolbarGroup会依据“是否存在el”来区分渲染CustomToolbarItem还是ToolbarButton见 toolbarGroup.ts。除el外ToolbarCustomOptions还额外支持hidden、onMounted两个仅在自定义元素下可用的选项见 ui.d.ts其中onMounted(execCommand)会在元素挂载完成后被调用可用来绑定需要执行命令的复杂交互如 scrollSync 元素的自定义复选框逻辑见 toolbarItemFactory.ts。工具栏状态变更Change Toolbar Item State编辑器可以根据当前光标所在位置对应的节点类型通过改变工具栏元素样式来“点亮”对应按钮。例如当光标位于加粗文本strong节点上时bold工具栏元素会被激活追加active类。若希望自定义的工具栏元素也能随光标位置切换状态则需要配置state选项const editor new Editor({ el: document.querySelector(#editor), toolbarItems: [ [{ name: myItem, tooltip: myItem, command: bold, text: , className: toastui-editor-toolbar-icons, style: { backgroundImage: none, color: red }, // 光标位于 strong 节点时该工具栏元素会被追加 active 类 state: strong, }] ], // ... });当工具栏按钮依据state被激活时编辑器会为其追加activeCSS 类之后即可基于该类编写自定义激活样式。按钮激活类拼接发生在 toolbarButton.ts${item.className || }${active ? active : }。state 列表只有使用下列 state 值才能改变工具栏元素的激活状态heading标题strong加粗emph斜体strike删除线thematicBreak水平分隔线blockQuote引用块bulletList无序列表orderedList有序列表taskList任务列表table表格code行内代码codeBlock代码块从类型定义看state的类型是ToolbarStateKeys即上述键的联合类型同时底层状态映射ToolbarStateMap还额外包含indent、outdent两项见 ui.d.ts与默认元素indent/outdent一一对应。状态联动的底层原理工具栏状态不是凭空产生的而是由 WYSIWYG 编辑器内的 ProseMirror 插件实时计算并广播的。在 toolbarState.ts 中toolbarStateHighlight插件在每次文档选择selection更新时调用getToolbarState(selection, doc, schema)遍历光标范围内的节点位于listItem时根据node.attrs.task判定为taskList或父级列表类型节点类型包含table时归一化为table对strong、strike、emph、code四种 mark 类型检查选区两侧是否存在对应 mark其余节点类型直接作为 state 键标记为{ active: true }。计算结果通过eventEmitter.emit(changeToolbarState, { toolbarState })广播出去。而在 UI 侧buttonHoc.ts 中每个带state的按钮都会listen(changeToolbarState)从toolbarState[item.state]中取出{ active, disabled }并更新自身状态——这就是光标移动时按钮实时点亮的完整调用链。onUpdated() 选项自定义元素的状态回调使用el选项创建工具栏元素时由于编辑器无法直接操纵你传入的 DOM必须借助onUpdated回调来响应状态变化const myCustomEl document.createElement(span); myCustomEl.textContent ; myCustomEl.style cursor: pointer; background: red; myCustomEl.addEventListener(click, () { editor.exec(bold); }); const editor new Editor({ el: document.querySelector(#editor), toolbarItems: [ [{ name: myItem, tooltip: myItem, el: myCustomEl, state: strong, onUpdated({ active, disabled }) { if (active) { myCustomEl.style.background green; } else { myCustomEl.style.background ; } } }] ], // ... });onUpdated()接收一个包含active、disabled状态的对象作为参数可据此为元素追加样式或定义任意行为。其触发时机在 customToolbarItem.ts当active或disabled与前一次渲染不同时调用item.onUpdated?.({ active, disabled })。注意disabled与active可能同时出现例如列表内indent/outdent的禁用态状态对象类型见 ui.d.ts。动态增删工具栏项insertToolbarItem 与 removeToolbarItem除初始化配置外编辑器还提供了运行时 APIeditor.insertToolbarItem({ groupIndex, itemIndex }, item)向指定分组的指定位置插入一个工具栏项字符串或选项对象editor.removeToolbarItem(itemName)按name移除工具栏项。两个 API 的类型声明见 editor.d.ts实现位于 toolbar.tsinsertToolbarItem会先通过createToolbarItemInfo把字符串规范化为选项对象再在对应分组splice插入若分组索引越界则新建分组。结合 example15-customizing-toolbar-buttons.html 可以看到完整用法——该示例在初始化工具栏后又通过insertToolbarItem在第一个分组的最前面动态插入了一个自定义的按钮并配合firstclass 实现红色样式。完整实战示例官方提供了可运行的示例 example15-customizing-toolbar-buttons.html其中综合展示了三种定制手段function createLastButton() { const button document.createElement(button); button.className toastui-editor-toolbar-icons last; button.style.backgroundImage none; button.style.margin 0; button.innerHTML iB/i; button.addEventListener(click, () { editor.exec(bold); }); return button; } const editor new toastui.Editor({ el: document.querySelector(#editor), previewStyle: vertical, height: 500px, initialValue: The first and last buttons are customized., toolbarItems: [ [heading, bold, italic, strike], [hr, quote], [ul, ol, task, indent, outdent], [table, image, link], [code, codeblock], // 用 el 选项定制“最后一个”按钮 [{ el: createLastButton(), command: bold, tooltip: Custom Bold }] ] }); editor.insertToolbarItem({ groupIndex: 0, itemIndex: 0 }, { name: myItem, tooltip: Custom Button, command: bold, text: , className: toastui-editor-toolbar-icons first, style: { backgroundImage: none } });该示例在编辑器初始化后动态插入“第一个”按钮使用insertToolbarItem并在toolbarItems中配置了“最后一个”按钮使用el自定义元素配合样式表中.toastui-editor-defaultUI button.first { color: red; }与.last { color: orange; }的定制样式直观演示了本节所有 API 的组合用法。小结工具栏是 TOAST UI Editor 中交互密度最高的组件。通过toolbarItems二维数组可以自由重组 16 种内建元素通过command/popup选项可以复用内建按钮 UI 定制点击行为通过el选项可以完全接管渲染元素通过stateonUpdated可以实现随光标位置实时点亮的动态状态再配合insertToolbarItem/removeToolbarItem两个运行时 API即可打造出高度贴合业务场景的定制工具栏。【免费下载链接】tui.editor Markdown WYSIWYG Editor. GFM Standard Chart UML Extensible.项目地址: https://gitcode.com/gh_mirrors/tu/tui.editor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

用 @eggjs/typebox-validate 在 Egg + TypeScript 中实现“写一遍类型“的参数校验

用 @eggjs/typebox-validate 在 Egg + TypeScript 中实现“写一遍类型“的参数校验

用 eggjs/typebox-validate 在 Egg TypeScript 中实现"写一遍类型"的参数校验 【免费下载链接】egg 🥚🥚🥚🥚 Born to build better enterprise frameworks and apps with Node.js & Koa. https://307.run/eggcode…

2026/9/21 16:14:16 阅读更多 →
SpringBoot车辆管理系统:架构设计与性能优化实战

SpringBoot车辆管理系统:架构设计与性能优化实战

1. 项目概述:SpringBoot车辆管理系统的核心价值这个基于SpringBoot的车辆管理系统(项目编号11749)是典型的工业级企业资产管理解决方案。我在物流行业实施过类似系统,它本质上是通过数字化手段解决传统车辆管理中的三大痛点&#…

2026/9/21 16:14:16 阅读更多 →
Ubuntu 20.04 离线安装 Realtek b852 网卡驱动实战指南

Ubuntu 20.04 离线安装 Realtek b852 网卡驱动实战指南

1. 为什么离线装网卡驱动是个绕不开的坎如果你正在一台没有有线网络、也没有其他可用无线网卡的机器上折腾 Ubuntu 20.04,恰好手里这块 Realtek b852 又没被内核自带驱动认出来,那你大概率已经体会过那种“装系统五分钟,配网络两小时”的窒息…

2026/9/21 16:14:16 阅读更多 →

最新新闻

Presto Exchange Materialization 实战指南:以物化 Shuffle 突破 MPP 内存瓶颈

Presto Exchange Materialization 实战指南:以物化 Shuffle 突破 MPP 内存瓶颈

大数据数据库后端 【免费下载链接】presto The official home of the Presto distributed SQL query engine for big data 项目地址: https://gitcode.com/gh_mirrors/pre/presto 点击查看 免费下载 Exchange Materialization 是 Presto 为内存密集型查询提供的一种…

2026/9/21 16:39:36 阅读更多 →
MCP Python SDK 服务端订阅机制全解析:从 `subscriptions/listen` 到跨进程扩展

MCP Python SDK 服务端订阅机制全解析:从 `subscriptions/listen` 到跨进程扩展

人工智能MCP 服务MCP Clients 【免费下载链接】python-sdk The official Python SDK for Model Context Protocol servers and clients 项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk 点击查看 免费下载 本篇文章以 Model Context Protocol 官方 …

2026/9/21 16:39:36 阅读更多 →
Cluster Scorecard: [Seed Keyword]

Cluster Scorecard: [Seed Keyword]

【免费下载链接】claude-seo Universal SEO skill for Claude Code. 25 sub-skills 18 sub-agents covering technical SEO, E-E-A-T, schema, GEO/AEO, backlinks, local SEO, maps intelligence, semantic clustering, e-commerce SEO, international SEO, Google APIs, and…

2026/9/21 16:39:36 阅读更多 →
Diem Swiss Knife 实战指南:BCS 序列化交易生成、签名与验证命令行工具

Diem Swiss Knife 实战指南:BCS 序列化交易生成、签名与验证命令行工具

Diem Swiss Knife 实战指南:BCS 序列化交易生成、签名与验证命令行工具 【免费下载链接】diem Diem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world. 项目地址: https://gitcode.com/…

2026/9/21 16:39:36 阅读更多 →
easy-vibe 跨平台开发技术全景:React Native / Flutter / Electron / Tauri 架构流派与选型实战指南

easy-vibe 跨平台开发技术全景:React Native / Flutter / Electron / Tauri 架构流派与选型实战指南

教程文档 【免费下载链接】easy-vibe 从 0 到 1 学会 vibe coding,项目制学习 项目地址: https://gitcode.com/datawhalechina/easy-vibe 点击查看 免费下载 "Write once, run anywhere"(一次编写,处处运行&#xff09…

2026/9/21 16:39:36 阅读更多 →
VitePress 自定义主题完全指南:从零构建、分发与消费自己的主题

VitePress 自定义主题完全指南:从零构建、分发与消费自己的主题

前端文档 【免费下载链接】vitepress Vite & Vue powered static site generator. 项目地址: https://gitcode.com/gh_mirrors/vi/vitepress 点击查看 免费下载 VitePress 默认主题开箱即用,但当你需要完全掌控站点的外观与交互时,自定义…

2026/9/21 16:38:36 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →