基于百度编辑器Ueditor的二次开发


在业务开发的时候,曾经使用过wangEditor、Quill、CKEditor,但是后面提出的新需求(需要可以复制微信公众号文章的样式,可以从excel中复制表格),之前使用的编辑器都不能满足,发现Ueditor都满足这个需求,所以把Ueditor研究了一遍,并进行二次开发,在此记录一下。

官网下载

下载地址:https://ueditor.baidu.com/website/download.html
官方文档地址:http://fex.baidu.com/ueditor/
在这里插入图片描述
我下载的是1.4.3.3 Jsp版本utf-8,其他版本的编辑器部分应该是一致的,只是后台对接的部分不同。

基本配置

在这里插入图片描述上面这一部分地址的设置是设置服务器的统一接口路径
但其实我是没有用到的,因为我对图片上传的地址做了额外的设置:

var myUEditor = UE.getEditor('ueditor-container');
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
// 对上传图片的地址做特殊设置
UE.Editor.prototype.getActionUrl = function(action) {
    if (action == 'uploadimage' || action == 'uploadscrawl') {
        return 'http://img.XXXXXXX.com/imgserver/front/uploadImagesByUEditor'; //在这里返回我们实际的上传图片地址
    } else {
        return this._bkGetActionUrl.call(this, action);
    }
}

简化后端配置,不请求后端配置项

解压官网下载的压缩包,直接打开index.html,点开关于上传的按钮(图片上传、附件上传)都会报错:
“请求后台配置项http错误,上传功能将不能正常使用!”
如下图所示:
在这里插入图片描述在这里插入图片描述
查看了下源码,大致原理就是:
如果需要使用上传功能的话,就需要让后端新写一个接口返回一个json(这个json数据就是在jsp文件夹下的config.json),编辑器要获取到这个json才算是请求后台配置项成功,才可以正常使用上传功能。
查看了一下这个config.json文件,发现是关于一些文件大小的限制,上传字段名,完全静态,所以其实这部分直接写在前端,无需从后台请求也是可以的,而且这样也不用麻烦后台小哥哥(但不知道是否有安全问题,可能我的理解比较浅显)。

以下是修改步骤(修改一小部分源代码):
打开ueditor.all.js文件,大概是8082行:

    setTimeout(function(){
       	// 修改这个setTimeout里面的内容       	
       	try{
           	me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2'));
              var configUrl = me.getActionUrl('config'),
              isJsonp = utils.isCrossDomainUrl(configUrl);
   
              /* 发出ajax请求 */
              me._serverConfigLoaded = false;
   
              configUrl && UE.ajax.request(configUrl,{
                  'method': 'GET',
                  'dataType': isJsonp ? 'jsonp':'',
                  'onsuccess':function(r){
                      try {
                      		//这部分是请求数据成功后执行的逻辑,咱们直接给config赋值,然后直接执行这部分逻辑即可。
                          var config = isJsonp ? r:eval("("+r.responseText+")");
                          utils.extend(me.options, config);
                          me.fireEvent('serverConfigLoaded');
                          me._serverConfigLoaded = true;
                      } catch (e) {
                          showErrorMsg(me.getLang('loadconfigFormatError'));
                      }
                  },
                  'onerror':function(){
                      showErrorMsg(me.getLang('loadconfigHttpError'));
                  }
              });
           } catch(e){
               showErrorMsg(me.getLang('loadconfigError'));
           }
       });

修改后:

setTimeout(function(){
    try{
        me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2'));
       // 这里的config就是JSP文件夹下的config.json数据 这里根据需求做了删减,你们可以去那个文件重新粘贴。
        var config = {
            // "basePath":"",
            "imageActionName": "uploadimage", 
            "imageFieldName": "upfile", 
            // 图片上传大小的限制:10M
            "imageMaxSize": 10*1024*1024, 
            "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], 
            "imageCompressEnable": true, 
            "imageCompressBorder": 1600, 
            "imageInsertAlign": "none", 
            "imageUrlPrefix": "http://img.xueersipeiyou.com:8093/files", 
            "imagePathFormat": "/image/{yyyy}{mm}{dd}/{time}{rand:6}", 
                                        
            "fileActionName": "uploadfile", 
            "fileFieldName": "upfile", 
            "filePathFormat": "/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}", 
            "fileUrlPrefix": "", 
            "fileMaxSize": 51200000, 
            "fileAllowFiles": [
                ".png", ".jpg", ".jpeg", ".gif", ".bmp",
                ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
                ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
                ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
                ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
            ], 

            "imageManagerActionName": "listimage", 
            "imageManagerListPath": "/ueditor/jsp/upload/image/", 
            "imageManagerListSize": 10, 
            "imageManagerUrlPrefix": "", 
            "imageManagerInsertAlign": "none", 
            "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], 

            "fileManagerActionName": "listfile", 
            "fileManagerListPath": "/ueditor/jsp/upload/file/", 
            "fileManagerUrlPrefix": "", 
            "fileManagerListSize": 10, 
            "fileManagerAllowFiles": [
                ".png", ".jpg", ".jpeg", ".gif", ".bmp",
                ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
                ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
                ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
                ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
            ] 
        };

        utils.extend(me.options, config);
        me.fireEvent('serverConfigLoaded');
        me._serverConfigLoaded = true;

    } catch(e){
        showErrorMsg(me.getLang('loadconfigError'));
    }
});

