菜单配置

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

通用方法

确定 menu key

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

获取菜单的默认配置

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

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

修改配置

import { IEditorConfig } from '@wangeditor/editor'

// 初始化 MENU_CONF 属性
const editorConfig: Partial<IEditorConfig> = {
  // TS 语法
  // const editorConfig = {                       // JS 语法
  MENU_CONF: {},

  // 其他属性...
}

// 修改 uploadImage 菜单配置
editorConfig.MENU_CONF['uploadImage'] = {
  server: '/api/upload-image',
  fieldName: 'custom-field-name',
  // 继续写其他配置...

  //【注意】不需要修改的不用写,wangEditor 会去 merge 当前其他配置
}

// 修改 otherMenuKey 菜单配置
editorConfig.MENU_CONF['otherMenuKey'] = {
  // 配置
}

// 创建 editor 或传入 Vue React <Editor> 组件

颜色

// 文字颜色
editorConfig.MENU_CONF['color'] = {
  colors: ['#000', '#333', '#666'],
}

// 背景色
editorConfig.MENU_CONF['bgColor'] = {
  colors: ['#000', '#333', '#666'],
}

字号

editorConfig.MENU_CONF['fontSize'] = {
  fontSizeList: [
    // 元素支持两种形式
    //   1. 字符串;
    //   2. { name: 'xxx', value: 'xxx' }

    '12px',
    '16px',
    { name: '24px', value: '24px' },
    '40px',
  ],
}

字体

TIP

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

editorConfig.MENU_CONF['fontFamily'] = {
  fontFamilyList: [
    // 元素支持两种形式
    //   1. 字符串;
    //   2. { name: 'xxx', value: 'xxx' }

    '黑体',
    '楷体',
    { name: '仿宋', value: '仿宋' },
    'Arial',
    'Tahoma',
    'Verdana',
  ],
}

行高

editorConfig.MENU_CONF['lineHeight'] = {
  lineHeightList: ['1', '1.5', '2', '2.5'],
}

表情

editorConfig.MENU_CONF['emotion'] = {
  emotions: '😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉'.split(' '), // 数组
}

链接

  • checkLink 校验链接
  • parseLinkUrl 转换链接 url
// 自定义校验链接
function customCheckLinkFn(
  text: string,
  url: string
): string | boolean | undefined {
  // TS 语法
  // function customCheckLinkFn(text, url) {                                              // JS 语法

  if (!url) {
    return
  }
  if (url.indexOf('http') !== 0) {
    return '链接必须以 http/https 开头'
  }
  return true

  // 返回值有三种选择:
  // 1. 返回 true ,说明检查通过,编辑器将正常插入链接
  // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
}

// 自定义转换链接 url
function customParseLinkUrl(url: string): string {
  // TS 语法
  // function customParseLinkUrl(url) {                // JS 语法

  if (url.indexOf('http') !== 0) {
    return `http://${url}`
  }
  return url
}

// 插入链接
editorConfig.MENU_CONF['insertLink'] = {
  checkLink: customCheckLinkFn, // 也支持 async 函数
  parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
}
// 更新链接
editorConfig.MENU_CONF['editLink'] = {
  checkLink: customCheckLinkFn, // 也支持 async 函数
  parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
}

图片

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

import { SlateElement } from '@wangeditor/editor'

type ImageElement = SlateElement & {
  src: string
  alt: string
  url: string
  href: string
}

图片菜单的配置

  • onInsertedImage 插入图片之后的回调
  • onUpdatedImage 更新图片之后的回调
  • checkImage 校验图片链接
  • parseImageSrc 转换图片链接
// 自定义校验图片
function customCheckImageFn(
  src: string,
  alt: string,
  url: string
): boolean | undefined | string {
  // TS 语法
  // function customCheckImageFn(src, alt, url) {                                                    // JS 语法
  if (!src) {
    return
  }
  if (src.indexOf('http') !== 0) {
    return '图片网址必须以 http/https 开头'
  }
  return true

  // 返回值有三种选择:
  // 1. 返回 true ,说明检查通过,编辑器将正常插入图片
  // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
}

