vue+elementui Admin 結合的項目中使用TinyMce 富文本上傳本地圖片

1.其實element-admin中已經整合了tinyMce 富文本的配置,可是再項目需求中須要本身上傳本地圖片,就像這樣(用黴黴來鎮樓)html

2.本次項目上傳圖片的思想:先拿到本地的圖片轉換爲base64 的格式,傳遞給後端,後端保存後再返回給咱們一個圖片地址,最終咱們須要的就是這個地址作顯示和保存vue

image.png
image.png

具體的操做:由於安裝和基本的富文本配置都由elementui +admin 給咱們作了,我這裏主要是再貼一些本次我用到的工具和配置web

1)plugins:後端

const  plugins= ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount ']

2)工具條 toolbarapi

const  toolbar = ['searchreplace fontselect formatselect fontsizeselect bold italic underline strikethrough forecolor backcolor', ' hr alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscriptcode codesample bullist numlist ', ' table link image charmap preview anchor pagebreak insertdatetime media emoticons fullscreen ']

3)最後全部的配置,和圖片的上傳app

export default {
  name: 'Tinymce',
  // components: { editorImage },
  props: {
    id: {
      type: String,
      default: function () {
        return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
      }
    },
    value: {
      type: String,
      default: ''
    },
    config: {
      type: Object,
      default: () => {
        return {
          theme: 'modern',
          height: 400
        }
      }
    },
    toolbar: {
      type: Array,
      required: false,
      default () {
        return []
      }
    },
    accept: {
      default: 'image/jpeg, image/png',
      type: String
    },
    url: {
      default: '',
      type: String
    },

    maxSize: {
      default: 2097152,
      type: Number
    },
    withCredentials: {
      default: false,
      type: Boolean
    },

    menubar: {
      type: String,
      default: 'file edit insert view format table'
    },
    height: {
      type: [Number, String],
      required: false,
      default: 360
    },
    width: {
      type: [Number, String],
      required: false,
      default: 'auto'
    }
  },
  data () {
    return {
      Value: '',
      Url: '',
      upLoadBaseURL: 'process.env.VUE_APP_BASE_API',
      hasChange: false,
      hasInit: false,
      tinymceId: this.id,
      fullscreen: false,
      languageTypeList: {
        'zh': 'zh_CN',
        'en': 'en',
        'es': 'es_MX',
        'ja': 'ja'
      },
      api: {
        uploadImage: "/api/imageUpload"
      },
    }
  },
  computed: {
    containerWidth () {
      const width = this.width
      if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
        return `${width}px`
      }
      return width
    }
  },
  watch: {
    value (val) {
      if (!this.hasChange && this.hasInit) {
        this.$nextTick(() =>
          window.tinymce.get(this.tinymceId).setContent(val || ''))
      }
    }
  },
  mounted () {
    this.init()
  },
  activated () {
    if (window.tinymce) {
      this.initTinymce()
    }
  },
  deactivated () {
    this.destroyTinymce()
  },
  destroyed () {
    this.destroyTinymce()
  },
  methods: {
    init () {
      // dynamic load tinymce from cdn
      load(tinymceCDN, (err) => {
        if (err) {
          this.$message.error(err.message)
          return
        }
        this.initTinymce()
      })
    },
    initTinymce () {
      //  const _this = this
      const _this = this
      window.tinymce.init({
        selector: `#${this.tinymceId}`,
        language: this.languageTypeList['zh'],
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: plugins,
        end_container_on_empty_block: true,
        powerpaste_word_import: 'clean',
        code_dialog_height: 450,
        code_dialog_width: 1000,
        advlist_bullet_styles: 'square',
        advlist_number_styles: 'default',
        imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
        default_link_target: '_blank',
        link_title: false,
        // CONFIG: Paste  粘貼
        paste_retain_style_properties: 'all',
        paste_word_valid_elements: '*[*]',        // word須要它
        paste_data_images: true,                  // 粘貼的同時能把內容裏的圖片自動上傳,很是強力的功能
        paste_convert_word_fake_lists: false,     // 插入word文檔須要該屬性
        paste_webkit_styles: 'all',
        paste_merge_formats: true,
        nonbreaking_force_tab: false,
        paste_auto_cleanup_on_paste: false,

        // CONFIG: ContentStyle 這塊很重要, 在最後呈現的頁面也要寫入這個基本樣式保證先後一致, `table`和`img`的問題基本就靠這個來填坑了
        content_style: `
            *                         { padding:0; margin:0; }
            html, body                { height:100%; }
            img                       { max-width:100%; display:block;height:auto; }
            a                         { text-decoration: none; }
            iframe                    { width: 100%; }
            p                         { line-height:1.6; margin: 0px; }
            table                     { word-wrap:break-word; word-break:break-all; max-width:100%; border:none; border-color:#999; }
            .mce-object-iframe        { width:100%; box-sizing:border-box; margin:0; padding:0; }
            ul,ol                     { list-style-position:inside; }
          `,

        insert_button_items: 'image link | inserttable',

        // CONFIG: StyleSelect
        style_formats: [
          {
            title: '首行縮進',
            block: 'p',
            styles: { 'text-indent': '2em' }
          },
          {
            title: '行高',
            items: [
              { title: '1', styles: { 'line-height': '1' }, inline: 'span' },
              { title: '1.5', styles: { 'line-height': '1.5' }, inline: 'span' },
              { title: '2', styles: { 'line-height': '2' }, inline: 'span' },
              { title: '2.5', styles: { 'line-height': '2.5' }, inline: 'span' },
              { title: '3', styles: { 'line-height': '3' }, inline: 'span' }
            ]
          }
        ],
        // FontSelect
        font_formats: `
            微軟雅黑=微軟雅黑;
            宋體=宋體;
            黑體=黑體;
            仿宋=仿宋;
            楷體=楷體;
            隸書=隸書;
            幼圓=幼圓;
            Andale Mono=andale mono,times;
            Arial=arial, helvetica,
            sans-serif;
            Arial Black=arial black, avant garde;
            Book Antiqua=book antiqua,palatino;
            Comic Sans MS=comic sans ms,sans-serif;
            Courier New=courier new,courier;
            Georgia=georgia,palatino;
            Helvetica=helvetica;
            Impact=impact,chicago;
            Symbol=symbol;
            Tahoma=tahoma,arial,helvetica,sans-serif;
            Terminal=terminal,monaco;
            Times New Roman=times new roman,times;
            Trebuchet MS=trebuchet ms,geneva;
            Verdana=verdana,geneva;
            Webdings=webdings;
            Wingdings=wingdings,zapf dingbats`,

        // Tab
        tabfocus_elements: ':prev,:next',
        object_resizing: true,
        // Image
        imagetools_toolbar: 'rotateleft rotateright | flipv fliph | editimage imageoptions',

        nonbreaking_force_tab: true, // inserting nonbreaking space   need Nonbreaking Space Plugin
        init_instance_callback: editor => {
          if (_this.value) {
            editor.setContent(_this.value)
          }
          _this.hasInit = true
          editor.on('NodeChange Change KeyUp SetContent', () => {
            this.hasChange = true
            this.$emit('input', editor.getContent())
          })
        },
        setup (editor) {  //自定義功能
          editor.on('FullscreenStateChanged', (e) => {
            _this.fullscreen = e.state
          })
        },

        // ....上傳圖片配置代碼
        images_upload_handler: (blobInfo, success, failure) => {
          var reader = new FileReader();
          reader.readAsDataURL(blobInfo.blob());
          reader.onload = function () {
            raceApi.postImgUrl({ image: this.result }).then(res => {  //這裏就是要上傳base64  格式的圖片的請求了 
              if (res.code == 200) {
                let url = res.data.domain + res.data.path
                success(url)
                console.log(url);
              }
            })
          }
        },

        // prop內傳入的的config
        ...this.config,
        content_style: 'img {max-width:100% !important }', // 初始化賦值  這個主要是防止圖片拉昇變形的 (上傳的圖片再app顯示會變形要加上這個)

        setup: (editor) => {
          // 拋出 'on-ready' 事件鉤子
          editor.on(
            'init', () => {
              _this.loading = false
              _this.$emit('on-ready')
              editor.setContent(_this.value)
            }
          )
          // 拋出 'input' 事件鉤子,同步value數據
          editor.on(
            'input change undo redo', () => {
              _this.$emit('input', editor.getContent())
            }
          )
        }

      })
    },
    destroyTinymce () {
      const tinymce = window.tinymce.get(this.tinymceId)
      if (this.fullscreen) {
        tinymce.execCommand('mceFullScreen')
      }

      if (tinymce) {
        tinymce.destroy()
      }
    },
    setContent (value) {
      window.tinymce.get(this.tinymceId).setContent(value)
    },
    getContent () {
      window.tinymce.get(this.tinymceId).getContent()
    },
    imageSuccessCBK (arr) {
      const _this = this
      arr.forEach(v => {
        window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
      })
    }
  }
}
`
相關文章
相關標籤/搜索