Vditor 一款浏览器端的 Markdown 编辑器,支持所见即所得(富文本)、即时渲染(类似 Typora)和分屏预览模式

Vditor
易于使用的 Markdown 编辑器,为适配不同的应用场景而生

npm bundle size



English  |  Demo

💡 简介

Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React、Angular,提供桌面版

欢迎到 Vditor 官方讨论区了解更多。同时也欢迎关注 B3log 开源社区微信公众号 B3log开源

b3logos.jpg

🗺️ 背景

随着 Markdown 排版方式的普及,越来越多的应用开始集成 Markdown 编辑器。目前主流可集成的 Markdown 编辑器现状如下:

而这三点恰好对应了三种应用场景:

所以,一个能够适配应用场景的 Markdown 编辑器至关重要,它需要考虑到:

Vditor 在这些方面做了努力,希望能为现代化的通用 Markdown 编辑领域做出一些贡献。

✨ 特性

editor.png

preview.png

🔮 编辑模式

所见即所得(WYSIWYG)

所见即所得模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。

vditor-wysiwyg

即时渲染(IR)

即时渲染模式对熟悉 Typora 的用户应该不会感到陌生,理论上这是最优雅的 Markdown 编辑方式。

vditor-ir

分屏预览(SV)

传统的分屏预览模式适合大屏下的 Markdown 编辑。

vditor-sv

🍱 语法支持

以上大部分特性可以通过开关配置是否启用,开发者可根据自己的应用场景选择搭配。

🗃 案例

🛠️ 使用文档

CommonJS

npm install vditor --save
import Vditor from 'vditor'
import "~vditor/src/assets/scss/index"

const vditor = new Vditor(id, {options...})

HTML script

<!-- ⚠️生产环境请指定版本号,如 https://cdn.jsdelivr.net/npm/vditor@x.x.x/dist... -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vditor/dist/index.css" />
<script src="https://cdn.jsdelivr.net/npm/vditor/dist/index.min.js" defer></script>

示例代码

主题

编辑器主题

编辑器所展现的外观。内置 classic,dark 2 套主题。

内容主题

Markdown 输出的 HTML 所展现的外观。内置 light,dark,wechat 3 套主题。支持内容主题扩展接口。

代码主题

代码块所展现的外观。内置 GitHub 等 36 套主题。

API

id

可填入元素 id 或元素自身 HTMLElement

⚠️:当填入元素自身的 HTMLElement 时需设置 options.cache.id 或将 options.cache.enable 设置为 false

options

说明 默认值
after 编辑器异步渲染完成后的回调方法 -
height 编辑器总高度 'auto'
minHeight 编辑区域最小高度 -
width 编辑器总宽度,支持 % 'auto'
placeholder 输入区域为空时的提示 ''
lang 多语言:en_US, ja_JP, ko_KR, zh_CN 'zh_CN'
input(value: string, previewElement?: HTMLElement): void 输入后触发 -
focus(value: string): void 聚焦后触发 -
blur(value: string): void 失焦后触发 -
esc(value: string): void esc 按下后触发 -
ctrlEnter(value: string): void ⌘/ctrl+enter 按下后触发 -
select(value: string): void 编辑器中选中文字后触发 -
tab tab 键操作字符串,支持 \t 及任意字符串 -
typewriterMode 是否启用打字机模式 false
cdn 配置自建 CDN 地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}
mode 可选模式:sv, ir, wysiwyg 'ir'
debugger 是否显示日志 false
value 编辑器初始化值 ''
theme 主题:classic, dark 'classic'
icon 图标风格:ant, material 'ant'
outline 是否展现大纲 false

options.toolbar

