前言:

之前没用过富文本编辑器,最近项目中要用到富文本编辑器,而且要能上传图片,编写表格,就只好各种查文档,百度搜,本来用的是vue-quill-editor,可惜这个编辑器不能编写表格(也可能只是我没找到编写表格的配置),之后又用了wangEditor,个人感觉这个不太好看,之后就接着搜富文本编辑器,搜到一篇文章--vue项目移植tinymce踩坑2这篇文章里关于编辑器的配置,怎么上传图片都介绍的比较详细。本文只是根据这篇文章的一点改进,方便直接复制粘贴使用大笑

一、下载所需插件

  1. 首先直接         npm install tinymce -S
  2. 下载中文语言包,附上地址下载链接
  3. 把node_modules\tinymce下的skins文件夹和中文语言包解压后的文件夹放到项目根目录下

二、创建方便引用的富文本编辑器组件

话不多说直接上代码

创建组件editor.vue

<template>
  <textarea :id='id' :value='value'></textarea>
</template>

<script>
  // Import TinyMCE
  import tinymce from 'tinymce/tinymce'
  import 'tinymce/themes/modern/theme'
  import 'tinymce/plugins/advlist' // 这几条引入是因为我的导入不了,不知道为啥
  import 'tinymce/plugins/link'
  import 'tinymce/plugins/image'
  import 'tinymce/plugins/code'
  import 'tinymce/plugins/table'
  import 'tinymce/plugins/textcolor'
  import 'tinymce/plugins/paste'
  import 'tinymce/plugins/textcolor'
  import 'tinymce/plugins/colorpicker'
  const INIT = 0
  const CHANGED = 2
  // var EDITOR = null
  export default {
    props: {
      value: {
        type: String,
        editor: null,
        required: true
      },
      setting: {},
      url: { // 接口
        default: '',
        type: String
      },
      accept: { // 文件类型
        default: 'image/jpeg, image/png',
        type: String
      },
      maxSize: { // 大小
        default: 2097152,
        type: Number
      },
      withCredentials: {
        default: false,
        type: Boolean
      }
    },
    watch: {
      value: function(val) {
        console.log('init ' + val)
        if (this.status === INIT || tinymce.activeEditor.getContent() !== val) {
          tinymce.activeEditor.setContent(val)
        }
        this.status = CHANGED
      }
    },
    data() {
      return {
        status: INIT,
        id: 'editor-' + new Date().getMilliseconds()
      }
    },
    methods: {
    },
    mounted() {
      const _this = this
      const setting =
      {
        selector: '#' + _this.id,
        upload_image_url: '/upload/cloud', // 配置的上传图片的路由
        language: 'zh_CN',
        init_instance_callback: function(editor) {
          // EDITOR = editor
          console.log('Editor: ' + editor.id + ' is now initialized.')
          editor.on('input change undo redo', () => {
            var content = editor.getContent()
            _this.$emit('show', content)
          })
        },
        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',
        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,
        'plugins': [
          'advlist link image',
          'code',
          'table textcolor paste textcolor colorpicker'
        ], // 配置
        'toolbar_items_size': 'small',
        'block_formats': 'Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;',
        'toolbar1': 'table |insertfile undo redo | formatselect | link unlink | uploadimg image media', // 工具栏1
        'toolbar2': ' fontsizeselect | forecolor backcolor | fontselect bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | outdent indent | removeformat', // 工具栏2
        // 图片上传
        images_upload_handler: function(blobInfo, success, failure) {
          // failure(blobInfo)
          // _this.$emit('on-ready', blobInfo.blob().size, blobInfo.blob())
          if (blobInfo.blob().size > _this.maxSize) {
            failure('文件体积过大')
          }
          if (_this.accept.indexOf(blobInfo.blob().type) >= 0) {
            uploadPic()
          } else {
            failure('图片格式错误')
          }
          function uploadPic() { // 发送请求
            const xhr = new XMLHttpRequest()
            const formData = new FormData()
            xhr.withCredentials = _this.withCredentials
            xhr.open('POST', _this.url)
            xhr.onload = function() {
              failure('上传---' + xhr.status)
              if (xhr.status !== 200) {
                // 抛出 'on-upload-fail' 钩子
                _this.$emit('on-upload-fail')
                failure('上传失败: ' + xhr.status)
                return
              }
              const json = JSON.parse(xhr.responseText)
              // 抛出 'on-upload-success' 钩子
              _this.$emit('on-upload-success', [
                json, success, failure
              ])
            }
            xhr.onerror = function() {
              _this.$emit('on-ready', '上传失败')
            }
            formData.append('file', blobInfo.blob())
            xhr.send(formData)
          }
        }
      }
      Object.assign(setting, _this.setting)

      tinymce.init(setting)
    },
    beforeDestroy: function() {
      tinymce.get(this.id).destroy()
    }
  }
</script>

三、其他组件引用

代码如下

<template>
  <div class="app-container calendar-list-container">
        <div style="margin:0 5%; width: 90%;">
          <editor
            class="editor"
            :value="content"
            :setting="editorSetting"
            @show="editors"
            :url              = "Url"
            :max-size         = "MaxSize"
            :accept           = "Accept"
            :with-credentials = "withCredentials"
            @on-upload-fail         = "onEditorReady"
            @on-upload-success= "onEditorUploadComplete"></editor>
        </div>
  </div>
</template>
<script type="text/ecmascript-6">
  import editor from './editor' // 根据editor.vue组件位置引入
  export default {
    data() {
      return {
        editorSetting: { // 配置富文本编辑器高
          height: 300
        },
        Url: 'http://localhost:9528/api/PublicTransaction-SYS-Web/upload/singleUpload', // 图片对应的上传地址
        MaxSize: 75765, // 文件大小
        Accept: 'image/jpeg, image/png', // 文件格式
        withCredentials: true,
        content: '' // 富文本编辑器双向绑定的内容
      }
    },
    components: { // 引入组件
      editor
    },
    methods: {
      editors(content) { // editor组件传过来的值赋给content
        console.log(content)
        this.content = content
      },
      onEditorReady(ins, ina) { // 上传失败的函数
        console.log('ins')
        console.log(ins)
        console.log(ina)
      },
      onEditorUploadComplete(json) { // 处理上传图片后返回数据,添加img标签到编辑框内
        console.log('json')
        console.log(json)
        console.log(json[0].data.filePath)
        this.content = this.content + '<img src=' + json[0].data.filePath + '>'
      }
    }
  }
</script>
<style scoped >

</style>

引入要给组件嵌套一个标签,否则右边会超出,很难看,最后附上成果图(右下角有一个像文本域一样的小三角,可以拉长显示区域),以后要用了复制粘贴就方便了大笑



Logo

前往低代码交流专区

更多推荐