QuillJS copyCode插件报错:Failed to execute 'insertBefore' on 'Node'
Fixing "Failed to execute 'insertBefore' on 'Node'" in QuillJS CopyCode Plugin
I’ve dug into your issue, and you’re spot-on about the root cause: Quill expects code-blocks (the <pre> elements) to be direct children of its content container, but your plugin was wrapping them in an extra <div class="ql-container">—this breaks Quill’s internal DOM management. When you add space between text and the code block, Quill tries to manipulate the DOM nodes but can’t find the structure it expects, hence the error.
Here’s how to fix this without disrupting Quill’s core DOM rules:
Key Changes
- Ditch the extra container wrapper entirely—we don’t need it. Instead, position the copy badge relative to the code block directly using CSS.
- Adjust the badge insertion logic to add it as a sibling to the code block, never moving the code block itself.
- Remove all container-related methods since we’re no longer using that wrapper.
Modified Code
const copyContentIntoClipboard = (rawData: string) => { const encodedContent = encodeURIComponent(rawData); const filteredEncodedContent = encodedContent.replace(/%EF%BB%BF/g, ""); const targetContent = decodeURIComponent(filteredEncodedContent); const tmpHolder = document.createElement("textarea"); tmpHolder.value = targetContent; document.body.appendChild(tmpHolder); tmpHolder.select(); document.execCommand("copy"); document.body.removeChild(tmpHolder); }; const CodeBlock = Quill.import("formats/code-block"); class CopyCode extends CodeBlock { copyBadge: HTMLDivElement | null; domNode: HTMLElement; copyHandler: EventListener; _mountBadge() { const copyBadge = document.createElement("div"); copyBadge.contentEditable = "false"; copyBadge.classList.add("ql-badge", "ql-badge-copy"); copyBadge.textContent = "copy"; // Insert badge as a sibling right after the code block this.domNode.parentElement?.insertBefore( copyBadge, this.domNode.nextSibling ); /* Add this CSS to your stylesheet to position the badge over the code block: .ql-editor pre { position: relative; padding-top: 32px; /* Make space for the badge at the top */ } .ql-badge-copy { position: absolute; top: 8px; right: 8px; background: #f0f0f0; padding: 4px 8px; border-radius: 4px; cursor: pointer; user-select: none; } */ const copyHandler = (e: MouseEvent) => { e.stopPropagation(); e.preventDefault(); const copyCode = this.domNode.textContent?.trim() || ''; copyBadge.textContent = "copied!"; setTimeout(() => { copyBadge.textContent = "copy"; }, 2000); copyContentIntoClipboard(copyCode); }; copyBadge.addEventListener("click", copyHandler, true); this.copyHandler = copyHandler; this.copyBadge = copyBadge; } _dismountBadge() { if (this.copyBadge && this.copyBadge.parentElement) { this.copyBadge.removeEventListener("click", this.copyHandler, true); this.copyBadge.parentElement.removeChild(this.copyBadge); } this.copyBadge = null; this.copyHandler = () => {}; } insertInto(...args: any) { super.insertInto(...args); const allowCustomMount = !this.copyBadge && this.parent; if (allowCustomMount) { this._mountBadge(); } } remove() { this._dismountBadge(); super.remove(); } }
Why This Works
- We never move Quill’s native code-block node (
this.domNode), so Quill can maintain its internal DOM state correctly during edits like adding spaces between text and code blocks. - The copy badge is added as a sibling node, and CSS positions it over the code block without altering Quill’s expected structure.
- All container-related logic is removed, eliminating the DOM manipulation that caused the conflict with Quill’s internal operations.
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