new Vditor('vditor', {
  toolbar: [
    {
      hotkey: '⌘-⇧-S',
      name: 'sponsor',
      tipPosition: 's',
      tip: '成为赞助者',
      className: 'right',
      icon: '<svg t="1589994565028" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2808" width="32" height="32"><path d="M506.6 423.6m-29.8 0a29.8 29.8 0 1 0 59.6 0 29.8 29.8 0 1 0-59.6 0Z" fill="#0F0F0F" p-id="2809"></path><path d="M717.8 114.5c-83.5 0-158.4 65.4-211.2 122-52.7-56.6-127.7-122-211.2-122-159.5 0-273.9 129.3-273.9 288.9C21.5 562.9 429.3 913 506.6 913s485.1-350.1 485.1-509.7c0.1-159.5-114.4-288.8-273.9-288.8z" fill="#FAFCFB" p-id="2810"></path><path d="M506.6 926c-22 0-61-20.1-116-59.6-51.5-37-109.9-86.4-164.6-139-65.4-63-217.5-220.6-217.5-324 0-81.4 28.6-157.1 80.6-213.1 53.2-57.2 126.4-88.8 206.3-88.8 40 0 81.8 14.1 124.2 41.9 28.1 18.4 56.6 42.8 86.9 74.2 30.3-31.5 58.9-55.8 86.9-74.2 42.5-27.8 84.3-41.9 124.2-41.9 79.9 0 153.2 31.5 206.3 88.8 52 56 80.6 131.7 80.6 213.1 0 103.4-152.1 261-217.5 324-54.6 52.6-113.1 102-164.6 139-54.8 39.5-93.8 59.6-115.8 59.6zM295.4 127.5c-72.6 0-139.1 28.6-187.3 80.4-47.5 51.2-73.7 120.6-73.7 195.4 0 64.8 78.3 178.9 209.6 305.3 53.8 51.8 111.2 100.3 161.7 136.6 56.1 40.4 88.9 54.8 100.9 54.8s44.7-14.4 100.9-54.8c50.5-36.3 108-84.9 161.7-136.6 131.2-126.4 209.6-240.5 209.6-305.3 0-74.9-26.2-144.2-73.7-195.4-48.2-51.9-114.7-80.4-187.3-80.4-61.8 0-127.8 38.5-201.7 117.9-2.5 2.6-5.9 4.1-9.5 4.1s-7.1-1.5-9.5-4.1C423.2 166 357.2 127.5 295.4 127.5z" fill="#141414" p-id="2811"></path><path d="M353.9 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2812"></path><path d="M659.3 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2813"></path><path d="M411.6 538.5c0 52.3 42.8 95 95 95 52.3 0 95-42.8 95-95v-31.7h-190v31.7z" fill="#5B5143" p-id="2814"></path><path d="M506.6 646.5c-59.6 0-108-48.5-108-108v-31.7c0-7.2 5.8-13 13-13h190.1c7.2 0 13 5.8 13 13v31.7c0 59.5-48.5 108-108.1 108z m-82-126.7v18.7c0 45.2 36.8 82 82 82s82-36.8 82-82v-18.7h-164z" fill="#141414" p-id="2815"></path><path d="M450.4 578.9a54.7 27.5 0 1 0 109.4 0 54.7 27.5 0 1 0-109.4 0Z" fill="#EA64F9" p-id="2816"></path><path d="M256 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2817"></path><path d="M703.3 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2818"></path></svg>',
      click () {alert('捐赠地址:https://ld246.com/sponsor')},
    }],
})
说明 默认值
name 唯一标示 -
icon svg 图标 -
tip 提示 -
tipPosition 提示位置:ne, nw -
hotkey 快捷键,格式为⌘/ctrl-key⌘/ctrl-⇧/shift-key -
suffix 插入编辑器中的后缀 -
prefix 插入编辑器中的前缀 -
click(): void 自定义按钮点击时触发的事件 -
className 样式名 ''
toolbar?: Array<options.toolbar> 子菜单 -

options.toolbarConfig

说明 默认值
hide 是否隐藏工具栏 false
pin 是否固定工具栏 false

options.counter

说明 默认值
enable 是否启用计数器 false
max 允许输入的最大值 -
type 统计类型:md,text 'md'

options.cache