修改后,重新打开index.html,
会发现后台配置项已经配置成功,报错已经消失啦:
在这里插入图片描述
ps:如果觉得直接把配置写在源码里不好,可以把这个config抽离出来,放在ueditor.config.js定义,然后再在源码里引用。

虽然后台配置项已经配置成功了,不报错了,但是现在的上传功能还是不能使用的,因为后端还需要写图片/文件上传接口,这个还是不能省略的哈,所以还得往下看:

后端接口规范

官网后端接口规范说明:http://fex.baidu.com/ueditor/#dev-request_specification
简单归纳就是上传图片/文件接口返回的格式为:

/* 要包含4个字段: 
	state: 请求状态,若成功则返回SUCCESS 失败则返回ERROR(只要不是SUCCESS即可) 
	url: 上传文件的访问路径
	title: 上传后的文件名称
 	original: 上传前的源文件名称
*/
{
    "state": "SUCCESS",
    "url": "upload/demo.zip",
    "title": "demo.zip",
    "original": "demo.zip"
}

修改图片上传

这部分主要说明:修改图片上传面板+修改配置(增加自定义formdata字段数据)
把多图上传改为图片上传
接下来我们要去修改images对话框(多图上传)里面的内容:
在这里插入图片描述
image.html
这里把不想要的面板可以去掉(我去掉了[在线管理]、[图片搜索])

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>ueditor图片对话框</title>
    <script type="text/javascript" src="../internal.js"></script>

    <!-- jquery -->
    <script type="text/javascript" src="../../third-party/jquery-1.10.2.min.js"></script>

    <!-- webuploader -->
    <script src="../../third-party/webuploader/webuploader.min.js"></script>
    <link rel="stylesheet" type="text/css" href="../../third-party/webuploader/webuploader.css">

    <!-- image dialog -->
    <link rel="stylesheet" href="image.css" type="text/css" />
