魔改 Simditor 编辑器,增强自定义上传

字数 117 阅读 854

2018-07-13 今天得空,就来梳理下这个东东。

这个现场情况是这样的:

  • 需要将附件通过web直传到Aliyun-OSS
  • web-client upload file -> Aliyun-OSS Server -> response file-token -> web-client upload file-token to private-server -> response source-url -> web-client preview
  • 这个需求,就必须得自行编写个Simditor-upload插件了
  • Simditor-upload插件 : simditor-http-upload.js
  • Simditor配置: simditor.config.js

    simditor-http-upload.js

    /* eslint-disable */
    import $ from 'jquery'
    import Simditor from 'simditor'
    const inputAttribute = {
      accept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg',
      multiple: false
    class HttpUploadButton extends Simditor.Button {
      constructor(...args) {
        super(...args)
        this.i18n = {
          'zh-CN': {
            httpupload: '上传文件'
          'en-US': {
            httpupload: 'upload file'
        this.init()
      init() {
        const {
          httpUpload
        } = this.editor.opts
        if (!httpUpload && !httpUpload.bindUpload) {
          throw new Error('upload httpUpload must config httpUpload.')
        this.input = $('<input />', {
          type: 'file',
          class: 'plugin-http-upload',
          accept: inputAttribute.accept,
          multiple: inputAttribute.multiple,
          style: 'top:0;right:0;opacity:0;filter:alpha(opacity=0);cursor:pointer;'
        }).prependTo(this.editor.el)
        this.editor.el.on('click mouseup', '.toolbar-item-httpupload', (e) => {
          if (!this.editor.selection.range()) {
            console.warn('current not is focus.')
            httpUpload.error('请点击编辑区域,然后上传')
            return undefined
          this.$rootNodes = this.editor.selection.blockNodes()
          this.editor.selection.save()
          this.input.trigger('click')
          e.stopPropagation()
        this.editor.el.on('change', '.plugin-http-upload', () => {
          httpUpload.bindUpload(this.input, (data) => {
            this.input.val('')
            if (['', null, undefined].indexOf(data) === -1) {
              let $insert = ''
              if (Array.isArray(data)) {
                const imgs = data.map(link => `<img src="${link}">`)
                $insert = $(`${imgs.join('')}`)
              } else if (typeof data === 'string') {
                $insert = /^http/.test(data) ? $(`<img src="${data}">`) : $(`<span>${data}</span>`)
              this.editor.selection.restore()
              this.editor.selection.insertNode($insert)
            this.editor.trigger('valuechanged')
            this.editor.trigger('selectionchanged')
    HttpUploadButton.prototype.type = 'ul.simditor-uploadfile'
    HttpUploadButton.prototype.name = 'httpupload'
    // HttpUploadButton.prototype.icon = 'upload'
    HttpUploadButton.prototype.icon = 'picture-o'
    export default (option = {}) => {
      Object.assign(inputAttribute, option)
      Simditor.Toolbar.addButton(HttpUploadButton)
    

    simditor.config.js

    /* eslint-disable */
    import { Toast } from 'mint-ui'
    import Simditor from 'simditor'
    import SimditorHttpUpload from './simditor-http-upload'
    class SimditorConfig {
      constructor(context, el) {
        // 组件环境
        this.context = context
        // 编辑器实例
        this.instance = this.init(el)
      init(el) {
        SimditorHttpUpload({
          accept: 'image/jpeg,image/jpg,image/png'
        return new Simditor({
          textarea: document.querySelector(el),
          toolbar: ['bold', 'italic', '|', 'httpupload'],
          placeholder: '请输入正文',
          toolbarFloat: true,
          toolbarFloatOffset: 0,
          pasteImage: false,
          httpUpload: {
            bindUpload: this.bindAttachUpload.bind(this),
            error: (err) => {
              console.warn(`httpUpload Error: ${err}`)
              Toast(err)
      // 绑定上传
      bindAttachUpload(uploadInput, callback) {
        if (callback) {
          this.handleUpload(uploadInput[0].files)
            .then((list) => {
              callback(list)
            .catch(err => console.warn(err))
      // 销毁
      destroy() {
        this.instance.destroy()
      // 真实上传
      handleUpload(files) {
        return new Promise((resolve, reject) => {
          if (this.context.httpUpload) {
            this.context.httpUpload({
              files,
              success: (list) => {
                resolve(list)
          } else {
            reject('not found methods: httpUpload.')
            throw new Error(`${this.context} not found methods: httpUpload.`)
    export default SimditorConfig
    

    Index.vue

    import SimditorConfig from './simditor.config'
    export default {
      name: 'RichText',
      mounted() {
        this.$nextTick(() => {
          this.editor = new SimditorConfig(this, '#editor')
      methods: {
        // 三方上传
        httpUpload({ files, success } = {}) {
          if (!this.oss) {
            this.$topTips('关键信息初始化失败,请刷新重试')
            return undefined
          const upload = (fileList) => {
            fileList.forEach((file) => {
              file.progress = (p) => {
                this.progress = p * 100
            this.handleUploadFileMultiple({ files: fileList })
              .then((response) => {
                const imgs = response.map(obj => obj.url)
                success(imgs)
              .catch((err) => {
                console.error(err)