说明 默认值
enable 是否使用 localStorage 进行缓存 true
id 缓存 key,第一个参数为元素且启用缓存时必填 -
after(html: string): string 缓存后的回调 -

options.preview

说明 默认值
delay 预览 debounce 毫秒间隔 1000
maxWidth 预览区域最大宽度 800
mode 显示模式:both, editor 'both'
url md 解析请求 -
parse(element: HTMLElement): void 预览回调 -
transform(html: string): string 渲染之前回调 -

options.preview.hljs

说明 默认值
enable 是否启用代码高亮 true
style 可选值参见 Chroma github
lineNumber 是否启用行号 false

options.preview.markdown

说明 默认值
autoSpace 自动空格 false
fixTermTypo 自动矫正术语 false
chinesePunct 自动矫正标点 false
toc 插入目录 false
footnotes 脚注 true
codeBlockPreview wysiwyg 和 ir 模式下是否对代码块进行渲染 true
mathBlockPreview wysiwyg 和 ir 模式下是否对数学公式进行渲染 true
paragraphBeginningSpace 段落开头空两个 false
sanitize 是否启用过滤 XSS true
listStyle 为列表添加 data-style 属性 false
linkBase 链接相对路径前缀 ''
linkPrefix 链接强制前缀 ''
mark 启用 mark 标记 false

options.preview.theme

说明 默认值
current 当前主题 "light"
list 可选主题列表 { dark: "Dark", light: "Light", wechat: "WeChat" }
path 主题样式地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/css/content-theme

options.preview.math

说明 默认值
inlineDigit 内联数学公式起始 $ 后是否允许数字 false
macros 使用 MathJax 渲染时传入的宏定义 {}
engine 数学公式渲染引擎:KaTeX, MathJax 'KaTeX'

options.preview.actions?: Array<IPreviewAction | IPreviewActionCustom>

默认值为 ["desktop", "tablet", "mobile", "mp-wechat", "zhihu"]。
可从默认值中挑选进行配置,也可使用以下字段进行自定制开发。

说明 默认值
key 按钮唯一标识,不能为空 -
text 按钮文字 -
className 按钮类名 -
click(key: string) => void 按钮点击回调事件 -

options.hint

说明 默认值
delay 提示 debounce 毫秒间隔 200
emoji 默认表情,可从 lute/emoji_map 中选取,也可自定义 { '+1': '👍', '-1': '👎', 'heart': '❤️', 'cold_sweat': '😰' }
emojiTail 常用表情提示 -
emojiPath 表情图片地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/images/emoji
extend: IHintExtend[] 对 @/话题等关键字自动补全的扩展 []
interface IHintExtend {
    key: string;

    hint?(value: string): Array<{
        html: string;
        value: string;
    }>;
}

options.upload

