wangEditor3富文本本地上传图片视频功能,插件源码修改

近期公司用到了wangEditor作为富文本使用,但是出现了点问题,原来的wangEditor插件只支持网络图片和网络视频的插入,现在要求新增本地图片和视频的导入,于是特地去查看了手册:wangEditor3使用手册
关于图片上传,插件用起来很简单:手册是这么介绍的

上传图片tab:

<div id="div1">
    <p>欢迎使用 wangEditor 富文本编辑器</p>
</div>

<script type="text/javascript" src="/wangEditor.min.js"></script>
<script type="text/javascript">
    var E = window.wangEditor
    var editor = new E('#div1')

    // 下面两个配置,使用其中一个即可显示“上传图片”的tab。但是两者不要同时使用!!!
    // editor.customConfig.uploadImgShowBase64 = true   // 使用 base64 保存图片
    // editor.customConfig.uploadImgServer = '/upload'  // 上传图片到服务器

    editor.create()
</script>

如果图片使用base64 保存的话,直接editor.customConfig.uploadImgShowBase64 = true 放开就行;
要是上传到服务器的话,后台要进行处理,并且要返回一个图片的url。
而且要以 map形式返回,map中存放data 和errno 即url和错误类型 如下

其中/upload是上传图片的服务器端接口,接口返回的数据格式如下(实际返回数据时,不要加任何注释!!!)

{
    // errno 即错误代码,0 表示没有错误。
    //       如果有错误,errno != 0,可通过下文中的监听函数 fail 拿到该错误码进行自定义处理
    "errno": 0,

    // data 是一个数组,返回若干图片的线上地址
    "data": [
        "图片1地址",
        "图片2地址",
        "……"
    ]
}

隐藏“网络图片”tab
默认情况下,“网络图片”tab是一直存在的。如果不需要,可以参考一下示例来隐藏它。

<div id="div1">
    <p>欢迎使用 wangEditor 富文本编辑器</p>
</div>

<script type="text/javascript" src="/wangEditor.min.js"></script>
<script type="text/javascript">
    var E = window.wangEditor
    var editor = new E('#div1')

    // 隐藏“网络图片”tab
    editor.customConfig.showLinkImg = false

    editor.create()
</script>

重点来了,wangEditor3只支持网络视频的插入,并且要以 iframe 形式上传,要是上传本地视频,插件并不支持,必须修改源码实现:
重要代码如下:

// 构造函数
    function Video(editor) {
        this.editor = editor;
        this.$elem = $('<div class="w-e-menu"><i class="w-e-icon-play"></i></div>');
        this.type = 'panel';

        // 当前是否 active 状态
        this._active = false;
    }

