菜单配置

本文是各个菜单项的详细配置。如想要自定义工具栏的菜单(隐藏某些菜单、排序、分组等),请参考工具栏配置

通用方法

确定 menu key

要配置哪个菜单,首先要知道这个菜单的 key 。执行 editor.getAllMenuKeys() 可获取编辑器所有菜单,从中找到自己想要的菜单 key 即可。

获取菜单的默认配置

找到菜单 key 之后,可以先看看菜单的当前配置,再自行修改。

  1. editor.getMenuConfig('uploadImage') // 获取 uploadImage 的当前配置

修改配置

  1. import { IEditorConfig, createEditor, createToolbar } from '@wangeditor/editor'
  2. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} } // 初始化 MENU_CONF 属性
  3. // 修改 uploadImage 菜单配置
  4. editorConfig.MENU_CONF['uploadImage'] = {
  5. server: '/api/upload-image',
  6. fieldName: 'custom-field-name'
  7. // 继续写其他配置...
  8. //【注意】不需要修改的不用写,wangEditor 会去 merge 当前其他配置
  9. }
  10. // 修改 otherMenuKey 菜单配置
  11. editorConfig.MENU_CONF['otherMenuKey'] = {
  12. // 配置
  13. }
  14. // 创建编辑器
  15. const editor = createEditor({
  16. selector: '#editor-container',
  17. config: editorConfig,
  18. })
  19. // 创建菜单栏
  20. const toolbar = createToolbar({...})

TIP

请一定在 createEditor 之前完成菜单配置的修改,否则可能无效。

颜色

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. // 文字颜色
  3. editorConfig.MENU_CONF['color'] = {
  4. colors: ['#000', '#333', '#666']
  5. }
  6. // 背景色
  7. editorConfig.MENU_CONF['bgColor'] = {
  8. colors: ['#000', '#333', '#666']
  9. }
  10. // 执行 createEditor

字号

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['fontSize'] = {
  3. fontSizeList: ['12px', '16px', '24px', '40px']
  4. }
  5. // 执行 createEditor

字体

TIP

请注意,某些字体不能商用。具体请自行查找。

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['fontFamily'] = {
  3. fontFamilyList: [
  4. // 元素支持两种形式
  5. // 1. 字符串;
  6. // 2. { name: 'xxx', value: 'xxx' }
  7. '黑体',
  8. '楷体',
  9. { name: '仿宋', value: '仿宋' },
  10. 'Arial',
  11. 'Tahoma',
  12. 'Verdana'
  13. ]
  14. }
  15. // 执行 createEditor

行高

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['lineHeight'] = {
  3. lineHeightList: ['1', '1.5', '2', '2.5']
  4. }
  5. // 执行 createEditor

表情

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['emotion'] = {
  3. emotions: '😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉'.split(' ') // 数组
  4. }
  5. // 执行 createEditor

链接

  • checkLink 校验链接
  • parseLinkUrl 转换链接 url
  1. // 自定义校验链接
  2. function customCheckLinkFn(text: string, url: string): string | boolean | undefined {
  3. if (!url) {
  4. return
  5. }
  6. if (url.indexOf('http') !== 0) {
  7. return '链接必须以 http/https 开头'
  8. }
  9. return true
  10. // 返回值有三种选择:
  11. // 1. 返回 true ,说明检查通过,编辑器将正常插入链接
  12. // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  13. // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
  14. }
  15. // 自定义转换链接 url
  16. function customParseLinkUrl(url: string): string {
  17. if (url.indexOf('http') !== 0) {
  18. return `http://${url}`
  19. }
  20. return url
  21. }
  22. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  23. // 插入链接
  24. editorConfig.MENU_CONF['insertLink'] = {
  25. checkLink: customCheckLinkFn, // 也支持 async 函数
  26. parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
  27. }
  28. // 更新链接
  29. editorConfig.MENU_CONF['editLink'] = {
  30. checkLink: customCheckLinkFn, // 也支持 async 函数
  31. parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
  32. }
  33. // 执行 createEditor

图片

如果用于 Typescript ,需定义图片元素类型。可单独放在 .d.ts 中定义。

  1. import { SlateElement } from '@wangeditor/editor'
  2. type ImageElement = SlateElement & {
  3. src: string
  4. alt: string
  5. url: string
  6. href: string
  7. }