// POST data  
xhr.send(formData);  // formData = FormData.append("file[]", File)  
// return data  
{  
 "msg": "",  
 "code": 0,  
 "data": {  
 "errFiles": ['filename', 'filename2'],  
 "succMap": {  
   "filename3": "filepath3",  
   "filename3": "filepath3"  
   }  
 }  
}
// POST data  
xhr.send(JSON.stringify({url: src})); // src 为站外图片地址  
// return data  
{  
 msg: '',  
 code: 0,  
 data : {  
   originalURL: '',  
   url: ''  
 }  
}
if (xhr.status === 200) {
    if (vditor.options.upload.success) {
        vditor.options.upload.success(editorElement, xhr.responseText);
    } else {
        let responseText = xhr.responseText;
        if (vditor.options.upload.format) {
            responseText = vditor.options.upload.format(files as File [], xhr.responseText);
        }
        genUploadedLabel(responseText, vditor);
    }
} else {
    if (vditor.options.upload.error) {
        vditor.options.upload.error(xhr.responseText);
    } else {
        vditor.tip.show(xhr.responseText);
    }
}
说明 默认值
url 上传 url ''
max 上传文件最大 Byte 10 * 1024 * 1024
linkToImgUrl 剪切板中包含图片地址时,使用此 url 重新上传 ''
linkToImgCallback(responseText: string): void 图片地址上传回调 -
linkToImgFormat(responseText: string): string 对图片地址上传的返回值进行格式化 -
success(editor: HTMLPreElement, msg: string): void 上传成功回调 -
error(msg: string): void 上传失败回调 -
token CORS 上传验证,头为 X-Upload-Token -
withCredentials 跨站点访问控制 false
headers 请求头设置 -
filename(name: string): string 文件名安全处理 name => name.replace(/\W/g, '')
accept 文件上传类型,同 input accept -
validate(files: File[]) => string | boolean 校验,成功时返回 true 否则返回错误信息 -
handler(files: File[]) => string | null 自定义上传,当发生错误时返回错误信息 -
format(files: File[], responseText: string): string 对服务端返回的数据进行转换,以满足内置的数据结构 -
file(files: File[]): File[] 将上传的文件处理后再返回 -
setHeaders(): { [key: string]: string } 上传前使用返回值设置头 -
extraData: { [key: string]: string | Blob } 为 FormData 添加额外的参数 -
multiple 上传文件是否为多个 true
fieldName 上传字段名称 'file[]'

options.resize

说明 默认值
enable 是否支持大小拖拽 false
position 拖拽栏位置:top, bottom 'bottom'
after(height: number): void 拖拽结束的回调 -

options.classes

说明 默认值
preview 预览元素上的 className ''

methods

说明
getValue() 获取 Markdown 内容
getHTML() 获取 HTML 内容
insertValue(value: string, render = true) 在焦点处插入内容,并默认进行 Markdown 渲染
focus() 聚焦到编辑器
blur() 让编辑器失焦
disabled() 禁用编辑器
enable() 解除编辑器禁用
getSelection(): string 返回选中的字符串
setValue(markdown: string, clearStack = false) 设置编辑器内容且选中清空历史栈
clearStack() 清空撤销和重做记录栈
renderPreview(value?: string) 设置预览区域内容
getCursorPosition():{top: number, left: number} 获取焦点位置
deleteValue() 删除选中内容
updateValue(value: string) 更新选中内容
isUploading() 上传是否还在进行中
clearCache() 清除缓存
disabledCache() 禁用缓存
enableCache() 启用缓存
html2md(value: string) HTML 转 md
tip(text: string, time: number) 消息提示。time 为 0 将一直显示
setPreviewMode(mode: "both" | "editor") 设置预览模式
setTheme(theme: "dark" | "classic", contentTheme?: string, codeTheme?: string, contentThemePath?: string) 设置主题、内容主题及代码块风格
getCurrentMode(): string 获取编辑器当前编辑模式
destroy() 销毁编辑器

static methods