// 原型
    Video.prototype = {

        constructor: Video,

        onClick: function onClick() {
            this._createInsertPanel();
        },

        _createInsertPanel: function _createInsertPanel() {
            var t = this;
            var editor = this.editor;
            var uploadVideo = editor.uploadVideo;
            var config = editor.config;

            // id
            var upTriggerId = getRandom('up-trigger');
            var upFileId = getRandom('up-file');
            var e = getRandom("text-val");
            var n = getRandom("btn");
            // tabs 的配置
            var tabsConfig = [{
                title: '上传本地视频',
                tpl: '<div class="w-e-up-img-container">\n                    ' +
                    '<div id="' + upTriggerId + '" class="w-e-up-btn">\n                        ' +
                    '<i class="w-e-icon-upload2"></i>\n                    </div>\n                    ' +
                    '<div style="display:none;">\n                        <input id="' + upFileId + '" type="file" multiple="multiple" accept="audio/mp4, video/mp4"/>\n                    ' +
                    '</div>\n                            </div>',
                events: [{
                    // 触发选择视频
                    selector: '#' + upTriggerId,
                    type: 'click',
                    fn: function fn() {
                        var $file = $('#' + upFileId);
                        var fileElem = $file[0];
                        if (fileElem) {
                            fileElem.click();
                        } else {
                            // 返回 true 可关闭 panel
                            return true;
                        }
                    }
                }, {
                    // 选择视频完毕
                    selector: '#' + upFileId,
                    type: 'change',
                    fn: function fn() {
                        var $file = $('#' + upFileId);
                        var fileElem = $file[0];
                        if (!fileElem) {
                            // 返回 true 可关闭 panel
                            return true;
                        }

                        // 获取选中的 file 对象列表
                        var fileList = fileElem.files;
                        if (fileList.length) {
                            uploadVideo.uploadVideo(fileList);
                        }

                        // 返回 true 可关闭 panel
                        return true;
                    }
                }]
            },
                {
                    title: "插入视频",
                    tpl: '<div>\n                        <input id="' + e + '" type="text" class="block" placeholder="格式如:<iframe src=... ></iframe>"/>\n                        <div class="w-e-button-container">\n                            <button id="' + n + '" class="right">插入</button>\n                        </div>\n                    </div>',
                    events: [{
                        selector: "#" + n,
                        type: "click",
                        fn: function() {
                            var $linkUrl = $('#' + e);
                            var url = $linkUrl.val().trim();
                            return url && t._insertss(url),
                                !0
                        }
                    }]
                }
            ]; // tabs end

            // 判断 tabs 的显示
            var tabsConfigResult = [];
            if ((config.uploadImgShowBase64 || config.uploadImgServer || config.customUploadImg) && window.FileReader) {
                // 显示“上传图片”
                tabsConfigResult.push(tabsConfig[0]);
            }
            if (config.showLinkImg) {
                // 显示“网络图片”
                tabsConfigResult.push(tabsConfig[1]);
            }


            // 创建 panel 并显示
            var panel = new Panel(this, {
                width: 300,
                tabs: tabsConfigResult
            });
            panel.show();

            // 记录属性
            this.panel = panel;
        },
        _insertss: function(t) {
            this.editor.cmd.do("insertHTML", t + "<p><br></p>")
        },

        // 试图改变 active 状态
        tryChangeActive: function tryChangeActive(e) {
            var editor = this.editor;
            var $elem = this.$elem;
            if (editor._selectedImg) {
                this._active = true;
                $elem.addClass('w-e-active');
            } else {
                this._active = false;
                $elem.removeClass('w-e-active');
            }
        }
    };
 // 上传视频
        uploadVideo: function uploadVideo(files) {
            var _this3 = this;

            if (!files || !files.length) {
                return;
            }

            // ------------------------------ 获取配置信息 ------------------------------
            var editor = this.editor;
            var config = editor.config;
            var uploadVideoServer = "/upload/videoUpload.action";//上传地址

            var maxSize = 100 * 1024 * 1024;       //100M
            var maxSizeM = maxSize / 1000 / 1000;
            var maxLength = 1;
            var uploadFileName = "file";
            var uploadVideoParams = config.uploadVideoParams || {};
            var uploadVideoHeaders = {};
            var hooks =config.uploadImgHooks || {};
            var timeout = 5 * 60 * 1000;        //5 min
            var withCredentials = config.withCredentials;
            if (withCredentials == null) {
                withCredentials = false;
            }

            // ------------------------------ 验证文件信息 ------------------------------
            var resultFiles = [];
            var errInfo = [];
            arrForEach(files, function (file) {
                var name = file.name;
                var size = file.size;

                // chrome 低版本 name === undefined
                if (!name || !size) {
                    return;
                }

                if (/\.(mp4)$/i.test(name) === false) {
                    // 后缀名不合法,不是视频
                    errInfo.push('\u3010' + name + '\u3011\u4e0d\u662f\u89c6\u9891');
                    return;
                }
                if (maxSize < size) {
                    // 上传视频过大
                    errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M');
                    return;
                }

                // 验证通过的加入结果列表
                resultFiles.push(file);
            });
            // 抛出验证信息
            if (errInfo.length) {
                this._alert('视频验证未通过: \n' + errInfo.join('\n'));
                return;
            }
            if (resultFiles.length > maxLength) {
                this._alert('一次最多上传' + maxLength + '个视频');
                return;
            }

            // ------------------------------ 自定义上传 ------------------------------
            // 添加视频数据
            var formdata = new FormData();
            arrForEach(resultFiles, function (file) {
                var name = uploadFileName || file.name;
                formdata.append(name, file);
            });

            // ------------------------------ 上传视频 ------------------------------
            if (uploadVideoServer && typeof uploadVideoServer === 'string') {
                // 添加参数
                var uploadVideoServer = uploadVideoServer.split('#');
                uploadVideoServer = uploadVideoServer[0];
                var uploadVideoServerHash = uploadVideoServer[1] || '';
                objForEach(uploadVideoParams, function (key, val) {
                    val = encodeURIComponent(val);

                    // 第一,将参数拼接到 url 中
                    if (uploadVideoParamsWithUrl) {
                        if (uploadVideoServer.indexOf('?') > 0) {
                            uploadVideoServer += '&';
                        } else {
                            uploadVideoServer += '?';
                        }
                        uploadVideoServer = uploadVideoServer + key + '=' + val;
                    }

                    // 第二,将参数添加到 formdata 中
                    formdata.append(key, val);
                });
                if (uploadVideoServerHash) {
                    uploadVideoServer += '#' + uploadVideoServerHash;
                }

                // 定义 xhr
                var xhr = new XMLHttpRequest();
                xhr.open('POST', uploadVideoServer);

                // 设置超时
                xhr.timeout = timeout;
                xhr.ontimeout = function () {
                    // hook - timeout
                    if (hooks.timeout && typeof hooks.timeout === 'function') {
                        hooks.timeout(xhr, editor);
                    }

                    _this3._alert('上传视频超时');
                };

                // 监控 progress
                if (xhr.upload) {
                    xhr.upload.onprogress = function (e) {
                        var percent = void 0;
                        // 进度条
                        var progressBar = new Progress(editor);
                        if (e.lengthComputable) {
                            percent = e.loaded / e.total;
                            progressBar.show(percent);
                        }
                    };
                }

                // 返回数据
                xhr.onreadystatechange = function () {
                    var result = void 0;
                    if (xhr.readyState === 4) {
                        if (xhr.status < 200 || xhr.status >= 300) {
                            // hook - error
                            if (hooks.error && typeof hooks.error === 'function') {
                                hooks.error(xhr, editor);
                            }

                            // xhr 返回状态错误
                            _this3._alert('上传视频发生错误', '\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status);
                            return;
                        }

                        result = xhr.responseText;
                        if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') {
                            try {
                                result = JSON.parse(result);
                            } catch (ex) {
                                // hook - fail
                                if (hooks.fail && typeof hooks.fail === 'function') {
                                    hooks.fail(xhr, editor, result);
                                }
                                _this3._alert('上传视频失败', '上传视频返回结果错误,返回结果是: ' + result);
                                return;
                            }
                        }
                        if (!hooks.customInsert && result.errno != 0) {
                            // hook - fail
                            if (hooks.fail && typeof hooks.fail === 'function') {
                                hooks.fail(xhr, editor, result);
                            }
                            // 数据错误
                            _this3._alert('上传视频失败', '上传视频返回结果错误,返回结果 errno=' + result.errno);
                        } else {
                            if (hooks.customInsert && typeof hooks.customInsert === 'function') {
                                hooks.customInsert(_this3.insertLinkVideo.bind(_this3), result, editor);
                            } else {
                                // 将视频插入编辑器
                                var data = result || [];
                                // data.forEach(function (link) {
                                //     console.log(link);
                                //
                                // });
                                _this3.insertLinkVideo(data.data);
                            }

                            // hook - success
                            if (hooks.success && typeof hooks.success === 'function') {
                                hooks.success(xhr, editor, result);
                            }
                        }
                    }
                };

                // hook - before
                if (hooks.before && typeof hooks.before === 'function') {
                    var beforeResult = hooks.before(xhr, editor, resultFiles);
                    if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') {
                        if (beforeResult.prevent) {
                            // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
                            this._alert(beforeResult.msg);
                            return;
                        }
                    }
                }

                // 自定义 headers
                objForEach(uploadVideoHeaders, function (key, val) {
                    xhr.setRequestHeader(key, val);
                });

                // 跨域传 cookie
                xhr.withCredentials = withCredentials;

                // 发送请求
                xhr.send(formdata);

                // 注意,要 return 。不去操作接下来的 base64 显示方式
                return;
            }
        }
    };

