在vue中使用tinymce富文本编辑器(踩坑记录)

在vue中使用tinymce富文本编辑器(踩坑记录)

  • 准备
  • 基础设置
  • 上传图片和视频
  • vue中的双向绑定
  • 图片一直显示为相对路径
  • 编辑器中输入的光标一直在前面

在开始这篇文章之前博主还用了 quill和 wangeditor,都算是比较轻量级的富文本编辑器了,不过功能也是超轻量级!而且用起来也不方便,尤其是自己在使用wangeditor时为了上传视频弄好久,最后发现尺寸也不好改!终于遇见了 tinymce 相见恨晚,tinymce算得上是所见即所得,想要什么功能就直接在配置里面加就好了,人家都写的好好的,废话不多说 直接开始操作。

准备

可以通过npm下载npm install tinymce -S
我自己用的增加了百度地图、数学符号等插件的包然后放在 public 文件夹下面
在vue中使用tinymce富文本编辑器(踩坑记录)_第1张图片

基础设置

我是在methods里面写了一个方法seteditor()进行初始化的,再在声明周期函数里在页面进行渲染完成后调用。
一定要注意:要用一个div标签将这个组件包裹住


// An highlighted block
methods:{
     
  seteditor(){
     
    tinymce.init({
     
      selector: '#tincyme',//传入id
      language:'zh_CN', //设置汉化 还要记得将汉化包放在文件里面哦
      images_upload_url:'后端给的上传图片接口'
       plugins: 'print preview searchreplace autolink directionality visualblocks' //这些都是按需导入
       toolbar: 'code undo redo restoredraft ' //想要什么就加什么就好
       height: 650, //编辑器高度
       min_height: 400,//按照自己的需求设置
       fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
       font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;',
       importcss_append: true,
    )}
  }
}

设置为中文
在vue中使用tinymce富文本编辑器(踩坑记录)_第2张图片

mounted() {
     
  this.seteditor()
},
beforeDestroy () {
     
  window.tinymce.remove('#tincyme') //一定要销毁 否则每次都需要刷新页面才能初始化
},

然后封装成一个组件 哪个界面需要调用就直接拿来用就行,在需要的界面引入
import EditorBar from '@/components/editor/index.vue'
注册

components: {
     
  EditorBar
},

使用

<!-- 富文本编辑器 -->        
 <editor-bar v-model="form.content"  />

在vue中使用tinymce富文本编辑器(踩坑记录)_第3张图片

上传图片和视频

这是上传图片的方法

images_upload_handler: (blobInfo, success, failure) => {
     
        let formData = new FormData();
        // formdata.append("imgData", blobInfo.base64());
        formData.append('file', blobInfo.blob());
        formData.append("name", blobInfo.blob().name);
        formData.append("size", blobInfo.blob().size);
        formData.append("type", blobInfo.blob().type);
        // uploadImg 这是我写的上传图片的方法 调用api里的方法就行 用request请求也能够携带着token 比自己之前在界面里一个一个写方便多了
        uploadImg(formData).then(res => {
     
          success(res.data);
        });
},

上传视频 图片也适用

//自定义文件选择器的回调内容
      file_picker_callback: function (callback, value, meta) {
     
        //文件分类
        var filetype='.pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4';
        //后端接收上传文件的地址
        var upurl='/article/upload';
        //为不同插件指定文件类型及后端地址
        switch(meta.filetype){
     
            case 'image':
                filetype='.jpg, .jpeg, .png, .gif';
                upurl='/article/upload'; //后端给的接口
                break;
            case 'media':
                filetype='.mp3, .mp4';
                upurl='/article/upload'; //后端给的接口
                break;
            case 'file':
            default:
        }
        //模拟出一个input用于添加本地文件
        var input = document.createElement('input');
        input.setAttribute('type', 'file');
        input.setAttribute('accept', filetype);
        input.onchange = function(res) {
     
            let file = res.target.files[0]; 
            let  formData;
            formData = new FormData();
            formData.append('file', file );
            formData.append('filename', file.name );
            let backurl
            uploadImg(formData).then(res => {
     
              backurl = res.data;
              callback(' '+backurl+' ', {
      title: file.name });
            });
        };
        input.click();
    },

现在视频就能够上传啦,但是要注意回显的你查看标签可能时一个img标签,没关系 可以改!

// video_template_callback: function(data) {
     
    //     return '
    //     + ' controls="controls">\n' + '
    //     + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' 
    //     + (data.source2 ? '
    //     + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') 
    //     + '';
    // },
    // media_url_resolver: (data, resolve) => {
     
    //   try {
     
    //     let videoUri = encodeURI(data.url)
    //     let embedHtml = `

// // class="mce-object mce-object-video" // data-mce-selected="1" // data-mce-object="video" // data-mce-p-width="100%" // data-mce-p-height="auto" // data-mce-p-controls="controls" // data-mce-p-controlslist="nodownload" // data-mce-p-allowfullscreen="true" // data-mce-p-src=${videoUri} > // // // //

//

`
// resolve({ html: embedHtml }) // } catch (e) { // resolve({ html: '' }) // } // },

但是最后我还是注释掉了,因为我发现这样不好修改尺寸! 而且官方也说了可以用preview插件进行预览
在vue中使用tinymce富文本编辑器(踩坑记录)_第4张图片
在vue中使用tinymce富文本编辑器(踩坑记录)_第5张图片
在我的展示界面显示也很好
在vue中使用tinymce富文本编辑器(踩坑记录)_第6张图片
至此 上传图片视频已经搞定了!是不是超级简单

vue中的双向绑定

在需要的界面上用v-model绑定值
在组件里 props接收父组件传过来的值

 model: {
     
   prop: 'value',
   // event: 'change'
   },
 props: {
     
   value: {
     
     type: String,
     default: ''
    },
  },
data() {
     
  return {
     
    editor: null,
    info_: null,
    flag: true,
    tinymceFlag: 1,//是防止组件缓存导致编辑器不能正常使用,每次切换来都更改key,使其重新渲染
    }
  },
  watch: {
     
    value(val) {
     
      if(this.flag){
     
        tinyMCE.activeEditor.setContent(val);//给编辑器设置内容
      }
      this.flag=true;
    }
    // value为编辑框输入的内容,这里我监听了一下值,当父组件调用得时候,如果给value赋值了,子组件将会显示父组件赋给的值
  },

在初始化编辑器里面加入接收父组件的方法

setup: function(editor) {
     
      editor.on('input change undo redo execCommand KeyUp', function(e) {
     
          that.flag = false //注意这里是that哦 要注意this的指向
          that.$emit('input', editor.getContent()); 
      })
    },

至此 已经完成了富文本编辑器的整个功能啦。

图片一直显示为相对路径

在配置里加上这个就ok了convert_urls: false,

编辑器中输入的光标一直在前面

这是因为我们在修改时 watch监听到了value的改变 所以又重新获取 我们就继续getcontent光标就在前面添加,还有可能出现添加错误,不能中文输入的问题。
data中添加一个flag:true标志就行 当为true时就监听 在向父组件传参的时候 先将其置为false

setup: function(editor) {
     
      editor.on('input change undo redo execCommand KeyUp', function(e) {
     
          that.flag = false //注意
          that.$emit('input', editor.getContent());
      })
    },

文章中可能还有很多的遗漏和不足,欢迎各位大佬的指教和探讨。

你可能感兴趣的:(vue)