Vditor.mermaidRender(document)
import VditorPreview from 'vditor/dist/method.min'  
VditorPreview.mermaidRender(document)
previewElement: HTMLDivElement,   // 使用该元素进行渲染
markdown: string,  // 需要渲染的 markdown 原文
options?: IPreviewOptions {  
 anchor?: number;  // 为标题添加锚点 0:不渲染;1:渲染于标题前;2:渲染于标题后,默认 0
 customEmoji?: { [key: string]: string };    // 自定义 emoji,默认为 {}  
 lang?: (keyof II18nLang);    // 语言,默认为 'zh_CN'  
 emojiPath?: string;    // 表情图片路径 
 hljs?: IHljs; // 参见 options.preview.hljs 
 speech?: {  // 对选中后的内容进行阅读
  enable?: boolean,
 };
 math?: IMath; // 数学公式渲染配置
 cdn?: string; // 自建 CDN 地址
 transform?(html: string): string; // 在渲染前进行的回调方法
 after?(): void; // 渲染完成后的回调
 lazyLoadImage?: string; // 设置为 Loading 图片地址后将启用图片的懒加载
 markdown?: options.preview.markdown;
 theme?: options.preview.theme;
 renderers?: ILuteRender; // 自定义渲染 https://ld246.com/article/1588412297062
}
说明
mermaidRender(element: HTMLElement, cdn = options.cdn) 流程图/时序图/甘特图
flowchartRender(element: HTMLElement, cdn = options.cdn) flowchart 渲染
codeRender(element: HTMLElement, lang: (keyof II18nLang) = "zh_CN") 为 element 中的代码块添加复制按钮
chartRender(element: (HTMLElement | Document) = document, cdn = options.cdn) 图表渲染
mindmapRender(element: (HTMLElement | Document) = document, cdn = options.cdn) 脑图渲染
abcRender(element: (HTMLElement | Document) = document, cdn = options.cdn) 五线谱渲染
md2html(mdText: string, options?: IPreviewOptions): Promise<string> Markdown 文本转换为 HTML,该方法需使用异步编程
preview(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions) 页面 Markdown 文章渲染
highlightRender(hljsOption?: IHljs, element?: HTMLElement | Document, cdn = options.cdn) 为 element 中的代码块进行高亮渲染
mediaRender(element: HTMLElement) 特定链接分别渲染为视频、音频、嵌入的 iframe
mathRender(element: HTMLElement, options?: {cdn?: string, math?: IMath}) 对数学公式进行渲染
speechRender(element: HTMLElement, lang?: (keyof II18nLang)) 对选中的文字进行阅读
graphvizRender(element: HTMLElement, cdn?: string) 对 graphviz 进行渲染
outlineRender(contentElement: HTMLElement, targetElement: Element) 对大纲进行渲染
lazyLoadImageRender(element: (HTMLElement | Document) = document) 对启用懒加载的图片进行渲染
setCodeTheme(codeTheme: string, cdn = options.cdn) 设置代码主题,codeTheme 参见 options.preview.hljs.style
setContentTheme(contentTheme: string, path: string) 设置内容主题,contentTheme 参见 options.preview.theme.list

🏗 开发文档

原理相关

环境

  1. 安装 node LTS 版本
  2. 下载最新代码并解压
  3. 根目录运行 npm install
  4. npm run start 启动本地服务器,打开 http://localhost:9000
  5. 修改代码
  6. npm run build 打包代码到 dist 目录

CDN 切换

由于使用了按需加载的机制,默认 CDN 为 https://cdn.jsdelivr.net/npm/vditor@版本号

如果代码有修改或需要使用自建 CDN 的话,可按以下步骤进行操作:

升级

版本升级时请仔细阅读 CHANGELOG 中的升级部分

Ⓜ️ Markdown 使用指南

🏘️ 社区

📄 授权

Vditor 使用 MIT 开源协议。

🙏 鸣谢

📽️ 历史

我们在开发 Sym 的初期是直接使用 WYSIWYG 富文本编辑器的。那时候基于 HTML 的编辑器非常流行,项目中引用起来也很方便,也符合用户当时的使用习惯。

后来,Markdown 的崛起逐步改变了大家的排版方式。再加上我们其他几个项目都是面向程序员用户的,所以迁移到 md 上也是大势所趋。我们选择了 CodeMirror,这是一款优秀的编辑器,它对开发者提供了丰富的编程接口,对各种浏览器的兼容性也比较好。

再后来,随着我们项目业务需求方面的沉淀,使用 CodeMirror 有时候会感到比较“笨重”。比如要实现 @自动完成用户名列表、插入 Emoji、上传文件等就需要比较深入的二次开发,而这些业务需求恰恰是很多项目场景共有且必备的。

终于,我们决定开始在 Sym 中自己实现编辑器。随着几个版本的迭代,Sym 的编辑器也日趋成熟。在我们运营的社区链滴上陆续有人问我们是否能将编辑器单独抽离出来提供给大家使用。与此同时,我们的前端主程 V 同学对于维护分散在各个项目中的编辑器也感到有点力不从心,外加对 TypeScript 的好感,所以就决定使用 ts 来实现一个全新的浏览器端 md 编辑器。