// 转换图片链接
function customParseImageSrc(src: string): string {
  // TS 语法
  // function customParseImageSrc(src) {               // JS 语法
  if (src.indexOf('http') !== 0) {
    return `http://${src}`
  }
  return src
}

// 插入图片
editorConfig.MENU_CONF['insertImage'] = {
  onInsertedImage(imageNode: ImageElement | null) {
    // TS 语法
    // onInsertedImage(imageNode) {                    // JS 语法
    if (imageNode == null) return

    const { src, alt, url, href } = imageNode
    console.log('inserted image', src, alt, url, href)
  },
  checkImage: customCheckImageFn, // 也支持 async 函数
  parseImageSrc: customParseImageSrc, // 也支持 async 函数
}
// 编辑图片
editorConfig.MENU_CONF['editImage'] = {
  onUpdatedImage(imageNode: ImageElement | null) {
    // TS 语法
    // onUpdatedImage(imageNode) {                    // JS 语法
    if (imageNode == null) return

    const { src, alt, url } = imageNode
    console.log('updated image', src, alt, url)
  },
  checkImage: customCheckImageFn, // 也支持 async 函数
  parseImageSrc: customParseImageSrc, // 也支持 async 函数
}

上传图片

上传图片的配置比较复杂,拆分为几个部分来讲解。可参考这个 demoopen in new window

editorConfig.MENU_CONF['uploadImage'] = {
    // 上传图片的配置
}

 

服务端地址

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

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

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

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

上传失败的返回格式:

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

TIP

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

基本配置

editorConfig.MENU_CONF['uploadImage'] = {
  // form-data fieldName ,默认值 'wangeditor-uploaded-image'
  fieldName: 'your-custom-name',

  // 单个文件的最大体积限制,默认为 2M
  maxFileSize: 1 * 1024 * 1024, // 1M

  // 最多可上传几个文件,默认为 100
  maxNumberOfFiles: 10,

  // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
  allowedFileTypes: ['image/*'],

  // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
  meta: {
    token: 'xxx',
    otherKey: 'yyy',
  },

  // 将 meta 拼接到 url 参数中,默认 false
  metaWithUrl: false,

  // 自定义增加 http  header
  headers: {
    Accept: 'text/x-json',
    otherKey: 'xxx',
  },

  // 跨域是否传递 cookie ,默认为 false
  withCredentials: true,

  // 超时时间,默认为 10 秒
  timeout: 5 * 1000, // 5 秒
}

回调函数

editorConfig.MENU_CONF['uploadImage'] = {
  // 上传之前触发
  onBeforeUpload(file: File) {
    // TS 语法
    // onBeforeUpload(file) {    // JS 语法
    // file 选中的文件,格式如 { key: file }
    return file

    // 可以 return
    // 1. return file 或者 new 一个 file ,接下来将上传
    // 2. return false ,不上传这个 file
  },

  // 上传进度的回调函数
  onProgress(progress: number) {
    // TS 语法
    // onProgress(progress) {       // JS 语法
    // progress 是 0-100 的数字
    console.log('progress', progress)
  },

  // 单个文件上传成功之后
  onSuccess(file: File, res: any) {
    // TS 语法
    // onSuccess(file, res) {          // JS 语法
    console.log(`${file.name} 上传成功`, res)
  },

  // 单个文件上传失败
  onFailed(file: File, res: any) {
    // TS 语法
    // onFailed(file, res) {           // JS 语法
    console.log(`${file.name} 上传失败`, res)
  },

  // 上传错误,或者触发 timeout 超时
  onError(file: File, err: any, res: any) {
    // TS 语法
    // onError(file, err, res) {               // JS 语法
    console.log(`${file.name} 上传出错`, err, res)
  },
}

