最近用vue+element-ui开发一套后台管理系统,其中项目中需要用到富文本编辑器,这里总结下开发过程中遇到的坑和使用方法。

 刚开始用的是vue-quill-editor结合element-ui上传图片到服务器,name问题来了 按照官方文档上面的方式。下面是我的代码

<template>
<div>
    <!-- 图片上传组件辅助-->
    <el-upload
            class="avatar-uploader"
            :action="serverUrl"
            name="img"
            :headers="header"
            :show-file-list="false"
            :on-success="uploadSuccess"
            :on-error="uploadError"
            :before-upload="beforeUpload">
    </el-upload>
    <!--富文本编辑器组件-->
   <el-row v-loading="uillUpdateImg">
    <quill-editor
            v-model="detailContent"
            ref="myQuillEditor"
            :options="editorOption"
            @change="onEditorChange($event)"
            @ready="onEditorReady($event)"
    >
    </quill-editor>
   </el-row>
</div>
</template>
<script>

export default {
    data() {
        return {
            quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
            serverUrl: '',  // 这里写你要上传的图片服务器地址
            header: {token: sessionStorage.token},  // 有的图片服务器要求请求头需要有token之类的参数,写在这里
            detailContent: '', // 富文本内容
            editorOption: {}  // 富文本编辑器配置
        }
    },
    methods: {
        // 上传图片前
        beforeUpload(res, file) {},
        // 上传图片成功
        uploadSuccess(res, file) {},
        // 上传图片失败
        uploadError(res, file) {}
    }
}
</script>

 

那么我们需要怎样将富文本图片上传这个按钮跟自定义的文件上传做绑定呢。

clipboard.png

 