</head>
<body>

    <div class="wrapper">
        <div id="tabhead" class="tabhead">
            <span class="tab" data-content-id="remote"><var id="lang_tab_remote"></var></span>
            <span class="tab focus" data-content-id="upload"><var id="lang_tab_upload"></var></span>
            <span class="tab" data-content-id="online"><var id="lang_tab_online"></var></span>
            <span class="tab" data-content-id="search"><var id="lang_tab_search"></var></span>
        </div>
        <div class="alignBar">
            <label class="algnLabel"><var id="lang_input_align"></var></label>
                    <span id="alignIcon">
                        <span id="noneAlign" class="none-align focus" data-align="none"></span>
                        <span id="leftAlign" class="left-align" data-align="left"></span>
                        <span id="rightAlign" class="right-align" data-align="right"></span>
                        <span id="centerAlign" class="center-align" data-align="center"></span>
                    </span>
            <input id="align" name="align" type="hidden" value="none"/>
        </div>
        <div id="tabbody" class="tabbody">

            <!-- 远程图片 -->
            <div id="remote" class="panel">
                <div class="top">
                    <div class="row">
                        <label for="url"><var id="lang_input_url"></var></label>
                        <span><input class="text" id="url" type="text"/></span>
                    </div>
                </div>
                <div class="left">
                    <div class="row">
                        <label><var id="lang_input_size"></var></label>
                        <span><var id="lang_input_width">&nbsp;&nbsp;</var><input class="text" type="text" id="width"/>px </span>
                        <span><var id="lang_input_height">&nbsp;&nbsp;</var><input class="text" type="text" id="height"/>px </span>
                        <span><input id="lock" type="checkbox" disabled="disabled"><span id="lockicon"></span></span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_border"></var></label>
                        <span><input class="text" type="text" id="border"/>px </span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_vhspace"></var></label>
                        <span><input class="text" type="text" id="vhSpace"/>px </span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_title"></var></label>
                        <span><input class="text" type="text" id="title"/></span>
                    </div>
                </div>
                <div class="right"><div id="preview"></div></div>
            </div>

            <!-- 上传图片 -->
            <div id="upload" class="panel focus">
                <div id="queueList" class="queueList">
                    <div class="statusBar element-invisible">
                        <div class="progress">
                            <span class="text">0%</span>
                            <span class="percentage"></span>
                        </div><div class="info"></div>
                        <div class="btns">
                            <div id="filePickerBtn"></div>
                            <div class="uploadBtn"><var id="lang_start_upload"></var></div>
                        </div>
                    </div>
                    <div id="dndArea" class="placeholder">
                        <div class="filePickerContainer">
                            <div id="filePickerReady"></div>
                        </div>
                    </div>
                    <ul class="filelist element-invisible">
                        <li id="filePickerBlock" class="filePickerBlock"></li>
                    </ul>
                </div>
            </div>

            <!-- 在线图片 -->
            <div id="online" class="panel">
                <div id="imageList"><var id="lang_imgLoading"></var></div>
            </div>

            <!-- 搜索图片 -->
            <div id="search" class="panel">
                <div class="searchBar">
                    <input id="searchTxt" class="searchTxt text" type="text" />
                    <select id="searchType" class="searchType">
                        <option value="&s=4&z=0"></option>
                        <option value="&s=1&z=19"></option>
                        <option value="&s=2&z=0"></option>
                        <option value="&s=3&z=0"></option>
                    </select>
                    <input id="searchReset" type="button"  />
                    <input id="searchBtn" type="button"  />
                </div>
                <div id="searchList" class="searchList"><ul id="searchListUl"></ul></div>
            </div>

        </div>
    </div>
    <script type="text/javascript" src="image.js"></script>

</body>
</html>

image.js
大约在第365行,这部分是使用了FEX百度前端团队开发的一个文件上传组件webUploader,以下是我们需要研究及修改的部分:

uploader = _this.uploader = WebUploader.create({
    pick: {
        id: '#filePickerReady',
        label: lang.uploadSelectFile
    },
    accept: {
        title: 'Images',
        extensions: acceptExtensions,
        mimeTypes: 'image/*'
    },
    swf: '../../third-party/webuploader/Uploader.swf',
    server: actionUrl,
    resize: true,
    // 此属性是你提交的图片的name属性值,相当于<input type="file" name="imgFile">
    fileVal: editor.getOpt('imageFieldName'),
    duplicate: true,
    fileSingleSizeLimit: imageMaxSize,    // 默认 2 M
    compress: editor.getOpt('imageCompressEnable') ? {
        width: imageCompressBorder,
        height: imageCompressBorder,
        // 图片质量,只有type为`image/jpeg`的时候才有效。
        quality: 90,
        // 是否允许放大,如果想要生成小图的时候不失真,此选项应该设置为false.
        allowMagnify: false,
        // 是否允许裁剪。
        crop: false,
        // 是否保留头部meta信息。
        preserveHeaders: true
    }:false,
    formData: {
        'dirName':'pip' 
    }
});

说明及修改

1、配置里的 fileVal 属性是提交的图片的name属性值,

fileVal:XXX 

相当于

<input type="file" name="XXX">

这个属性也是后端接口在接收这个文件时的字段名

fileVal: editor.getOpt('imageFieldName'),

这里取的是ueditor.config.js中的配置,如果需要修改可以去ueditor.config.js中修改。

2、除了传输文件,如果还想传一些其他的数据,那就需要再配置formData这个选项:

formData: {
    'dirName':'pip' 
}

新增按钮及弹窗(自定义附件上传)

二次开发(添加自定义按钮)-相关文档-:http://fex.baidu.com/ueditor/#dev-developer
因为我这边产品的需求是需要将上传的附件与文章分开的,而ueditor自带的附件上传功能是将附件嵌入在文章里面,所以附件上传这个功能需要重新做:
在这里插入图片描述
第1步,创建一个自定义的对话框:
在这里插入图片描述