于是,Vditor 就这样诞生了。

赞助商 我要投放

优质回帖
  • Vanessa 1
    作者

    前端是这样传送的

        const formData = new FormData();
        for (let i = 0, iMax = uploadFileList.length; i < iMax; i++) {
            formData.append("file[]", uploadFileList[i]);
        }
         xhr.send(formData);
    
  • haaid 1

    文字错误:接触编辑器禁用,「接触」->「解除」

  • someone9891 1
    捐赠者

    此链接 404

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • xushijie10086

    请教一下自定义上传图片的问题image.png

    如果这样上传成功之后,
    如何将图片 url 插入输入框里 【![name](//xxxx.xxx.xxx/xxx.jpg)】 <== 这样的

    1 回复
  • lisaem 2 评论

    请移步问答中回复 关于 solo 中使用 vaditor 的几个疑问

    一个小问题 希望有缘人回答一下。本人在自己的服务器上部署了博客 solo,在家用 vditor 编辑预览文章都没问题,今天来公司,想写点东西,发现预览功能无法使用,左边输入的内容,右边无法显示预览,一片空白。Chrome 里面用 f12 抓了下网络请求,发现有个请求被公司内网屏蔽了,具体是 http://我的网址/console/markdown/2html,这个请求失败导致的。我试了下给出的教程链接 https://hacpai.com/guide/markdown 这个预览就没问题,我看网络也是请求到后台去的 https://hacpai.com/markdown。然后返回一个 JSON,解析后的 HTML 网页。
    1.想问下 目前 vaditor 的预览不是用 markdown-it 支持前端预览吗?我是个大后端,对前端不太明白,为何这个预览还要网络请求,貌似是调到后台的转换方法 flexmark 了,还是有什么开关或者配置?
    2.vditor 本身是只是一个 Markdown 编辑器,转换预览(解析器功能)还是依赖第三方的组件,前端预览用 markdown-it,集成在 vditor 中,通过后端预览是发送到后端(路径是 http://我的网址/console/markdown/2html)然后先判断
    MARKDOWN_ENGINE_URL 是否可用,否的话就用集成的 flexmark。我这样理解对不对?

    3 操作
    lisaem 在 2019-07-29 15:57:56 更新了该回帖
    lisaem 在 2019-07-29 14:12:03 更新了该回帖
    lisaem 在 2019-07-29 14:08:19 更新了该回帖
    我自己的那个请求失败的问题,应该可以通过 https 改造解决。我对比了下公司拦截的都是 http 并且提交头是 application/json;charset=UTF-8
    lisaem
    收到,已在新帖中进行回复
    Vanessa
  • someone 1 评论
    \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.

    该回帖因偏离主题而被折叠
    1 操作
    Vanessa 在 2019-08-16 17:38:28 折叠了该回帖
    Vanessa
  • Tracy4ever

    请问,是不是如果 upload 写了 handler 方法,那么就不能使用内置的成功和失败回调啊?可是不写 handler 的话是不是对后台传参也有要求啊?我看到内置的上传的传参是 form-data 格式,然后参数名是 file[],但是如果同时传多张图片的时候,会传两个 file[]。传多张图片要做怎样的格式要求?

    1 回复
  • Tracy4ever

    那如果使用内置的上传,是不是上传成功,则后台返回

    {
    	code: 0,
    	msg: '',
    	data: {
    		errFiles: [],
    		succMap: {
    			'filname1': 'filePath1',
    			'filname2': 'filePath2'
    		}
    	}
    }
    

    上传失败则后台返回

    {
    	code: 1,
    	msg: '...',
    	data: {
    		errFiles: [filename1,filename2],
    		succMap: {
    		}
    	}
    }
    
  • Tracy4ever

    如果使用内置上传多张图片,部分上传成功,部分上传失败,那后台返回的应该是上传成功的代码还是失败的代码啊?

  • Vanessa
    作者
    • 使用 handler 就需要自己完成上传的处理,对后台参数没有要求
    • 多个文件使用 formData.append("file[]", uploadFileList[i]);
    • 上传会存在某些文件成功,某些文件失败的情况,因此 errFiles 和 succMap 会同时存在。只要 xhr.status === 200 就可以了
    1 回复
  • Tracy4ever

    TIM 图片 20190820113538.png
    后台返回了这样的格式,为什么预览的时候图片显示 404 呢?路径是乱码的

    1 回复
  • Vanessa
    作者

    你是怎么使用的?编辑器截图我看看

    1 回复
  • Tracy4ever

    我写成指令了TIM 图片 20190820141634.png
    TIM 图片 20190820141659.png
    TIM 图片 20190820141949.png

    2 回复
  • Vanessa
    作者

    是不是你的返回值和文件名不一致?可以用 options.upload.filename 处理一下

    内置上传的返回格式如下
    ⚠️ filename 需和文件名安全处理后的结果保持一致

    2 回复
  • Tracy4ever 5 评论

    就是返回那个路径中的文件名要和图片的文件名一致的意思吗?现在 succMap 中的文件名和图片的文件名是一致的

    是 succMap 中的 key 和输入框中中括号内的文件名保持一直。这样的话就可以显示出来图片了
    Vanessa
    @Vanessa 已经实现 key 和中括号内文件名一致,接口返回 200 了,但还是一直显示上传中,而且图片出不来,会查找当前路径 localhost:8888/ 乱码 ,发现乱码是 "上传中..." 的意思
    Tracy4ever
    @Vanessa 因为路径不对,所以会报 404,但是点击蓝色的图片名字,是会跳到对应路径去的,只是图片没出来
    Tracy4ever
    @Tracy4ever 我看你截图中没有乱码,返回值需为 data.succmap[TIM20190820113538.png],你再确认一下。你的现象应该是返回值和文件名不匹配
    Vanessa
    @Tracy4ever 我也遇到这个 请问大佬解决没
    huaxie2017
  • Tracy4ever 6 评论

    您帮忙看看是不是这样,应该名字是保持一致了,但是图片显示不出来的 alt 是上传前的图片名字,图三就是乱码的截图,乱码意思就是上传中...
    1.png
    2.png
    3.png

    0 引用
    你上传的文件名是 TIM20190820113538.png,返回的确是 admin-xxx,名字不一致
    Vanessa
    @Vanessa 哦哦,是这个也要保持一致,但是后台说那是为了避免上传重复图片所做的重命名处理,就算我用 filename 也没办法改成我上传前的名字,这个你们有处理办法吗?
    Tracy4ever
    @Tracy4ever TIM20190820113538.png 这个不用存后台数据库,前端传给后台,后台再返回就可以了。避免重复,路径可以使用 admin-xxx
    Vanessa
    @Vanessa 那就是 succMap{'TIM20190820113538.png':'http://.....admin-xx'}, 然后, 但是这个原来上传的图片名字叫 TIM 图片 20190820113538.png, 图片两个字不知道为什么没有了
    Tracy4ever
    @Tracy4ever 你可以使用 filename 方法进行修改,默认为 name.replace(/\W/g, "")
    Vanessa
    @Vanessa 终于可以了,当时没有清楚地理解这个含义:“⚠️ filename 需和文件名安全处理后的结果保持一致”,所以走了很多弯路,谢谢你!
    Tracy4ever
  • power721 1 评论

    终于找到一个满足功能的编辑器啦!

    燃烧你的卡路里
    Vanessa
  • XShellv

    请问我在使用 Markdown 表情快捷键时为啥表情效果出不来呢?😭

    1 回复
  • Vanessa
    作者

    可以详细描述一下么?是自动完成出不来么?

    1 回复
  • dengwentong
    捐赠者

    看起来就很 6😄

  • XShellv

    比如,编辑器左侧使用冒号加一冒号,右侧还是冒号加一冒号,并没有生成对应的表情 😭

    1 回复
  • XShellv

    还有就是 React 只能拿到 Markdown 字符串在 componentDidMount 中使用 Vditor.preview 生成 HTML,这种方式是否不利于 SEO?因为我查看网页源代码是成片的 Markdown 字符串。

  • Vanessa
    作者

    请关注 https://github.com/b3log/vditor/issues/112

    SEO 可以使用 lute 进行渲染。

  • haaid 1

    文字错误:接触编辑器禁用,「接触」->「解除」

  • haaid

    自定义了一个按键,click 写的 vditor.insertValue('@');,在控制台好用,click 回调里不好用,打断点调试看到 vditor 是存在的,方法执行了。

    1 回复
  • Vanessa
    作者
    onclick="vditor.insertValue('1')"
    

    我在代码 https://github.com/b3log/vditor/blob/master/demo/index.html 中加如以上代码测试是可以的。麻烦更新到最新版本,或给出相关代码。

    1 回复
  • haaid 1 评论

    我是写到了 Vue 的 mounted 方法中,这个代码在例子中(GitHub 的 demo/index.js)可以,Vue 中就不行,我断点看到有值的。

    01.png

    02.png

    Vanessa 1
  • buexplain

    image.png
    自定义上传返回的数据结构对不?有没有更详细的示例。


    看了 https://github.com/b3log/vditor/blob/master/src/ts/upload/index.ts#L109?utm_source=hacpai.com 后,明白了。
    上传完成后需要调用:vEditor.insertValue 方法即可。

    2 回复
    1 操作
    buexplain 在 2019-10-13 11:19:44 更新了该回帖
  • Vanessa
    作者

    可能还是有点问题的,这几天度假中,过两天回去看。谢谢

  • someone9891 1
    捐赠者

    此链接 404

  • xiluotop 1 评论

    我可以分享到我的博客嘛,我会标明来源的 😋

    欢迎分享
    Vanessa
  • Vanessa
    作者

    只对数据结构进行转换的话可以使用 options.upload.format

  • qkzzxb

    vditor 如何生成 toc 目录,看配置文件没有提到这个,要自己魔改吗huaji

    1 回复
  • Vanessa
    作者

    目前还没有该功能

    1 回复
  • qkzzxb

    比如说这个帖子右侧的目录是通过别的方法生成的吗?

    1 回复
  • Vanessa 1
    作者

    是的,这个和 vditor 没有关系

    1 回复
  • qkzzxb

    谢谢大佬,我在 symphony 的项目里找到了相关源码

  • 547176052

    image.png
    溢出是啥错误

  • 547176052

    image.png

    1 回复
  • Vanessa
    作者

    升级 node 版本再试一下

    1 回复
  • 547176052

    image.png
    这个是什么错误

    我调用了这个

    vditor.setValue("- ~~删除线~~ - `~~删除线~~`");
    
    1 回复
  • 547176052

    image.png
    我用的是最新版本了

  • Vanessa
    作者

    麻烦发一下完整的代码及 vditor 的版本

    1 回复
  • 547176052

    vditormaster1.zip
    用的是这个
    应该是最新版本吧

    1 回复
  • Vanessa
    作者

    image.png

    我下载后运行是正常的。可以描述以下你操作的具体步骤么?

    1 回复
  • 547176052

    image.png
    是不是 win10 系统不行
    需要 Linux 吗

    2 回复
  • Vanessa
    作者

    所有支持 npm 的系统都可以的。

    1 回复
  • someone27889 1
    捐赠者

    权限不足,用管理员 cmd 试试呢?

    1 回复
  • 547176052

    image.png
    郁闷 一直不成功

    1 回复
  • Vanessa
    作者

    下面这个没有错误信息,已经在 build 了,等 success 后打开 127.0.0.1:9000 就可以访问了

    2 回复
  • 547176052

    image.png
    不知道是哪里的问题

  • 547176052

    image.png

    1 回复
请输入回帖内容 ...