Toast UI Editor 自定义图片上传

桑鸿志
2023-12-01

原先项目使用quill富文本编辑器但是对于文章的样式展现不够好,所以转而使用Toast UI ,Toast UI相对于quill而言多了markdown编辑模式,样式展示丰富了很多,但是缺点就是相关Toast UI的中文文档实在太少,网上基本没有如何自定义Toast UI的按钮功能的中文教程,所以记录此次的爬坑。

首先先把所有功能代码进行展示

<template>
  <div>
    <editor @input="onContentChange"
            ref="tuiEditor"
            :value="value"
            :mode="mode"
            :options="option"
            :height="height"
            :previewStyle="previewStyle"
            @change="onEditorChange" ></editor>
    <input class="hidden"
           ref="files"
           @change="uploadFile"
           type="file"
           accept="image/*">
    <span class="warnTip mt2 block">
      提示:超链接请输入完整格式(例如https://xxx.xxx.xxx或者http://xxx.xxx.xxx)
    </span>
  </div>

</template>

<script lang="ts">
  import {Vue, Component, Prop} from 'vue-property-decorator';
  import 'tui-editor/dist/tui-editor.css'
  import 'tui-editor/dist/tui-editor-contents.css'
  import 'codemirror/lib/codemirror.css'
  import 'highlight.js/styles/github.css'
  import {Editor} from '@toast-ui/vue-editor'
  import {option} from '@/components/service-flow/uploadImgByMd'

  // interface Uplaod{
  //   uploadFn:
  // }

  const defaultOptions = {
    minHeight: '200px',
    language: 'en_US',
    useCommandShortcut: true,
    useDefaultHTMLSanitizer: true,
    usageStatistics: true,
    hideModeSwitch: false,
    toolbarItems: [
      'heading',
      'bold',
      'italic',
      'strike',
      'divider',
      'hr',
      'quote',
      'divider',
      'ul',
      'ol',
      'task',
      'indent',
      'outdent',
      'divider',
      'table',
      // 'image',
      'link',
      'divider',
      'code',
      'codeblock'
    ]
  };

  @Component({
    components: {
      Editor
    },
  })
  export default class ToastEditor extends Vue {
    //name



    //prop
    @Prop()
    value!:any;
    @Prop({
      default:"markdown"
    })
    mode!:any;
    @Prop(
      {
        default:"vertical"
      }
    )
    previewStyle!:string;
    @Prop(
      {
        default:"450px"
      }
    )
    height!:string;
    @Prop({
      default(){
        return{
          uploadFn:option.uploadFn,
          successDataTransform:option.successDataTransform,
          fail:"",
        }
      }
    })
    upload!:any;
    @Prop({
      default(){
        return {

        }
      }
    })
    uploadField!:any;
    //data
    option = defaultOptions;


    //computed


    //watch


    //life cycle
    mounted(){
      this.setButtonOfImg();
    }


    //methods
    uploadFile(e){

      let target = e.target;
      let file = target.files[0];
      //文件验证
      if(!this.fileValid(file)){
        target.value="";
        return
      };

      if(typeof this.upload.uploadFn == "function"){

        this.uploadField.file = file;
        this.upload.uploadFn(this.uploadField).then(res=>{
          this.upload.successDataTransform&&this.upload.successDataTransform(res,this.addImgToMd)
        })
      }
      console.log("file",file);
      //重置input file值
      target.value="";

    }
    setButtonOfImg(){
      let editor = (<any>this.$refs.tuiEditor).invoke('getCurrentModeEditor');
      let editorUI = (<any>this.$refs.tuiEditor).invoke('getUI');
      let toolbar = editorUI.getToolbar();
      let fileDom = this.$refs.files;
      editor.eventManager.addEventType('insertImg');
      editor.eventManager.listen('insertImg', function() {
        (<any>fileDom).click();
      });
      toolbar.addButton({
        name: 'customize',
        className: 'toast toast-img-icon',
        event: 'insertImg',
        tooltip: 'Insert img',
      }, 13);
    }

    //文件验证
    fileValid(file){
      // console.log("file_valid",file);

      if(file.size/1024>this.$bigDateConfig.IMG_SIZE_LIMIT){
        this.$message.error(`编辑图片超过${this.$bigDateConfig.IMG_SIZE_LIMIT}kb限制`);
        return false;
      }

      return true;
    }

    //添加图片到markdown
    addImgToMd(data){
      let editor = (<any>this.$refs.tuiEditor).invoke("getCodeMirror");
      let editorHtml = (<any>this.$refs.tuiEditor).invoke("getCurrentModeEditor");
      let isMarkdownMode = (<any>this.$refs.tuiEditor).invoke('isMarkdownMode');

      if(isMarkdownMode){
        editor.replaceSelection(`![img](${data})`);
      }else {
        let range = editorHtml.getRange();
        let img = document.createElement('img');
        img.src=`${data}`;
        img.alt="img";
        range.insertNode(img);
      }

    }

    onEditorChange(){

    }
    onContentChange(data){
      this.$emit("input",data);
    }
  }
</script>

<style>
  .toast.toast-img-icon{
    background-position: -130px -4px;
  }

</style>

自定义Toast UI功能主要要解决三个问题

1.如何添加自定义图标到功能栏?

2.如何为添加的自定义图标添加功能?

3.如何将后台传送的图片链接地址插入到编辑器中?

先来解决第一与第二个问题

  const defaultOptions = {
    minHeight: '200px',
    language: 'en_US',
    useCommandShortcut: true,
    useDefaultHTMLSanitizer: true,
    usageStatistics: true,
    hideModeSwitch: false,
    toolbarItems: [
      'heading',
      'bold',
      'italic',
      'strike',
      'divider',
      'hr',
      'quote',
      'divider',
      'ul',
      'ol',
      'task',
      'indent',
      'outdent',
      'divider',
      'table',
      // 'image', //注释掉编辑器自带的上传图片功能
      'link',
      'divider',
      'code',
      'codeblock'
    ]
  };
setButtonOfImg(){
      //获取编辑器
      let editor = (<any>this.$refs.tuiEditor).invoke('getCurrentModeEditor');
      let editorUI = (<any>this.$refs.tuiEditor).invoke('getUI');
      //获取编辑器上的功能条 
      let toolbar = editorUI.getToolbar();
      let fileDom = this.$refs.files;
      editor.eventManager.addEventType('insertImg');
      //这个事件监听就是添加自定义功能的地方
      editor.eventManager.listen('insertImg', function() {
        (<any>fileDom).click();
      });
      //为功能条添加自定义按钮     
      toolbar.addButton({
        name: 'customize',
        className: 'toast toast-img-icon',//自定义按钮的类名
        event: 'insertImg',//对应上文的eventManager添加的监听事件类型,通过点击触发
        tooltip: 'Insert img',//鼠标hover自定义按钮的提示信息
      }, 13);
    }

还有一个样式 

由于Toast UI自带的功能条的图标是雪碧图,所以我们可以通过background-position使用编辑器自带的插入图片的图标

<style>
  .toast.toast-img-icon{
    background-position: -130px -4px;
  }

</style>

基本上通过上述代码就可以解决问题已与问题二

现在来解决如何将后台传送的图片链接地址插入到编辑器中

//添加图片到markdown
    addImgToMd(data){
      let editor = (<any>this.$refs.tuiEditor).invoke("getCodeMirror");
      let editorHtml = (<any>this.$refs.tuiEditor).invoke("getCurrentModeEditor");
      let isMarkdownMode = (<any>this.$refs.tuiEditor).invoke('isMarkdownMode');

      //确认当前是富文本还是markdown编辑器 两种的实现方式不同  
      if(isMarkdownMode){
        //通过替换markdown内容来添加图片
        editor.replaceSelection(`![img](${data})`);
      }else {
        let range = editorHtml.getRange();
        let img = document.createElement('img');
        img.src=`${data}`;
        img.alt="img";
        //通过添加dom元素来添加图片
        range.insertNode(img);
      }

    }

全文结束

 

 

 

 

 类似资料: