closest()最适合判断光标或选区是否已在加粗语义节点内,通过向上查找strong、b、[style*="bold"]或.text-bold等匹配节点,结合选区宿主节点校验实现精准加粗/取消逻辑。

点击加粗按钮前,不需要先“检查选区是否已在加粗块内”,而是应该检查光标或选区所在的最近的语义容器节点是否已具备加粗样式(如 <strong>、<b> 或含 font-weight: bold 的内联元素),这正是 closest() 最适合的场景。
用 closest 定位最近的加粗语义节点
closest() 作用是沿 DOM 向上查找第一个匹配选择器的祖先(含自身),它比手动遍历 parentElement 更简洁、更健壮。关键在于:你不是检查“选区是否跨多个节点”,而是快速判断当前编辑位置是否已经处于加粗上下文中。
- 若用户光标在
<p><strong>hello</strong> world</p>的 “world” 上,closest('strong, b')返回null—— 说明此处未加粗,可执行加粗 - 若光标在 “hello” 中,
closest('strong, b')返回该<strong>元素 —— 表示已在加粗块内,此时可考虑取消加粗或忽略操作 - 支持扩展:加入
[style*="bold"]或自定义 class 如.text-bold,覆盖 CSS 驱动的加粗场景
结合选区获取与 closest 判断
不能只靠 closest(),必须先从选区提取有效宿主节点:
- 调用
window.getSelection(),取getRangeAt(0) - 对
range.startContainer调用closest();若为文本节点,用startContainer.parentElement再查 - 若选区跨多节点(如同时选中两个
<span>),closest()对每个节点分别判断,统一策略:只要任一节点已加粗,就视为“已在加粗块内”
加粗按钮逻辑中的实际判断流程
点击后立即执行以下判断链,closest() 是其中轻量但关键的一环:
- 确认选区存在且位于
contenteditable区域内 - 获取 range 起点所在的有效元素节点(跳过 #text、#comment 等)
- 对该节点调用
.closest('strong, b, [style*="bold"], .font-bold, .text-bold') - 若有匹配结果:执行“取消加粗”(unwrap 或移除 class/style);否则执行“添加加粗”
- 避免误判:若节点是
<pre>、<code>或带data-readonly,直接跳过,不依赖closest结果
注意边界情况
closest() 本身不处理空选区或跨块问题,需前置校验:
- 光标在空行(
<p><br></p>)时,startContainer可能是<br>,需 fallback 到其父<p>再查 - Safari 下某些嵌套结构中
startContainer可能为 document,应 guard 判空 - 不要仅凭
closest('strong')为null就认定“可加粗”——还需确认该位置允许插入<strong>(如不在表格单元格或 widget 内)

