图片菜单的配置

  • onInsertedImage 插入图片之后的回调
  • onUpdatedImage 更新图片之后的回调
  • checkImage 校验图片链接
  • parseImageSrc 转换图片链接
  1. // 自定义校验图片
  2. function customCheckImageFn(src: string, alt: string, url: string): boolean | undefined | string {
  3. if (!src) {
  4. return
  5. }
  6. if (src.indexOf('http') !== 0) {
  7. return '图片网址必须以 http/https 开头'
  8. }
  9. return true
  10. // 返回值有三种选择:
  11. // 1. 返回 true ,说明检查通过,编辑器将正常插入图片
  12. // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  13. // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
  14. }
  15. // 转换图片链接
  16. function customParseImageSrc(src: string): string {
  17. if (src.indexOf('http') !== 0) {
  18. return `http://${src}`
  19. }
  20. return src
  21. }
  22. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  23. // 插入图片
  24. editorConfig.MENU_CONF['insertImage'] = {
  25. onInsertedImage(imageNode: ImageElement | null) {
  26. if (imageNode == null) return
  27. const { src, alt, url, href } = imageNode
  28. console.log('inserted image', src, alt, url, href)
  29. },
  30. checkImage: customCheckImageFn, // 也支持 async 函数
  31. parseImageSrc: customParseImageSrc, // 也支持 async 函数
  32. }
  33. // 编辑图片
  34. editorConfig.MENU_CONF['editImage'] = {
  35. onUpdatedImage(imageNode: ImageElement | null) {
  36. if (imageNode == null) return
  37. const { src, alt, url } = imageNode
  38. console.log('updated image', src, alt, url)
  39. },
  40. checkImage: customCheckImageFn, // 也支持 async 函数
  41. parseImageSrc: customParseImageSrc, // 也支持 async 函数
  42. }
  43. // 执行 createEditor

上传图片

上传图片的配置比较复杂,拆分为几个部分来讲解。

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['uploadImage'] = {
  3. // 上传图片的配置
  4. }
  5. // 执行 createEditor

服务端地址

必填,否则上传图片会报错。

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. server: '/api/upload',
  3. }

【特别注意】服务端 response body 格式要求如下:
上传成功的返回格式:

  1. {
  2. "errno": 0, // 注意:值是数字,不能是字符串
  3. "data": {
  4. "url": "xxx", // 图片 src ,必须
  5. "alt": "yyy", // 图片描述文字,非必须
  6. "href": "zzz" // 图片的链接,非必须
  7. }
  8. }

上传失败的返回格式:

  1. {
  2. "errno": 1, // 只要不等于 0 就行
  3. "message": "失败信息"
  4. }

TIP

如果你的服务端 response body 无法按照上述格式,可以使用下文的 customInsert

基本配置

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // form-data fieldName ,默认值 'wangeditor-uploaded-image'
  3. fieldName: 'your-custom-name',
  4. // 单个文件的最大体积限制,默认为 2M
  5. maxFileSize: 1 * 1024 * 1024, // 1M
  6. // 最多可上传几个文件,默认为 100
  7. maxNumberOfFiles: 10,
  8. // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
  9. allowedFileTypes: ['image/*'],
  10. // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
  11. meta: {
  12. token: 'xxx',
  13. otherKey: 'yyy'
  14. },
  15. // 将 meta 拼接到 url 参数中,默认 false
  16. metaWithUrl: false,
  17. // 自定义增加 http header
  18. headers: {
  19. Accept: 'text/x-json',
  20. otherKey: 'xxx'
  21. },
  22. // 跨域是否传递 cookie ,默认为 false
  23. withCredentials: true,
  24. // 超时时间,默认为 10 秒
  25. timeout: 5 * 1000, // 5 秒
  26. }

回调函数

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // 上传之前触发
  3. onBeforeUpload(file) {
  4. // file 选中的文件,格式如 { key: file }
  5. return file
  6. // 可以 return
  7. // 1. return file 或者 new 一个 file ,接下来将上传
  8. // 2. return false ,不上传这个 file
  9. },
  10. // 上传进度的回调函数
  11. onProgress(progress: number) {
  12. // progress 是 0-100 的数字
  13. console.log('progress', progress)
  14. },
  15. // 单个文件上传成功之后
  16. onSuccess(file: File, res: any) {
  17. console.log(`${file.name} 上传成功`, res)
  18. },
  19. // 单个文件上传失败
  20. onFailed(file: File, res: any) {
  21. console.log(`${file.name} 上传失败`, res)
  22. },
  23. // 上传错误,或者触发 timeout 超时
  24. onError(file: File, err: any, res: any) {
  25. console.log(`${file.name} 上传出错`, err, res)
  26. },
  27. }

自定义功能

如果用于 Typescript ,则要定义插入函数的类型。

  1. type InsertFnType = (url: string, alt: string, href: string) => void