自定义功能

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

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

自定义插入

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

editorConfig.MENU_CONF['uploadImage'] = {
  // 自定义插入图片
  customInsert(res: any, insertFn: InsertFnType) {
    // TS 语法
    // customInsert(res, insertFn) {                  // JS 语法
    // res 即服务端的返回结果

    // 从 res 中找到 url alt href ,然后插入图片
    insertFn(url, alt, href)
  },
}

自定义上传

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

editorConfig.MENU_CONF['uploadImage'] = {
  // 自定义上传
  async customUpload(file: File, insertFn: InsertFnType) {
    // TS 语法
    // async customUpload(file, insertFn) {                   // JS 语法
    // file 即选中的文件
    // 自己实现上传,并得到图片 url alt href
    // 最后插入图片
    insertFn(url, alt, href)
  },
}

自定义选择图片

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

editorConfig.MENU_CONF['uploadImage'] = {
  // 自定义选择图片
  customBrowseAndUpload(insertFn: InsertFnType) {
    // TS 语法
    // customBrowseAndUpload(insertFn) {              // JS 语法
    // 自己选择文件
    // 自己上传文件,并得到图片 url alt href
    // 最后插入图片
    insertFn(url, alt, href)
  },
}

base64 插入图片

editorConfig.MENU_CONF['uploadImage'] = {
  // 其他配置...

  // 小于该值就插入 base64 格式(而不上传),默认为 0
  base64LimitSize: 5 * 1024, // 5kb
}

获取已删除的图片

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

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

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

视频

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

import { SlateElement } from '@wangeditor/editor'

type VideoElement = SlateElement & {
  src: string
  poster?: string
}

菜单配置

  • onInsertedVideo 插入视频之后的回调
  • checkVideo 校验视频链接
  • parseVideoSrc 转换视频链接
// 自定义校验视频
function customCheckVideoFn(
  src: string,
  poster: string
): boolean | string | undefined {
  // TS 语法
  // function customCheckVideoFn(src, poster) {                                             // JS 语法
  if (!src) {
    return
  }
  if (src.indexOf('http') !== 0) {
    return '视频地址必须以 http/https 开头'
  }
  return true

  // 返回值有三种选择:
  // 1. 返回 true ,说明检查通过,编辑器将正常插入视频
  // 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)
  // 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息
}

// 自定义转换视频
function customParseVideoSrc(src: string): string {
  // TS 语法
  // function customParseVideoSrc(src) {               // JS 语法
  if (src.includes('.bilibili.com')) {
    // 转换 bilibili url 为 iframe (仅作为示例,不保证代码正确和完整)
    const arr = location.pathname.split('/')
    const vid = arr[arr.length - 1]
    return `<iframe src="//player.bilibili.com/player.html?bvid=${vid}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>`
  }
  return src
}

editorConfig.MENU_CONF['insertVideo'] = {
  onInsertedVideo(videoNode: VideoElement | null) {
    // TS 语法
    // onInsertedVideo(videoNode) {                    // JS 语法
    if (videoNode == null) return

    const { src } = videoNode
    console.log('inserted video', src)
  },
  checkVideo: customCheckVideoFn, // 也支持 async 函数
  parseVideoSrc: customParseVideoSrc, // 也支持 async 函数
}

上传视频

上传视频的配置比较复杂,拆分为几个部分来讲解。可参考这个 demoopen in new window

editorConfig.MENU_CONF['uploadVideo'] = {
    // 上传视频的配置
}

 

服务端地址

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

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

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

{
  "errno": 0, // 注意:值是数字,不能是字符串
  "data": {
    "url": "xxx", // 视频 src ,必须
    "poster": "xxx.png" // 视频封面图片 url ,可选
  }
}

// 注意:@wangeditor/editor 版本 >= 5.1.8 才支持 video poster

上传失败的返回格式:

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

TIP

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

基本配置

editorConfig.MENU_CONF['uploadVideo'] = {
  // form-data fieldName ,默认值 'wangeditor-uploaded-video'
  fieldName: 'your-custom-name',

  // 单个文件的最大体积限制,默认为 10M
  maxFileSize: 5 * 1024 * 1024, // 5M

  // 最多可上传几个文件,默认为 5
  maxNumberOfFiles: 3,

  // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
  allowedFileTypes: ['video/*'],

  // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
  meta: {
    token: 'xxx',
    otherKey: 'yyy',
  },

  // 将 meta 拼接到 url 参数中,默认 false
  metaWithUrl: false,

  // 自定义增加 http  header
  headers: {
    Accept: 'text/x-json',
    otherKey: 'xxx',
  },

  // 跨域是否传递 cookie ,默认为 false
  withCredentials: true,

  // 超时时间,默认为 30 秒
  timeout: 15 * 1000, // 15 秒

  // 视频不支持 base64 格式插入
}

回调函数

editorConfig.MENU_CONF['uploadVideo'] = {
  // 上传之前触发
  onBeforeUpload(file: File) {
    // TS 语法
    // onBeforeUpload(file) {      // JS 语法
    // file 选中的文件,格式如 { key: file }
    return file

    // 可以 return
    // 1. return file 或者 new 一个 file ,接下来将上传
    // 2. return false ,不上传这个 file
  },

  // 上传进度的回调函数
  onProgress(progress: number) {
    // TS 语法
    // onProgress(progress) {       // JS 语法
    // progress 是 0-100 的数字
    console.log('progress', progress)
  },

  // 单个文件上传成功之后
  onSuccess(file: File, res: any) {
    // TS 语法
    // onSuccess(file, res) {          // JS 语法
    console.log(`${file.name} 上传成功`, res)
  },

  // 单个文件上传失败
  onFailed(file: File, res: any) {
    // TS 语法
    // onFailed(file, res) {          // JS 语法
    console.log(`${file.name} 上传失败`, res)
  },

  // 上传错误,或者触发 timeout 超时
  onError(file: File, err: any, res: any) {
    // TS 语法
    // onError(file, err, res) {               // JS 语法
    console.log(`${file.name} 上传出错`, err, res)
  },
}

自定义功能

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

type InsertFnType = (url: string, poster: string = '') => void

自定义插入

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

editorConfig.MENU_CONF['uploadVideo'] = {
  // 自定义插入视频
  customInsert(res: any, insertFn: InsertFnType) {
    // TS 语法
    // customInsert(res, insertFn) {                  // JS 语法
    // res 即服务端的返回结果

    // 从 res 中找到 url poster ,然后插入视频
    insertFn(url, poster)
  },
}

自定义上传

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

editorConfig.MENU_CONF['uploadVideo'] = {
  // 自定义上传
  async customUpload(file: File, insertFn: InsertFnType) {
    // TS 语法
    // async customUpload(file, insertFn) {                   // JS 语法
    // file 即选中的文件
    // 自己实现上传,并得到视频 url poster
    // 最后插入视频
    insertFn(url, poster)
  },
}

自定义选择视频

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

editorConfig.MENU_CONF['uploadVideo'] = {
  // 自定义选择视频
  customBrowseAndUpload(insertFn: InsertFnType) {
    // TS 语法
    // customBrowseAndUpload(insertFn) {             // JS 语法
    // 自己选择文件
    // 自己上传文件,并得到视频 url poster
    // 最后插入视频
    insertFn(url, poster)
  },
}

代码高亮

  • codeLangs 配置代码语言
editorConfig.MENU_CONF['codeSelectLang'] = {
  // 代码语言
  codeLangs: [
    { text: 'CSS', value: 'css' },
    { text: 'HTML', value: 'html' },
    { text: 'XML', value: 'xml' },
    // 其他
  ],
}

TIP

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

其他

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

Last Updated:
Contributors: 王福朋