很简单,我们需要在editorOption配置中这么写
export default {
data() {

        return {
        quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
            serverUrl: '',  // 这里写你要上传的图片服务器地址
            header: {token: sessionStorage.token},  // 有的图片服务器要求请求头需要有token之类的参数,写在这里
            detailContent: '', // 富文本内容
            editorOption: {
                placeholder: '',
                theme: 'snow',  // or 'bubble'
                modules: {
                    toolbar: {
                        container: toolbarOptions,  // 工具栏
                        handlers: {
                            'image': function (value) {
                                if (value) {
                                    document.querySelector('#quill-upload input').click()
                                } else {
                                    this.quill.format('image', false);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

 但是这里问题就出现了,当你用element-ui upload方法上传时你会发现上传不成功,emmmm~你会发现上传时Request Method 方式为OPTIONS,这跟平时的提交方式不一样,Status Code等于204,,去网上又查阅了下,发现这种请求方式,但是最终还是没有解决掉,好像是需要后端也要相应的改下东西

clipboard.png

 所以走到这里只能用另外一种方式去实现相同的功能了————Ueditor

第一步:先按照官方的提示 去官网下载相应的代码,我这里后端语言是PHP所以我下的是PHP的版本,根据需求去下载
 

 clipboard.png

 clipboard.png

第二步:ueditor里除了php文件都放到static文件,这是我的目录结构

 clipboard.png

 

第三步:将PHP文件放到后端去,我这边项目是我直接放到ftp上面去的,结构如下

 clipboard.png

 

第四步:我这边封装成了一个公共组件,因为有很多页面需要用到

 

<template>
<div>

<script id="editor" type="text/plain"></script>
</div>
</template>

<script>
//import AppConfig from '@/config'
import '../../../static/ueditor/ueditor.config.js'
import '../../../static/ueditor/ueditor.all.js'
import '../../../static/ueditor/lang/zh-cn/zh-cn.js'

export default {

name: "UEditor",
props: {
    id: {
        type: String
    },
    config: {
        type: Object
    },
    defaultMsg: {
        type: String
    },
},
created() {
    //this.$emit('defaultMsgVlaue', this.names)
},
data() {
    return {
        editor: null,
        names: ''
    }
},
mounted() {
    //初始化UE
    const _this = this;
      this.initEditor()
    //this.editor = UE.getEditor(this.id, this.config);
    // this.editor.addListener('ready', () => {
    //     this.editor.setContent(_this.defaultMsg);
    // });
},
destoryed() {
    this.editor.destory();
},
methods: {
    getUEContent: function() {
        return this.editor.getContent();
    },
    initEditor() {
      let _this= this;
      this.editor = UE.getEditor('editor', this.config)
      //编辑器准备就绪后会触发该事件
      this.editor.addListener('ready',()=>{
        //设置可以编辑
        this.editor.setEnabled();
          this.editor.setContent(_this.defaultMsg);
      })
      //编辑器内容修改时
      this.selectionchange()
    },
    //编辑器内容修改时
    selectionchange() {
      this.editor.addListener('selectionchange', () => {
        //this.content = this.ue.getContent()
      })
    }
},
activated() {
    //初始化编辑器
  this.initEditor()
}
}
</script>

 页面调用如下

<template>
<div id="app" class="hello">

<el-button size="primary" type="info" icon="plus" @click="openWindow">打开窗口</el-button>
<el-dialog title="新增菜单" size="small" v-model="addFormVisible" :close-on-click-modal="false">
  <div>
    <el-button size="primary" type="info" icon="plus" @click="getContent">获取内容</el-button>
    <UEditor :config=config ref="ueditor" :defaultMsg=defaultMsg></UEditor>
  </div>
</el-dialog>
</div>
</template>

<script>
import {UEditor} from './ueditor/index.js'

export default{

  name: 'hello',
  components: {UEditor},
  data(){
    return {
      config: {
        /*//可以在此处定义工具栏的内容
        toolbars: [
          ['fullscreen', 'source','|', 'undo', 'redo','|','bold', 'italic', 'underline', 'fontborder', 'strikethrough',
            '|','superscript','subscript','|', 'forecolor', 'backcolor','|', 'removeformat','|', 'insertorderedlist', 'insertunorderedlist',
            '|','selectall', 'cleardoc','fontfamily','fontsize','justifyleft','justifyright','justifycenter','justifyjustify','|',
            'link','unlink']
        ],*/
        autoHeightEnabled: false,
        autoFloatEnabled: true,  //是否工具栏可浮动
        initialContent:'请输入内容',   //初始化编辑器的内容,也可以通过textarea/script给值,看官网例子
        autoClearinitialContent:true, //是否自动清除编辑器初始内容,注意:如果focus属性设置为true,这个也为真,那么编辑器一上来就会触发导致初始化的内容看不到了
        initialFrameWidth: null,
        initialFrameHeight: 450,
        BaseUrl: '',
        UEDITOR_HOME_URL: 'static/ueditor/'
      },
      addFormVisible: false
    }
  },
  methods: {
    openWindow: function(){
        this.addFormVisible = true;
    },
    //获取文档内容
    getContent: function(){
      let content = this.$refs.ueditor.getUEContent();
      console.log(content);
      alert(content);
    }
  }
}

</script>

 

注意:在这里封装成一个公共组件了,但是在使用的过程中会发现,在同一页面回显数据到ueditor时只会渲染一次,这可怎么办呢,
这里想到了用watch来监听,然后再将数据放到ueditor里,这里我用的参数名是defaultMsg,代码如下:
watch: {
    'defaultMsg': {
        handler(newValue, oldValue) {
            //父组件param对象改变会触发此函数
            this.editor.setContent(newValue);

        },
        deep: true
    }
}
这样的话再同一个页面回显ueditor时就会实时改变,做到这里我想着试下在其他页面是否可以,因为有多个路由页面需要用到ueditor,当我在其他页面打开ueditor时,发现ueditor加载不出来了,然后我就纳闷了,然后排查了很多问题之后,终于知道是因为每次只初始化了ueditor,但是在关闭页面时没有将其销毁,所以需要在上面封装的公共组件里去销毁下
destroyed() {
  //销毁编辑器实例,使用textarea代替
  this.editor.destroy()
  //重置编辑器,可用来做多个tab使用同一个编辑器实例
  //如果要使用同一个实例,请注释destroy()方法
  // this.ue.reset()
}
这样的话就解决了在多个路由页面的时候ueditor不现实的问题。
第五步:配置文件上传和回显,我们需要在上传图片,并且让上传的图片回显到ueditor里,首先先将文件ueditor/ueditor.config.js里的serverUrl换成自己项目的服务器路径

 clipboard.png

这里配置之后就可以直接使用了

遇到的其他问题如下:前端代码必须跟PHP文件放在同一个域名上,我之前是将两块代码分别放到不同FTP上,这样导致ueditor里文件可以上传但是提示上传失败,这样上传的图片没法回显
有些还是不清楚的,或者有其他更好实现效果的方法的伙伴可以跟我留言,欢迎共同进步
Logo

前往低代码交流专区

更多推荐