自定义插入

如果你的服务端 response body 无法按照上文规定的格式,则无法插入图片,提示失败。
但你可以使用 customInsert 来自定义插入图片。

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // 自定义插入图片
  3. customInsert(res: any, insertFn: InsertFnType) {
  4. // res 即服务端的返回结果
  5. // 从 res 中找到 url alt href ,然后插图图片
  6. insertFn(url, alt, href)
  7. },
  8. }

自定义上传

如果你不想使用 wangEditor 自带的上传功能,例如你要上传到阿里云 OSS 。
可以通过 customUpload 来自定义上传。

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // 自定义上传
  3. async customUpload(file: File, insertFn: InsertFnType) {
  4. // file 即选中的文件
  5. // 自己实现上传,并得到图片 url alt href
  6. // 最后插入图片
  7. insertFn(url, alt, href)
  8. }
  9. }

自定义选择图片

如果你不想使用 wangEditor 自带的选择文件功能,例如你有自己的图床,或者图片选择器。
可以通过 customBrowseAndUpload 来自己实现选择图片、上传图片,并插入图片。

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // 自定义选择图片
  3. customBrowseAndUpload(insertFn: InsertFnType) {
  4. // 自己选择文件
  5. // 自己上传文件,并得到图片 url alt href
  6. // 最后插入图片
  7. insertFn(url, alt, href)
  8. }
  9. }

base64 插入图片

  1. editorConfig.MENU_CONF['uploadImage'] = {
  2. // 其他配置...
  3. // 小于该值就插入 base64 格式(而不上传),默认为 0
  4. base64LimitSize: 5 * 1024 // 5kb
  5. }

获取已删除的图片

这是一个常见的需求。
上传图片到编辑器,然后又把图片删除了。此时你可能想要拿到这张删除的图片,在服务器也把图片文件删了。

  • 使用 onInsertedImage 来收集所有上传或者插入的图片,记录为 imageList1
  • 最后保存编辑器内容之前,使用 editor.getElemsByType('image') 获取当前编辑器的所有图片,记录为 imageList2
  • 对比 imageList1imageList2 ,两者的差异,就是删除过的图片

可能会有疑问:为何要在最后去对比?我想要在图片删除时就及时得到反馈。
但,这样是不行的,因为图片删除了,还可能会被撤销回来。所以,一定要在最后去操作。

视频

如果用于 Typescript ,需定义视频元素类型。可单独放在 .d.ts 中定义。

  1. import { SlateElement } from '@wangeditor/editor'
  2. type VideoElement = SlateElement & {
  3. src: string
  4. }

菜单配置

  • onInsertedVideo 插入视频之后的回调
  • checkVideo 校验视频链接
  • parseVideoSrc 转换视频链接
  1. // 自定义校验视频
  2. function customCheckVideoFn(src: string): boolean | string | undefined {
  3. if (!src) {
  4. return
  5. }
  6. if (src.indexOf('http') !== 0) {
  7. return '视频地址必须以 http/https 开头'
  8. }
  9. return true
  10. // 返回值有三种选择:
  11. // 1. 返回 true ,说明检查通过,编辑器将正常插入视频
  12. // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  13. // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
  14. }
  15. // 自定义转换视频
  16. function customParseVideoSrc(src: string): string {
  17. if (src.includes('.bilibili.com')) {
  18. // 转换 bilibili url 为 iframe (仅作为示例,不保证代码正确和完整)
  19. const arr = location.pathname.split('/')
  20. const vid = arr[arr.length - 1]
  21. return `<iframe src="//player.bilibili.com/player.html?bvid=${vid}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>`
  22. }
  23. return src
  24. }
  25. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  26. editorConfig.MENU_CONF['insertVideo'] = {
  27. onInsertedVideo(videoNode: VideoElement | null) {
  28. if (videoNode == null) return
  29. const { src } = videoNode
  30. console.log('inserted video', src)
  31. },
  32. checkVideo: customCheckVideoFn, // 也支持 async 函数
  33. parseVideoSrc: customParseVideoSrc, // 也支持 async 函数
  34. }
  35. // 执行 createEditor

上传视频

上传视频的配置比较复杂,拆分为几个部分来讲解。

  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['uploadVideo'] = {
  3. // 上传视频的配置
  4. }
  5. // 执行 createEditor

服务端地址

必填,否则上传视频会报错。

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. server: '/api/upload',
  3. }

【特别注意】服务端 response body 格式要求如下:
上传成功的返回格式:

  1. {
  2. "errno": 0, // 注意:值是数字,不能是字符串
  3. "data": {
  4. "url": "xxx", // 视频 src ,必须
  5. }
  6. }

上传失败的返回格式:

  1. {
  2. "errno": 1, // 只要不等于 0 就行
  3. "message": "失败信息"
  4. }

TIP

如果你的服务端 response body 无法按照上述格式,可以使用下文的 customInsert

基本配置

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. // form-data fieldName ,默认值 'wangeditor-uploaded-video'
  3. fieldName: 'your-custom-name',
  4. // 单个文件的最大体积限制,默认为 10M
  5. maxFileSize: 5 * 1024 * 1024, // 5M
  6. // 最多可上传几个文件,默认为 5
  7. maxNumberOfFiles: 3,
  8. // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
  9. allowedFileTypes: ['video/*'],
  10. // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
  11. meta: {
  12. token: 'xxx',
  13. otherKey: 'yyy'
  14. },
  15. // 将 meta 拼接到 url 参数中,默认 false
  16. metaWithUrl: false,
  17. // 自定义增加 http header
  18. headers: {
  19. Accept: 'text/x-json',
  20. otherKey: 'xxx'
  21. },
  22. // 跨域是否传递 cookie ,默认为 false
  23. withCredentials: true,
  24. // 超时时间,默认为 30 秒
  25. timeout: 15 * 1000, // 15 秒
  26. // 视频不支持 base64 格式插入
  27. }

回调函数

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. // 上传之前触发
  3. onBeforeUpload(file) {
  4. // file 选中的文件,格式如 { key: file }
  5. return file
  6. // 可以 return
  7. // 1. return file 或者 new 一个 file ,接下来将上传
  8. // 2. return false ,不上传这个 file
  9. },
  10. // 上传进度的回调函数
  11. onProgress(progress: number) {
  12. // progress 是 0-100 的数字
  13. console.log('progress', progress)
  14. },
  15. // 单个文件上传成功之后
  16. onSuccess(file: File, res: any) {
  17. console.log(`${file.name} 上传成功`, res)
  18. },
  19. // 单个文件上传失败
  20. onFailed(file: File, res: any) {
  21. console.log(`${file.name} 上传失败`, res)
  22. },
  23. // 上传错误,或者触发 timeout 超时
  24. onError(file: File, err: any, res: any) {
  25. console.log(`${file.name} 上传出错`, err, res)
  26. },
  27. }

自定义功能

如果用于 Typescript ,则要定义插入函数的类型。

  1. type InsertFnType = (url: string) => void

自定义插入

如果你的服务端 response body 无法按照上文规定的格式,则无法插入视频,提示失败。
但你可以使用 customInsert 来自定义插入视频。

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. // 自定义插入视频
  3. customInsert(res: any, insertFn: InsertFnType) {
  4. // res 即服务端的返回结果
  5. // 从 res 中找到 url ,然后插入视频
  6. insertFn(url)
  7. },
  8. }

自定义上传

如果你不想使用 wangEditor 自带的上传功能,例如你要上传到阿里云 OSS 。
可以通过 customUpload 来自定义上传。

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. // 自定义上传
  3. async customUpload(file: File, insertFn: InsertFnType) {
  4. // file 即选中的文件
  5. // 自己实现上传,并得到视频 url
  6. // 最后插入视频
  7. insertFn(url)
  8. }
  9. }

自定义选择视频

如果你不想使用 wangEditor 自带的选择文件功能,例如你有自己的图床,或者视频文件选择器。
可以通过 customBrowseAndUpload 来自己实现选择视频、上传视频,并插入视频。

  1. editorConfig.MENU_CONF['uploadVideo'] = {
  2. // 自定义选择视频
  3. customBrowseAndUpload(insertFn: InsertFnType) {
  4. // 自己选择文件
  5. // 自己上传文件,并得到视频 url
  6. // 最后插入视频
  7. insertFn(url)
  8. }
  9. }

代码高亮

  • codeLangs 配置代码语言
  1. const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} }
  2. editorConfig.MENU_CONF['codeSelectLang'] = {
  3. // 代码语言
  4. codeLangs: [
  5. { text: 'CSS', value: 'css' },
  6. { text: 'HTML', value: 'html' },
  7. { text: 'XML', value: 'xml' },
  8. // 其他
  9. ]
  10. }
  11. // 执行 createEditor

TIP

配置代码语言时,只能从 editor.getMenuConfig('codeSelectLang').codeLangs 中选择,不能自己随意增加。 如有其他语言的需要,可以给我们提交 issue ,这需要修改源码。

其他

其他菜单的配置,请参考上文的 通用方法 自行修改。