Browse Source

:zap: wysiwyg 性能优化

Liyuan Li 5 years ago
parent
commit
9926bf912a

+ 1 - 1
demo/index.js

@@ -4,7 +4,7 @@ import '../src/assets/scss/index.scss'
 window.vditor = new Vditor('vditor', {
   debugger: true,
   typewriterMode: true,
-  mode: 'ir',
+  // mode: 'ir',
   placeholder: 'placeholder',
   preview: {
     markdown: {

+ 4 - 44
src/assets/scss/_wysiwyg.scss

@@ -45,52 +45,16 @@
     content: ' ';
   }
 
-  code {
+  code[data-marker="`"] {
     padding-left: 0 !important;
     padding-right: 0 !important;
   }
 
-  &__block {
-    &[data-type="html-block"] {
-      & > pre {
-        margin-bottom: 0;
-      }
-
-      .vditor-wysiwyg__preview {
-        background-color: var(--preview-background-color);
-      }
-    }
+  &__block pre:first-child {
+    margin-bottom: -1em;
 
     code {
-      padding: 0.2em 0.4em !important;
-    }
-
-    & > code {
-      display: none;
-    }
-
-    & > pre {
-      margin-bottom: -1em;
-      display: none;
-
-      & > code {
-        overflow: auto !important;
-        display: block;
-
-        &.language-mermaid,
-        &.language-graphviz,
-        &.language-math,
-        &.language-echarts {
-          background-color: var(--code-background-color) !important;
-        }
-      }
-    }
-
-    &[data-type=html-inline] .vditor-wysiwyg__preview svg {
-      fill: var(--second-color);
-      height: 12px;
-      cursor: pointer;
-      width: 12px;
+      background-color: var(--code-background-color) !important;
     }
   }
 
@@ -102,10 +66,6 @@
     code:not(.hljs):not(.highlight-chroma) {
       background-color: var(--preview-background-color);
     }
-
-    pre {
-      margin-bottom: 1em !important;
-    }
   }
 
   h1:before,

+ 14 - 10
src/ts/hint/index.ts

@@ -1,13 +1,12 @@
 import {Constants} from "../constants";
 import {processAfterRender} from "../ir/process";
-import {processCodeRender as processIRCodeRender} from "../ir/process";
 import {formatRender} from "../sv/formatRender";
 import {code160to32} from "../util/code160to32";
 import {getMarkdown} from "../util/getMarkdown";
 import {hasClosestByAttribute, hasClosestByClassName} from "../util/hasClosest";
+import {processCodeRender} from "../util/processCode";
 import {getCursorPosition, getSelectPosition, insertHTML, setSelectionFocus} from "../util/selection";
-import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
-import {processCodeRender} from "../wysiwyg/processCodeRender";
+import {execAfterRender} from "../util/fixBrowserBehavior";
 
 export class Hint {
     public timeId: number;
@@ -147,7 +146,7 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
                     preBeforeElement.parentElement.querySelectorAll("code").forEach((item) => {
                         item.className = "language-" + value.trimRight();
                     });
-                    processIRCodeRender(preBeforeElement.parentElement.querySelector(".vditor-ir__preview"), vditor);
+                    processCodeRender(preBeforeElement.parentElement.querySelector(".vditor-ir__preview"), vditor);
                     this.recentLanguage = value.trimRight();
                     return;
                 }
@@ -175,14 +174,19 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
             setSelectionFocus(range);
 
             if (vditor.currentMode === "wysiwyg") {
-                const blockRenderElement = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__block");
-                if (blockRenderElement) {
-                    processCodeRender(blockRenderElement, vditor);
-                }
-                afterRenderEvent(vditor);
+                 const preElement = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__block");
+                 if (preElement) {
+                     preElement.lastElementChild.innerHTML = preElement.firstElementChild.innerHTML
+                     processCodeRender(preElement.lastElementChild as HTMLElement, vditor);
+                 }
             } else {
-                processAfterRender(vditor);
+                const preElement = hasClosestByClassName(range.startContainer, "vditor-ir__marker--pre");
+                if (preElement) {
+                    preElement.nextElementSibling.innerHTML = preElement.innerHTML;
+                    processCodeRender(preElement.nextElementSibling as HTMLElement, vditor);
+                }
             }
+            execAfterRender(vditor);
         } else {
             const position = getSelectPosition(vditor.sv.element, range);
             const text = getMarkdown(vditor);

+ 4 - 6
src/ts/ir/index.ts

@@ -3,7 +3,7 @@ import {setHeaders} from "../upload/setHeaders";
 import {isCtrl, isFirefox} from "../util/compatibility";
 import {focusEvent, hotkeyEvent, scrollCenter, selectEvent} from "../util/editorCommenEvent";
 import {hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
-import {processPasteCode} from "../util/processPasteCode";
+import {processCodeRender, processPasteCode} from "../util/processCode";
 import {
     getSelectPosition,
     insertHTML,
@@ -13,7 +13,7 @@ import {
 import {expandMarker} from "./expandMarker";
 import {highlightToolbar} from "./highlightToolbar";
 import {input} from "./input";
-import {processAfterRender, processCodeRender, processHint} from "./process";
+import {processAfterRender, processHint} from "./process";
 
 class IR {
     public element: HTMLPreElement;
@@ -90,10 +90,8 @@ class IR {
                     + textPlain + codeElement.textContent.substring(position.end);
                 setSelectionByPosition(position.start + textPlain.length, position.start + textPlain.length,
                     codeElement.parentElement);
-                const previewElement =
-                    codeElement.parentElement.parentElement.querySelector(".vditor-ir__preview") as HTMLElement;
-                previewElement.innerHTML = codeElement.outerHTML;
-                processCodeRender(previewElement, vditor);
+                codeElement.parentElement.nextElementSibling.innerHTML = codeElement.outerHTML;
+                processCodeRender(codeElement.parentElement.nextElementSibling as HTMLElement, vditor);
             } else if (code) {
                 document.execCommand("insertHTML", false, code);
             } else {

+ 2 - 1
src/ts/ir/input.ts

@@ -1,8 +1,9 @@
 import {isHeadingMD, isHrMD} from "../util/fixBrowserBehavior";
 import {getTopList, hasClosestBlock, hasClosestByClassName, hasClosestByTag} from "../util/hasClosest";
 import {log} from "../util/log";
+import {processCodeRender} from "../util/processCode";
 import {getSelectPosition, setRangeByWbr} from "../util/selection";
-import {processAfterRender, processCodeRender} from "./process";
+import {processAfterRender} from "./process";
 
 export const input = (vditor: IVditor, range: Range) => {
     let blockElement = hasClosestBlock(range.startContainer);

+ 0 - 37
src/ts/ir/process.ts

@@ -1,11 +1,4 @@
 import {Constants} from "../constants";
-import {abcRender} from "../markdown/abcRender";
-import {chartRender} from "../markdown/chartRender";
-import {codeRender} from "../markdown/codeRender";
-import {graphvizRender} from "../markdown/graphvizRender";
-import {highlightRender} from "../markdown/highlightRender";
-import {mathRender} from "../markdown/mathRender";
-import {mermaidRender} from "../markdown/mermaidRender";
 import {isSafari} from "../util/compatibility";
 import {listToggle} from "../util/fixBrowserBehavior";
 import {getMarkdown} from "../util/getMarkdown";
@@ -78,36 +71,6 @@ export const processAfterRender = (vditor: IVditor, options = {
     }, 800);
 };
 
-export const processCodeRender = (previewPanel: HTMLElement, vditor: IVditor) => {
-    const codeElement = previewPanel.querySelector("code");
-    if (!codeElement) {
-        return;
-    }
-    const language = codeElement.className.replace("language-", "");
-    if (language === "abc") {
-        abcRender(previewPanel, vditor.options.cdn);
-    } else if (language === "mermaid") {
-        mermaidRender(previewPanel, ".vditor-ir__preview .language-mermaid", vditor.options.cdn);
-    } else if (language === "echarts") {
-        chartRender(previewPanel, vditor.options.cdn);
-    } else if (language === "graphviz") {
-        graphvizRender(previewPanel, vditor.options.cdn);
-    } else if (language === "math") {
-        let tag = "div";
-        if (previewPanel.tagName === "SPAN") {
-            tag = "span";
-        }
-        previewPanel.innerHTML = `<code class="language-math"><${tag} class="vditor-math">${previewPanel.innerHTML}</${tag}></code>`;
-        mathRender(previewPanel.parentElement, {cdn: vditor.options.cdn, math: vditor.options.preview.math});
-    } else {
-        highlightRender(Object.assign({}, vditor.options.preview.hljs, {enable: true}),
-            previewPanel, vditor.options.cdn);
-        codeRender(previewPanel, vditor.options.lang);
-    }
-
-    previewPanel.setAttribute("data-render", "1");
-};
-
 export const processHeading = (vditor: IVditor, value: string) => {
     const range = getSelection().getRangeAt(0);
     const headingElement = hasClosestBlock(range.startContainer) || range.startContainer as HTMLElement;

+ 1 - 1
src/ts/sv/html2md.ts

@@ -1,5 +1,5 @@
 import {setHeaders} from "../upload/setHeaders";
-import {processPasteCode} from "../util/processPasteCode";
+import {processPasteCode} from "../util/processCode";
 import {insertText} from "./insertText";
 import {setSelectionByInlineText} from "./setSelection";
 

+ 2 - 1
src/ts/toolbar/EditMode.ts

@@ -1,11 +1,12 @@
 import editSVG from "../../assets/icons/edit.svg";
 import {Constants} from "../constants";
 import {i18n} from "../i18n";
-import {processAfterRender, processCodeRender} from "../ir/process";
+import {processAfterRender} from "../ir/process";
 import {formatRender} from "../sv/formatRender";
 import {setPadding} from "../ui/initUI";
 import {getEventName, updateHotkeyTip} from "../util/compatibility";
 import {getMarkdown} from "../util/getMarkdown";
+import {processCodeRender} from "../util/processCode";
 import {renderDomByMd} from "../wysiwyg/renderDomByMd";
 import {MenuItem} from "./MenuItem";
 import {enableToolbar, hidePanel, hideToolbar, removeCurrentToolbar, showToolbar} from "./setToolbar";

+ 2 - 2
src/ts/undo/WysiwygUndo.ts

@@ -3,10 +3,10 @@ import {disableToolbar} from "../toolbar/setToolbar";
 import {enableToolbar} from "../toolbar/setToolbar";
 import {isFirefox, isSafari} from "../util/compatibility";
 import {scrollCenter} from "../util/editorCommenEvent";
+import {processCodeRender} from "../util/processCode";
 import {setRangeByWbr, setSelectionFocus} from "../util/selection";
 import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
 import {highlightToolbar} from "../wysiwyg/highlightToolbar";
-import {processCodeRender} from "../wysiwyg/processCodeRender";
 
 class WysiwygUndo {
     private undoStack: patch_obj[][];
@@ -143,7 +143,7 @@ class WysiwygUndo {
         this.lastText = text;
 
         vditor.wysiwyg.element.innerHTML = text;
-        vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__block").forEach((blockElement: HTMLElement) => {
+        vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__preview[data-render='2']").forEach((blockElement: HTMLElement) => {
             processCodeRender(blockElement, vditor);
         });
         setRangeByWbr(vditor.wysiwyg.element, vditor.wysiwyg.element.ownerDocument.createRange());

+ 14 - 10
src/ts/util/fixBrowserBehavior.ts

@@ -1,8 +1,8 @@
 import {Constants} from "../constants";
 import {processAfterRender} from "../ir/process";
+import {processCodeRender} from "../util/processCode";
 import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
 import {highlightToolbar} from "../wysiwyg/highlightToolbar";
-import {processCodeRender} from "../wysiwyg/processCodeRender";
 import {isCtrl} from "./compatibility";
 import {scrollCenter} from "./editorCommenEvent";
 import {
@@ -186,11 +186,13 @@ export const listIndent = (vditor: IVditor, liElement: HTMLElement, range: Range
 
         setRangeByWbr(vditor[vditor.currentMode].element, range);
         const tempTopListElement = getTopList(range.startContainer);
-        if (tempTopListElement && vditor.currentMode === "wysiwyg") {
-            tempTopListElement.querySelectorAll(".vditor-wysiwyg__block")
-                .forEach((blockElement: HTMLElement) => {
-                    processCodeRender(blockElement, vditor);
-                    blockElement.firstElementChild.setAttribute("style", "display:none");
+        if (tempTopListElement) {
+            tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
+                .forEach((item: HTMLElement) => {
+                    processCodeRender(item, vditor);
+                    if (vditor.currentMode === "wysiwyg") {
+                        item.previousElementSibling.setAttribute("style", "display:none");
+                    }
                 });
         }
         execAfterRender(vditor);
@@ -234,10 +236,12 @@ export const listOutdent = (vditor: IVditor, liElement: HTMLElement, range: Rang
         setRangeByWbr(vditor[vditor.currentMode].element, range);
         const tempTopListElement = getTopList(range.startContainer);
         if (tempTopListElement) {
-            tempTopListElement.querySelectorAll(".vditor-wysiwyg__block")
-                .forEach((blockElement: HTMLElement) => {
-                    processCodeRender(blockElement, vditor);
-                    blockElement.firstElementChild.setAttribute("style", "display:none");
+            tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
+                .forEach((item: HTMLElement) => {
+                    processCodeRender(item, vditor);
+                    if (vditor.currentMode === "wysiwyg") {
+                        item.previousElementSibling.setAttribute("style", "display:none");
+                    }
                 });
         }
         execAfterRender(vditor);

+ 79 - 0
src/ts/util/processCode.ts

@@ -0,0 +1,79 @@
+import {abcRender} from "../markdown/abcRender";
+import {chartRender} from "../markdown/chartRender";
+import {codeRender} from "../markdown/codeRender";
+import {graphvizRender} from "../markdown/graphvizRender";
+import {highlightRender} from "../markdown/highlightRender";
+import {mathRender} from "../markdown/mathRender";
+import {mermaidRender} from "../markdown/mermaidRender";
+
+export const processPasteCode = (html: string, text: string, type = "sv") => {
+    const tempElement = document.createElement("div");
+    tempElement.innerHTML = html;
+    let isCode = false;
+    if (tempElement.childElementCount === 1 &&
+        (tempElement.lastElementChild as HTMLElement).style.fontFamily.indexOf("monospace") > -1) {
+        // VS Code
+        isCode = true;
+    }
+    const pres = tempElement.querySelectorAll("pre");
+    if (tempElement.childElementCount === 1 && pres.length === 1
+        && pres[0].className !== "vditor-wysiwyg"
+        && pres[0].className !== "vditor-textarea") {
+        // IDE
+        isCode = true;
+    }
+    if (html.indexOf('\n<p class="p1">') === 0) {
+        // Xcode
+        isCode = true;
+    }
+
+    if (isCode) {
+        const code = text || html;
+        if (/\n/.test(code) || pres.length === 1) {
+            if (type === "wysiwyg") {
+                return `<div class="vditor-wysiwyg__block" data-block="0" data-type="code-block"><pre><code>${
+                    code.replace(/&/g, "&amp;").replace(/</g, "&lt;")}<wbr></code></pre></div>`;
+            }
+            if (type === "ir") {
+                return "```\n" + code.replace(/&/g, "&amp;").replace(/</g, "&lt;") + "\n```";
+            }
+            return "```\n" + code + "\n```";
+        } else {
+            if (type === "wysiwyg") {
+                return `<code>${code.replace(/&/g, "&amp;").replace(/</g, "&lt;")}</code><wbr>`;
+            }
+            return `\`${code}\``;
+        }
+    }
+    return false;
+};
+
+export const processCodeRender = (previewPanel: HTMLElement, vditor: IVditor) => {
+    const codeElement = previewPanel.querySelector("code");
+    if (!codeElement) {
+        return;
+    }
+    const language = codeElement.className.replace("language-", "");
+    if (language === "abc") {
+        abcRender(previewPanel, vditor.options.cdn);
+    } else if (language === "mermaid") {
+        mermaidRender(previewPanel, `.vditor-${vditor.currentMode}__preview .language-mermaid`, vditor.options.cdn);
+    } else if (language === "echarts") {
+        chartRender(previewPanel, vditor.options.cdn);
+    } else if (language === "graphviz") {
+        graphvizRender(previewPanel, vditor.options.cdn);
+    } else if (language === "math") {
+        let tag = "div";
+        if (previewPanel.tagName === "SPAN") {
+            tag = "span";
+        }
+        previewPanel.innerHTML = `<code class="language-math"><${tag} class="vditor-math">${previewPanel.innerHTML}</${tag}></code>`;
+        mathRender(previewPanel.parentElement, {cdn: vditor.options.cdn, math: vditor.options.preview.math});
+    } else {
+        highlightRender(Object.assign({}, vditor.options.preview.hljs, {enable: true}),
+            previewPanel, vditor.options.cdn);
+        codeRender(previewPanel, vditor.options.lang);
+    }
+
+    previewPanel.setAttribute("data-render", "1");
+};

+ 0 - 41
src/ts/util/processPasteCode.ts

@@ -1,41 +0,0 @@
-export const processPasteCode = (html: string, text: string, type = "sv") => {
-    const tempElement = document.createElement("div");
-    tempElement.innerHTML = html;
-    let isCode = false;
-    if (tempElement.childElementCount === 1 &&
-        (tempElement.lastElementChild as HTMLElement).style.fontFamily.indexOf("monospace") > -1) {
-        // VS Code
-        isCode = true;
-    }
-    const pres = tempElement.querySelectorAll("pre");
-    if (tempElement.childElementCount === 1 && pres.length === 1
-        && pres[0].className !== "vditor-wysiwyg"
-        && pres[0].className !== "vditor-textarea") {
-        // IDE
-        isCode = true;
-    }
-    if (html.indexOf('\n<p class="p1">') === 0) {
-        // Xcode
-        isCode = true;
-    }
-
-    if (isCode) {
-        const code = text || html;
-        if (/\n/.test(code) || pres.length === 1) {
-            if (type === "wysiwyg") {
-                return `<div class="vditor-wysiwyg__block" data-block="0" data-type="code-block"><pre><code>${
-                    code.replace(/&/g, "&amp;").replace(/</g, "&lt;")}<wbr></code></pre></div>`;
-            }
-            if (type === "ir") {
-                return "```\n" + code.replace(/&/g, "&amp;").replace(/</g, "&lt;") + "\n```";
-            }
-            return "```\n" + code + "\n```";
-        } else {
-            if (type === "wysiwyg") {
-                return `<code>${code.replace(/&/g, "&amp;").replace(/</g, "&lt;")}</code><wbr>`;
-            }
-            return `\`${code}\``;
-        }
-    }
-    return false;
-};

+ 3 - 2
src/ts/wysiwyg/highlightToolbar.ts

@@ -19,9 +19,9 @@ import {
     hasClosestByTag,
     hasTopClosestByTag,
 } from "../util/hasClosest";
+import {processCodeRender} from "../util/processCode";
 import {getEditorRange, selectIsEditor, setRangeByWbr, setSelectionFocus} from "../util/selection";
 import {afterRenderEvent} from "./afterRenderEvent";
-import {processCodeRender} from "./processCodeRender";
 
 export const highlightToolbar = (vditor: IVditor) => {
     clearTimeout(vditor.wysiwyg.hlToolbarTimeoutId);
@@ -488,7 +488,8 @@ export const highlightToolbar = (vditor: IVditor) => {
                         codeElement.className.split("-")[1].split(" ")[0] : vditor.hint.recentLanguage;
                     language.oninput = () => {
                         updateLanguage();
-                        processCodeRender(blockRenderElement, vditor);
+                        blockRenderElement.lastElementChild.innerHTML = blockRenderElement.firstElementChild.innerHTML
+                        processCodeRender(blockRenderElement.lastElementChild as HTMLElement, vditor);
                         afterRenderEvent(vditor);
                     };
                     language.onkeydown = (event: KeyboardEvent) => {

+ 6 - 8
src/ts/wysiwyg/index.ts

@@ -7,7 +7,7 @@ import {
     hasClosestBlock, hasClosestByAttribute,
     hasClosestByClassName, hasClosestByHeadings, hasClosestByMatchTag,
 } from "../util/hasClosest";
-import {processPasteCode} from "../util/processPasteCode";
+import {processCodeRender, processPasteCode} from "../util/processCode";
 import {
     getEditorRange,
     getSelectPosition,
@@ -19,7 +19,7 @@ import {afterRenderEvent} from "./afterRenderEvent";
 import {genImagePopover, highlightToolbar} from "./highlightToolbar";
 import {getRenderElementNextNode, modifyPre} from "./inlineTag";
 import {input} from "./input";
-import {processCodeRender, showCode} from "./processCodeRender";
+import {showCode} from "./showCode";
 
 class WYSIWYG {
     public element: HTMLPreElement;
@@ -146,6 +146,8 @@ class WYSIWYG {
                     + textPlain + codeElement.textContent.substring(position.end);
                 setSelectionByPosition(position.start + textPlain.length, position.start + textPlain.length,
                     codeElement.parentElement);
+                codeElement.parentElement.nextElementSibling.innerHTML = codeElement.outerHTML;
+                processCodeRender(codeElement.parentElement.nextElementSibling as HTMLElement, vditor);
             } else if (code) {
                 const node = document.createElement("template");
                 node.innerHTML = code;
@@ -156,10 +158,6 @@ class WYSIWYG {
                 } else {
                     vditor.wysiwyg.element.innerHTML = vditor.lute.SpinVditorDOM(vditor.wysiwyg.element.innerHTML);
                 }
-                vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__block").forEach(
-                    (blockRenderItem: HTMLElement) => {
-                        processCodeRender(blockRenderItem, vditor);
-                    });
                 setRangeByWbr(vditor.wysiwyg.element, range);
             } else {
                 if (textHTML.trim() !== "") {
@@ -213,8 +211,8 @@ class WYSIWYG {
                 }
             }
 
-            this.element.querySelectorAll(".vditor-wysiwyg__block").forEach((blockElement: HTMLElement) => {
-                processCodeRender(blockElement, vditor);
+            this.element.querySelectorAll(".vditor-wysiwyg__preview[data-render='2']").forEach((item: HTMLElement) => {
+                processCodeRender(item, vditor);
             });
 
             afterRenderEvent(vditor);

+ 6 - 15
src/ts/wysiwyg/input.ts

@@ -2,14 +2,14 @@ import {isToC, renderToc} from "../util/fixBrowserBehavior";
 import {
     getTopList,
     hasClosestBlock, hasClosestByAttribute,
-    hasClosestByClassName, hasClosestByHeadings,
+    hasClosestByHeadings,
     hasClosestByTag,
 } from "../util/hasClosest";
 import {log} from "../util/log";
+import {processCodeRender} from "../util/processCode";
 import {setRangeByWbr} from "../util/selection";
 import {afterRenderEvent} from "./afterRenderEvent";
 import {previoueIsEmptyA} from "./inlineTag";
-import {processCodeRender} from "./processCodeRender";
 
 export const input = (vditor: IVditor, range: Range, event?: InputEvent) => {
     let blockElement = hasClosestBlock(range.startContainer);
@@ -19,16 +19,7 @@ export const input = (vditor: IVditor, range: Range, event?: InputEvent) => {
         blockElement = vditor.wysiwyg.element;
     }
 
-    const renderElement = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__block");
-    const codeElement = hasClosestByTag(range.startContainer, "CODE");
-    if (codeElement && renderElement && renderElement.getAttribute("data-block") === "0") {
-        if (renderElement.firstElementChild.tagName === "PRE") {
-            processCodeRender(renderElement, vditor);
-        } else {
-            // 代码块前为空行,按下向后删除键,代码块内容会被删除
-            renderElement.outerHTML = `<p data-block="0">${renderElement.textContent}</p>`;
-        }
-    } else if (event && event.inputType !== "formatItalic"
+    if (event && event.inputType !== "formatItalic"
         && event.inputType !== "deleteByDrag"
         && event.inputType !== "insertFromDrop"
         && event.inputType !== "formatBold"
@@ -152,9 +143,9 @@ export const input = (vditor: IVditor, range: Range, event?: InputEvent) => {
         // 设置光标
         setRangeByWbr(vditor.wysiwyg.element, range);
 
-        // TODO: 目前为全局渲染。可优化为只选取当前列表、当前列表紧邻的前后列表;最顶层列表;当前块进行渲染
-        vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__block").forEach((blockRenderItem: HTMLElement) => {
-            processCodeRender(blockRenderItem, vditor);
+        vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__preview[data-render='2']")
+            .forEach((item: HTMLElement) => {
+            processCodeRender(item, vditor);
         });
     }
 

+ 0 - 109
src/ts/wysiwyg/processCodeRender.ts

@@ -1,109 +0,0 @@
-import codeSVG from "../../assets/icons/code.svg";
-import {Constants} from "../constants";
-import {abcRender} from "../markdown/abcRender";
-import {chartRender} from "../markdown/chartRender";
-import {codeRender} from "../markdown/codeRender";
-import {graphvizRender} from "../markdown/graphvizRender";
-import {highlightRender} from "../markdown/highlightRender";
-import {mathRender} from "../markdown/mathRender";
-import {mermaidRender} from "../markdown/mermaidRender";
-import {scrollCenter} from "../util/editorCommenEvent";
-import {hasClosestByTag} from "../util/hasClosest";
-import {setSelectionFocus} from "../util/selection";
-
-export const showCode = (previewElement: HTMLElement, first = true) => {
-    const previousElement = previewElement.previousElementSibling as HTMLElement;
-    const range = previousElement.ownerDocument.createRange();
-    if (previousElement.tagName === "CODE") {
-        previousElement.style.display = "inline-block";
-        if (first) {
-            range.setStart(previousElement.firstChild, 1);
-        } else {
-            range.selectNodeContents(previousElement);
-        }
-    } else {
-        previousElement.style.display = "block";
-
-        if (!previousElement.firstChild.firstChild) {
-            previousElement.firstChild.appendChild(document.createTextNode(""));
-        }
-        range.selectNodeContents(previousElement.firstChild);
-    }
-    if (first) {
-        range.collapse(true);
-    } else {
-        range.collapse(false);
-    }
-    setSelectionFocus(range);
-    scrollCenter(previewElement.parentElement.parentElement);
-};
-
-// html, math, math-inline, code block, abc, chart, mermaid, graphviz
-export const processCodeRender = (blockElement: HTMLElement, vditor: IVditor) => {
-    const blockType = blockElement.getAttribute("data-type");
-    if (!blockType) {
-        return;
-    }
-    const tagName = blockType.indexOf("block") > -1 ? "div" : "span";
-    let previewPanel: HTMLElement = blockElement.querySelector(".vditor-wysiwyg__preview");
-    if (!previewPanel) {
-        blockElement.insertAdjacentHTML("beforeend", `<${tagName} class="vditor-wysiwyg__preview"></${tagName}>`);
-        previewPanel = blockElement.querySelector(".vditor-wysiwyg__preview");
-        previewPanel.setAttribute("data-render", "false");
-    }
-
-    let codeElement = previewPanel.previousElementSibling as HTMLElement;
-    if (codeElement.tagName === "PRE") {
-        codeElement = codeElement.firstElementChild as HTMLElement;
-    }
-    const innerHTML = codeElement.innerHTML || "\n";
-    if (blockType === "code-block") {
-        const language = codeElement.className.replace("language-", "");
-        // 代码块下方输入中文会消失,因此要 trim
-        previewPanel.innerHTML = `<pre><code class="${codeElement.className}">${innerHTML.trimRight()}</code></pre>`;
-        if (language === "abc") {
-            abcRender(previewPanel, vditor.options.cdn);
-        } else if (language === "mermaid") {
-            mermaidRender(previewPanel, ".vditor-wysiwyg__preview .language-mermaid",
-                vditor.options.cdn);
-        } else if (language === "echarts") {
-            chartRender(previewPanel, vditor.options.cdn);
-        } else if (language === "graphviz") {
-            graphvizRender(previewPanel, vditor.options.cdn);
-        } else {
-            highlightRender(Object.assign({}, vditor.options.preview.hljs, {enable: true}),
-                previewPanel, vditor.options.cdn);
-            codeRender(previewPanel, vditor.options.lang);
-        }
-    } else if (blockType.indexOf("html") > -1) {
-        const tempHTML = innerHTML.replace(/&amp;/g, "&")
-            .replace(/&lt;/g, "<").replace(/&gt;/g, ">");
-        if (blockType === "html-inline") {
-            previewPanel.innerHTML = codeSVG + tempHTML.replace(Constants.ZWSP, "");
-            previewPanel.setAttribute("data-html", innerHTML.replace(Constants.ZWSP, ""));
-            return;
-        }
-        previewPanel.innerHTML = tempHTML;
-    } else if (blockType.indexOf("math") > -1) {
-        if (tagName === "span") {
-            previewPanel.innerHTML = `<code class="language-math"><${tagName} class="vditor-math">${
-                innerHTML.replace(Constants.ZWSP, "")}</${tagName}></code>`;
-        } else {
-            previewPanel.innerHTML = `<pre><code class="language-math"><${tagName} class="vditor-math">${
-                innerHTML.replace(Constants.ZWSP, "")}</${tagName}></code></pre>`;
-        }
-
-        mathRender(previewPanel, {cdn: vditor.options.cdn, math: vditor.options.preview.math});
-    }
-
-    if (getSelection().rangeCount > 0) {
-        const range = getSelection().getRangeAt(0);
-        if (blockElement.contains(range.startContainer) && hasClosestByTag(range.startContainer, "CODE")) {
-            let display = "inline-block";
-            if (blockElement.firstElementChild.tagName === "PRE") {
-                display = "block";
-            }
-            (blockElement.firstElementChild as HTMLElement).style.display = display;
-        }
-    }
-};

+ 1 - 1
src/ts/wysiwyg/processKeydown.ts

@@ -21,8 +21,8 @@ import {matchHotKey} from "../util/hotKey";
 import {getSelectPosition, setSelectionFocus} from "../util/selection";
 import {afterRenderEvent} from "./afterRenderEvent";
 import {nextIsCode} from "./inlineTag";
-import {showCode} from "./processCodeRender";
 import {removeHeading, setHeading} from "./setHeading";
+import {showCode} from "./showCode";
 
 export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
     // Chrome firefox 触发 compositionend 机制不一致 https://github.com/Vanessa219/vditor/issues/188

+ 4 - 4
src/ts/wysiwyg/renderDomByMd.ts

@@ -1,13 +1,13 @@
+import {processCodeRender} from "../util/processCode";
 import {afterRenderEvent} from "./afterRenderEvent";
-import {processCodeRender} from "./processCodeRender";
 
 export const renderDomByMd = (vditor: IVditor, md: string, enableInput = true) => {
     const editorElement = vditor.wysiwyg.element;
     editorElement.innerHTML = vditor.lute.Md2VditorDOM(md);
 
-    editorElement.querySelectorAll(".vditor-wysiwyg__block").forEach((blockElement: HTMLElement) => {
-        processCodeRender(blockElement, vditor);
-        blockElement.firstElementChild.setAttribute("style", "display:none");
+    editorElement.querySelectorAll(".vditor-wysiwyg__preview[data-render='2']").forEach((item: HTMLElement) => {
+        processCodeRender(item, vditor);
+        item.previousElementSibling.setAttribute("style", "display:none");
     });
 
     afterRenderEvent(vditor, {

+ 29 - 0
src/ts/wysiwyg/showCode.ts

@@ -0,0 +1,29 @@
+import {scrollCenter} from "../util/editorCommenEvent";
+import {setSelectionFocus} from "../util/selection";
+
+export const showCode = (previewElement: HTMLElement, first = true) => {
+    const previousElement = previewElement.previousElementSibling as HTMLElement;
+    const range = previousElement.ownerDocument.createRange();
+    if (previousElement.tagName === "CODE") {
+        previousElement.style.display = "inline-block";
+        if (first) {
+            range.setStart(previousElement.firstChild, 1);
+        } else {
+            range.selectNodeContents(previousElement);
+        }
+    } else {
+        previousElement.style.display = "block";
+
+        if (!previousElement.firstChild.firstChild) {
+            previousElement.firstChild.appendChild(document.createTextNode(""));
+        }
+        range.selectNodeContents(previousElement.firstChild);
+    }
+    if (first) {
+        range.collapse(true);
+    } else {
+        range.collapse(false);
+    }
+    setSelectionFocus(range);
+    scrollCenter(previewElement.parentElement.parentElement);
+};

+ 4 - 4
src/ts/wysiwyg/toolbarEvent.ts

@@ -2,11 +2,11 @@ import {Constants} from "../constants";
 import {removeCurrentToolbar, setCurrentToolbar} from "../toolbar/setToolbar";
 import {listToggle} from "../util/fixBrowserBehavior";
 import {hasClosestBlock, hasClosestByAttribute, hasClosestByMatchTag} from "../util/hasClosest";
+import {processCodeRender} from "../util/processCode";
 import {getEditorRange, setRangeByWbr, setSelectionFocus} from "../util/selection";
 import {afterRenderEvent} from "./afterRenderEvent";
 import {genAPopover, highlightToolbar} from "./highlightToolbar";
 import {getNextHTML, getPreviousHTML, splitElement} from "./inlineTag";
-import {processCodeRender} from "./processCodeRender";
 
 const cancelBES = (range: Range, vditor: IVditor, commandName: string) => {
     let element = range.startContainer.parentElement;
@@ -203,9 +203,9 @@ export const toolbarEvent = (vditor: IVditor, actionBtn: Element) => {
                 blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML);
             }
             setRangeByWbr(vditor.wysiwyg.element, range);
-            vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__block").forEach(
-                (blockRenderItem: HTMLElement) => {
-                    processCodeRender(blockRenderItem, vditor);
+            vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__preview[data-render='2']").forEach(
+                (item: HTMLElement) => {
+                    processCodeRender(item, vditor);
                 });
         } else if (commandName === "link") {
             if (range.toString() === "") {