后端上传方法:

/*富文本本地视频上传*/
	@ResponseBody
	@RequestMapping("/videoUpload")
	public Map<String, Object> videoUpload(@RequestParam(value="file",required=false) MultipartFile file, HttpServletRequest request){
		Map<String, Object> map = new HashMap<>();
		File targetFile=null;
		String url="";//返回存储路径
		int code=1;
		System.out.println(file);
		String fileName=file.getOriginalFilename();//获取文件名加后缀
		if(fileName!=null&&fileName!=""){
			//文件本地存储位置  这里的urlService.MEDIA_MEDIA   是一个配置的地址 返回的就是一个上传目录
			String path = urlService.MEDIA_MEDIA+ "thumbnail/t_news/video/";   
			String fileF = fileName.substring(fileName.lastIndexOf("."), fileName.length());//文件后缀
			//根据日期生成一个新的文件名,防止文件名冲突
			String fileQ=new Date().getTime()+"_"+new Random().nextInt(1000);
			fileName=fileQ+fileF;//新的文件名

			File file1 =new File(path);
			//如果文件夹不存在则创建
			if(!file1 .exists()  && !file1.isDirectory()){
				file1 .mkdir();
			}
			//将图片存入文件夹
			targetFile = new File(file1, fileName);
			try {
				//将上传的文件写到服务器上指定的文件。
				file.transferTo(targetFile);

				//存入后获取url  这里的urlService.REST_BASE_URL  就是一个文件下载的方法地址 下载方法也是后台写的
				//这里传了一个下载类型  和文件名后缀 还有id
				url= urlService.REST_BASE_URL+"/file/file/getVideo.action?type=33,"+fileF+"&id="+fileQ;
				map.put("data",url);
				map.put("errno",0);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return map;
	}

后端下载方法:

//这个上传方法是一个公用方法,加了一个type来区分,你可以不传,我已经把其他没有用的type类型判断的方法删掉了
@RequestMapping(value="/getVideo")
 public void getVideo (@RequestParam("id")String id,@RequestParam("type")String typeAndVideoName,
                          HttpServletResponse response,HttpServletRequest request){
		byte[] data;
		try {
			File file = null;
			//截取文件后缀
			 if (type.contains("33")) {
				String str1=type.substring(0, type.indexOf(","));
				String fileZ=type.substring(str1.length()+1, type.length());
				//这里的 FILE_BASE_PATH是从配置文件中读取的  就是之前富文本上传的地址
				file = new File(FILE_BASE_PATH + "thumbnail/t_news/video/" +id+fileZ);
				data = FileUtil.readAsByteArray(file);
			}
			OutputStream outputSream = response.getOutputStream();
			InputStream in = new ByteArrayInputStream(data);
			int len = 0;
			byte[] buf = new byte[1024];
			while ((len = in.read(buf, 0, 1024)) != -1) {
				outputSream.write(buf, 0, len);
			}
			outputSream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

前端jsp页面直接加上 调用就可以:

 var E = window.wangEditor;
          var editor = new E('#editor');
          editor.customConfig.menus =[
             // 'head',  // 标题
            //  'bold',  // 粗体
              'fontSize',  // 字号
              'fontName',  // 字体
              'italic',  // 斜体
              'underline',  // 下划线
              'strikeThrough',  // 删除线
              'foreColor',  // 文字颜色
              'backColor',  // 背景颜色
              'link',  // 插入链接
              'list',  // 列表
              'justify',  // 对齐方式
              'quote',  // 引用
            //  'emoticon',  // 表情
              'image',  // 插入图片
              'table',  // 表格
              'video',  // 插入视频
             // 'code',  // 插入代码
              'undo',  // 撤销
              'redo'  // 重复
          ];
           // 本地上传图片(举例)
          editor.customConfig.uploadImgShowBase64 = true;
          // 隐藏“网络图片”tab
          //editor.customConfig.showLinkImg = false;

          editor.create();

我整理了一份完整的wangEditor.js,包括本地和网络图片,本地视频和网络视频的插入 需要的话可以下载 https://download.csdn.net/download/weixin_43832166/12109361

参考资料:https://blog.csdn.net/one_hwx/article/details/87652525

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉登的小行星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值