Vditor-网页富文本编辑器

28   /   0   /   0   /   0   /   发布于 46天前
[gitee源代码](https://gitee.com/mirrors/Vditor) [官方使用说明](https://ld246.com/article/1549638745630) 去[jsdelivr](https://www.jsdelivr.com/package/npm/vditor?path=dist&utm_source=ld246.com&tab=files)下载,位置在右上角,有个下载图标 # 源码编译安装 ``` git clone https://gitee.com/mirrors/Vditor.git cd Vditor export PUPPETEER_SKIP_DOWNLOAD=true npm install ``` 这时可能会出现很多peer dependencies 冲突的错误。 1. 删除 `node_modules`和 `package-lock.json` 2. 修改package.json中相关包的版本,我这次修改了: ``` "ts-jest": "^29.4.6", "eslint-plugin-jest": "^29.2.1", "jest": "^29.7.0", ``` 之后再次运行 `npm install` ``` npm run start ``` 这时可能会出现/Vditor/src/ts/undo/index.ts有错误,可以把代码和错误给元宝,它会修改代码。修改过的代码如下: ``` import * as DiffMatchPatch from "diff-match-patch"; import {disableToolbar, enableToolbar, hidePanel} from "../toolbar/setToolbar"; import {isFirefox, isSafari} from "../util/compatibility"; import {scrollCenter} from "../util/editorCommonEvent"; import {execAfterRender} from "../util/fixBrowserBehavior"; import {highlightToolbar} from "../util/highlightToolbar"; import {processCodeRender} from "../util/processCode"; import {setRangeByWbr, setSelectionFocus} from "../util/selection"; import {renderToc} from "../util/toc"; // 定义 DiffMatchPatch 的类型 interface PatchObj { diffs: Array<[number, string]>; start1: number; start2: number; length1: number; length2: number; } interface IUndo { hasUndo: boolean; lastText: string; redoStack: PatchObj[][]; undoStack: PatchObj[][]; } class Undo { private stackSize = 50; // 修复错误1: 使用正确的类型声明 private dmp: any; // 使用 any 类型,因为 diff-match-patch 的类型定义不完整 private wysiwyg: IUndo; private ir: IUndo; private sv: IUndo; constructor() { this.resetStack(); // 修改这里:直接使用 default 导出 this.dmp = new (DiffMatchPatch as any).diff_match_patch(); } public clearStack(vditor: IVditor) { this.resetStack(); this.resetIcon(vditor); } public resetIcon(vditor: IVditor) { if (!vditor.toolbar) { return; } if (this[vditor.currentMode].undoStack.length > 1) { enableToolbar(vditor.toolbar.elements, ["undo"]); } else { disableToolbar(vditor.toolbar.elements, ["undo"]); } if (this[vditor.currentMode].redoStack.length !== 0) { enableToolbar(vditor.toolbar.elements, ["redo"]); } else { disableToolbar(vditor.toolbar.elements, ["redo"]); } } public undo(vditor: IVditor) { if (vditor[vditor.currentMode].element.getAttribute("contenteditable") === "false") { return; } if (this[vditor.currentMode].undoStack.length < 2) { return; } const state = this[vditor.currentMode].undoStack.pop(); if (!state) { return; } this[vditor.currentMode].redoStack.push(state); this.renderDiff(state, vditor); this[vditor.currentMode].hasUndo = true; // undo 操作后,需要关闭 hint hidePanel(vditor, ["hint"]); } public redo(vditor: IVditor) { if (vditor[vditor.currentMode].element.getAttribute("contenteditable") === "false") { return; } const state = this[vditor.currentMode].redoStack.pop(); if (!state) { return; } this[vditor.currentMode].undoStack.push(state); this.renderDiff(state, vditor, true); } public recordFirstPosition(vditor: IVditor, event: KeyboardEvent) { if (getSelection().rangeCount === 0) { return; } if (this[vditor.currentMode].undoStack.length !== 1 || this[vditor.currentMode].undoStack[0].length === 0 || this[vditor.currentMode].redoStack.length > 0) { return; } if (isFirefox() && event.key === "Backspace") { // Firefox 第一次删除无效 return; } if (isSafari()) { // Safari keydown 在 input 之后,不需要重复记录历史 return; } const text = this.addCaret(vditor); if (text.replace("<wbr>", "").replace(" vditor-ir__node--expand", "") !== this[vditor.currentMode].undoStack[0][0].diffs[0][1].replace("<wbr>", "")) { // 当还不没有存入 undo 栈时,按下 ctrl 后会覆盖 lastText return; } this[vditor.currentMode].undoStack[0][0].diffs[0][1] = text; this[vditor.currentMode].lastText = text; // 不能添加 setSelectionFocus(cloneRange); 否则 windows chrome 首次输入会烂 } public addToUndoStack(vditor: IVditor) { // afterRenderEvent.ts 已经 debounce const text = this.addCaret(vditor, true); const diff = this.dmp.diff_main(text, this[vditor.currentMode].lastText, true); const patchList = this.dmp.patch_make(text, this[vditor.currentMode].lastText, diff); if (patchList.length === 0 && this[vditor.currentMode].undoStack.length > 0) { return; } this[vditor.currentMode].lastText = text; this[vditor.currentMode].undoStack.push(patchList); if (this[vditor.currentMode].undoStack.length > this.stackSize) { this[vditor.currentMode].undoStack.shift(); } if (this[vditor.currentMode].hasUndo) { this[vditor.currentMode].redoStack = []; this[vditor.currentMode].hasUndo = false; disableToolbar(vditor.toolbar.elements, ["redo"]); } if (this[vditor.currentMode].undoStack.length > 1) { enableToolbar(vditor.toolbar.elements, ["undo"]); } } private renderDiff(state: PatchObj[], vditor: IVditor, isRedo: boolean = false) { let text; if (isRedo) { const redoPatchList = this.dmp.patch_deepCopy(state).reverse(); // 修复错误2和3: 为回调参数添加类型注解 redoPatchList.forEach((patch: any) => { patch.diffs.forEach((diff: any) => { diff[0] = -diff[0]; }); }); text = this.dmp.patch_apply(redoPatchList, this[vditor.currentMode].lastText)[0]; } else { text = this.dmp.patch_apply(state, this[vditor.currentMode].lastText)[0]; } this[vditor.currentMode].lastText = text; vditor[vditor.currentMode].element.innerHTML = text; if (vditor.currentMode !== "sv") { vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview`) .forEach((blockElement: HTMLElement) => { if (blockElement.parentElement.querySelector(".language-echarts")) { if (vditor.currentMode === "ir") { blockElement.parentElement.outerHTML = vditor.lute.SpinVditorIRDOM(blockElement.parentElement.outerHTML); } else { blockElement.parentElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.parentElement.outerHTML); } } }); vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) .forEach((blockElement: HTMLElement) => { processCodeRender(blockElement, vditor); }); } if (!vditor[vditor.currentMode].element.querySelector("wbr")) { // Safari 第一次输入没有光标,需手动定位到结尾 const range = getSelection().getRangeAt(0); range.setEndBefore(vditor[vditor.currentMode].element); range.collapse(false); } else { setRangeByWbr( vditor[vditor.currentMode].element, vditor[vditor.currentMode].element.ownerDocument.createRange()); scrollCenter(vditor); } renderToc(vditor); execAfterRender(vditor, { enableAddUndoStack: false, enableHint: false, enableInput: true, }); highlightToolbar(vditor); vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) .forEach((item: HTMLElement) => { processCodeRender(item, vditor); }); if (this[vditor.currentMode].undoStack.length > 1) { enableToolbar(vditor.toolbar.elements, ["undo"]); } else { disableToolbar(vditor.toolbar.elements, ["undo"]); } if (this[vditor.currentMode].redoStack.length !== 0) { enableToolbar(vditor.toolbar.elements, ["redo"]); } else { disableToolbar(vditor.toolbar.elements, ["redo"]); } } private resetStack() { this.ir = { hasUndo: false, lastText: "", redoStack: [], undoStack: [], }; this.sv = { hasUndo: false, lastText: "", redoStack: [], undoStack: [], }; this.wysiwyg = { hasUndo: false, lastText: "", redoStack: [], undoStack: [], }; } private addCaret(vditor: IVditor, setFocus = false) { let cloneRange: Range; if (getSelection().rangeCount !== 0 && !vditor[vditor.currentMode].element.querySelector("wbr")) { const range = getSelection().getRangeAt(0); if (vditor[vditor.currentMode].element.contains(range.startContainer)) { cloneRange = range.cloneRange(); const wbrElement = document.createElement("span"); wbrElement.className = "vditor-wbr"; range.insertNode(wbrElement); } } // 移除数学公式、echart 渲染 https://github.com/Vanessa219/vditor/issues/1738 const cloneElement = vditor[vditor.currentMode].element.cloneNode(true) as HTMLElement; cloneElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='1']`) .forEach((item: HTMLElement) => { if (!item.firstElementChild) { return; } if (item.firstElementChild.classList.contains("language-echarts") || item.firstElementChild.classList.contains("language-plantuml") || item.firstElementChild.classList.contains("language-mindmap")) { item.firstElementChild.removeAttribute("_echarts_instance_"); item.firstElementChild.removeAttribute("data-processed"); item.firstElementChild.innerHTML = item.previousElementSibling.firstElementChild.innerHTML; item.setAttribute("data-render", "2"); } else if (item.firstElementChild.classList.contains("language-math")) { item.setAttribute("data-render", "2"); item.firstElementChild.textContent = item.firstElementChild.getAttribute("data-math"); item.firstElementChild.removeAttribute("data-math"); } }); const text = cloneElement.innerHTML; vditor[vditor.currentMode].element.querySelectorAll(".vditor-wbr").forEach((item) => { item.remove(); // 使用 item.outerHTML = "" 会产生 https://github.com/Vanessa219/vditor/pull/686; }); if (setFocus && cloneRange) { setSelectionFocus(cloneRange); } return text.replace('<span class="vditor-wbr"></span>', "<wbr>"); } } export {Undo}; ``` 之后,就是 `npm run build`,目录下的dist就是全部的文件。
  • 共 0 条回复
  • 需要登录 后方可回复, 如果你还没有账号请点击这里注册
梦初醒 茅塞开
  • 不经他人苦,莫劝他人善。
  • 能量足,心态稳,温和坚定可以忍。
  • 辛苦决定不了收入,真正决定收入的只有一个,就是不可替代性。
  • 要么忙于生存,要么赶紧去死!
  • 内心强大到混蛋,比什么都好!
  • 规范流程比制定制度更重要!
  • 立志需要高远,但不能急功近利;
    行动需要迅速,却不可贪图速成。
  • 不要强求人品,要设计高效的机制。
  • 你弱的时候,身边都是鸡零狗碎;
    你强的时候,身边都是风和日丽。
  • 机制比人品更可靠,契约比感情更可靠。
  • 合作不意味着没有冲突,却是控制冲突的最好方法。
  • 误解是人生常态,理解本是稀缺的例外。
  • 成功和不成功之间,只差一次坚持!
  • 祁连卧北雪,大漠壮雄关。
  • 利益顺序,过程公开,机会均等,付出回报。