父页面摸不到的编辑器:跨域 iframe 里往 CodeMirror 6 灌正文
一、问题长什么样
写文章页面的正文区是个 iframe,地址指向 CDN 上的编辑器门户(HDMDEditorPortal 1.0.5)。它的 .cm-content 是 CodeMirror 6 的可编辑区,但父页面 document.querySelector 永远返回 null——跨域隔离生效,连 contentDocument 都是 null。
直接给外层容器设 innerHTML 更没用:CM6 的文档模型和 DOM 是双向同步的,绕过模型改 DOM,下一次视图刷新就被覆盖回去,父页面拿到的仍是空内容。
二、为什么粘贴能行
CM6 监听的是输入事件而不是 DOM 变更。剪贴板粘贴走的是 paste 事件,编辑器从中读 clipboardData.getData('text/plain'),再走自己的事务(transaction)插进文档模型。这条路径和用户按 Ctrl+V 完全一致,所以行号、撤销栈、变更通知全都正常。
关键是:event.isTrusted 为 false 不影响 CM6 处理,它没有做可信性校验。
三、具体做法
在 iframe 的上下文里执行:取 .cm-content 并 focus,构造 new DataTransfer(),setData('text/plain', text),再 new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }) 派发到该元素。返回值是 false 就说明事件的默认行为被 preventDefault 了,也就是编辑器吃下了这次粘贴。
验证方法不要看 DOM 文本长度(CM6 把换行渲染成块,textContent 会拼接),要看行数:document.querySelectorAll('.cm-line').length,以及父页面状态栏的字数计数器。
四、几个容易错的点
第一,必须先 focus,否则某些实现会把内容丢到 document 级而不是编辑器。第二,粘贴后父页面的计数器可能滞后,因为它靠 iframe postMessage 更新,等一两秒再断言。第三,中文全角标点在 JSON 里没问题,但如果你走的是命令行传参,注意编码,先确认文本字节数是预期值。
还有一个坑:如果编辑器内部对粘贴做了纯文本清洗(去掉多个空行),最终字数会略小于原文,这属于正常,不要拿字数相等当断言。
五、更稳的替代方案
如果目标是长期自动化,优先找页面暴露的 API(比如编辑器门户自己提供的 setContent 消息协议),其次是模拟真实键盘输入。合成事件属于中间方案:比逐字输入快得多,又比直接改 DOM 可靠。
真要长期维护,务必在脚本里加一条断言:粘贴后行数 > 0 且字数 > 阈值,否则直接失败退出,不要带着空正文去点发布。
- 点赞
- 收藏
- 关注作者
评论(0)