attachment_user.html

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>ueditor附件对话框</title>
    <!-- 引入pip配置文件 -->
    <!-- jquery -->
    <script type="text/javascript" src="../../../../pip_static/js/config/config.js"></script>
    <script type="text/javascript" src="../../third-party/jquery-1.10.2.min.js"></script>
    <!-- attachment dialog -->
    <link rel="stylesheet" href="attachment_user.css" type="text/css" />
    <style>
        .upload-btn{
            opacity: 0;
            width: 100%;
            height: 100%;
            display: block;
            cursor: pointer;
            background: rgb(255, 255, 255);
        }
        .upload-btn:hover{
            background: rgba(0,162,212);   
        }

    </style>
</head>
<body>

    <div class="wrapper">
        <div id="tabbody" class="tabbody">
            <!-- 上传附件 -->
            <div id="upload" class="panel focus">
                <div class="placeholder">
                    <label class="webuploader-pick" for="file">点击选择文件</label>
                    <input type="file" id="file" name="file" style="opacity: 0;width: 0px;height: 0px; visibility: hidden;">
                    <div class="tips">附件大小不可超过200M</div>
                </div>
            </div>
        </div>
    </div>
    <script type="text/javascript" src="attachment_user.js"></script>

</body>
</html>

attachment.js

(function () {
    function uploadFileListener(){
        var fileInput = $('#file')[0];
        fileInput.addEventListener('change', function () {
            console.log('上传附件');
            if (fileInput.files != null && fileInput.files[0] != null) {
                var file = fileInput.files[0];
                if (Math.ceil(file.size / 1024 / 1024) > 200) {
                    window.parent.layer.msg('附件大小不能超过'+ 200 +'MB',{time: 1200});
                    return;
                }
                var fileObj = fileInput.files[0];
                var fd = new FormData();
                fd.append('imgFile', fileObj);
                fd.append("dirName", 'pip');
                $.ajax({
                    url: '上传接口地址',
                    data: fd,
                    type: "POST",
                    dataType: "json",
                    cache: false,
                    processData: false,
                    contentType: false,
                    beforeSend: function(){
                        // $('#upload-loading').show();
                    },
                    success: function (result) {
                        console.log(result);
                        if(result.code==0){
                            fileInput.value = '';
                            window.parent.vm.files.push({
                                name: fileObj.name,
                                idName : result.data.split('/pip/')[1] 
                            });
                            window.parent.layer.msg("附件上传成功", {time:1500});
                            window.parent.ueAttachmentDialog.close(false);
                        }else{
                            window.parent.layer.msg( result.message ||'附件上传失败,请联系管理员');
                        }
                    },
                    error: function(error){
                        alert(JSON.stringify(error));
                    },
                    complete: function(){}
                });
            }
        });
    }
    uploadFileListener();
})();

第2步,注册UI组件(对话框及按钮):

UE.registerUI('dialog', function(editor, uiName){
    //创建dialog
    var dialog = new UE.ui.Dialog({
    iframeUrl:'../../lib/ueditor/dialogs/attachment_user/attachment_user.html',
    //需要指定当前的编辑器实例
    editor:editor,
    //指定dialog的名字
    name:uiName,
    //dialog的标题
    title:"附件",
    //指定dialog的外围样式
    cssRules:"width:660px; height:420px;",
    //如果给出了buttons就代表dialog有确定和取消
    buttons:[
        {
            className:'edui-cancelbutton',
            label:'关闭',
            onclick:function () {
                dialog.close(false);
            }
        }
    ]});
    // 定义一个全局变量ueAttachmentDialog来存放dialog,
    // 为了在iframe的操作中可以通过:window.parent.ueAttachmentDialog.close(false)来操作和访问父窗口的方法和变量。
    window.ueAttachmentDialog = dialog;
    var btn = new UE.ui.Button({
        name:'add-user-attachment',
        title:'添加附件',
        //需要添加的额外样式,指定icon图标,这里默认使用一个重复的icon
        cssRules :'background-position: -622px -40px;',
        onclick:function () {
            //渲染dialog
            dialog.render();
            dialog.open();
        }
    });
    return btn;
}, 54); // 这个54是指自定义按钮的排在默认按钮中的index

特别说明:
定义一个全局变量window.ueAttachmentDialog来存放dialog,
这是为了在iframe的操作中可以通过:window.parent.ueAttachmentDialog.close(false)来操作和访问父窗口的方法和变量。

按钮文案修改

工具栏的按钮文字在文件夹lang/zh-cn/zh-cn.js下修改:
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值