效果图
前言
据我了解,这是一款基于bootstrap的富文本编辑器,比较喜欢的它的样式风格和图片上传的功能。
问题1:
它默认的图片上传,是把图片转成base64编码并提交给后端。这显然不是我们想要的,我们希望图片以文件形式提交给后端保存,后端返回其保存的路径。
问题2:
图片异步上传时,没有进度显示。如果上传动态图等较大的图片,用户体验不是很好。为此,我使用一款基于bootstrap的模态框插件 BootBox.js (https://www.bootboxjs.cn/)来显示上传进度条。
踩坑
1、bootstrap,bootbox, summernote相关依赖引入,略...
2、summernote的API可能不同版本之间有差异,这里只提供重写图片上传和显示上传进度条的思路,summernote具体API参照官网文档
3、在服务器部署环境下测试:
(1)有时候发现图片插入位置错误,并没有成功插入到编辑框中,但在本地测试没发现。原因未知。
(2)为什么进度条满了之后,要等一会进度条对话框才消失?
上传进度,是指前端已经发送出去的字节数,后端完全接收之后。会把临时文件移动到指定目录,并往数据库中插入数据。业务层面的操作需要耗时。所以,进度条满了,代表前端已经把所有字节发送出去。从完全发送完毕到得到响应的中间有一段时间差。当得到响应后,进度条对话框才隐藏。
(3)为什么进度条对话框隐藏之后,要等一会图片才插入到编辑框中?
summernote中插入图片的操作是异步的。所以没有等到插入图片完成,进度条对话框就被关闭了。图片被插入到编辑框后,要根据网络URL来加载图片,测试发现是完全加载图片后才插入到编辑框中显示出来。如果服务器带宽小(我用的学生服务器),较大的图片加载会比较慢。
代码
<script>
$(function() {
var $summernote = $('#summernote').summernote({
height: 420,
focus: true,
toolbar: [
['style', ['style']],
['font', ['bold', 'italic', 'underline', 'clear']],
['fontname', ['fontname']],
['fontsize', ['fontsize']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['table', ['table']],
['insert', ['link', 'picture', 'video']],
['view', ['fullscreen', 'codeview']],
['help', ['help']]
],
// 复写图片上传方法
onImageUpload: function (files, editor, $editable) {
sendFile(files[0], editor, $editable);
}
});
//ajax上传图片
function sendFile(file, editor, $editable) {
if (file == null) {
// 取消或关闭了文件选择对话框
return;
}
console.log(editor);
console.log($editable);
var val = 0; // 进度。百分比
var totalBytes = file.size; // 文件的总字节数
console.log(totalBytes);
var formData = new FormData();
formData.append("file", file);
// 显示进度对话框
showProgressDialog();
var uploadAjax = $.ajax({
url: "图片上传的接口路径",
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
xhr: function() {
//获取原生的xhr对象
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
//添加 progress 事件监听
//console.log(xhr.upload);
xhr.upload.onprogress = function(e) {
// e.loaded 已经加载的字节数
val = (int) (e.loaded / totalBytes * 100);
if (val > 100) {
val = 100;
}
// 更新进度条的进度
$('#progressBar').css({
width: val.toFixed(2) + '%'
});
$('#progressBar').html(val.toFixed(2) + '%');
};
xhr.upload.onabort = function() {
// 取消上传的回调
};
}
return xhr;
},
// ajax请求成功的回调
success: function (data) {
console.log(data);
if (data['result'] === true) {
//console.log($editable);
// 异步将图片插入到编辑框中
editor.insertImage($editable, "__public__/" + data['save_path']);
//$summernote.summernote('insertImage', data['save_path']);
} else {
alert(data['error']);
}
// 关闭对话框
bootbox.hideAll();
}
});
function showProgressDialog() {
var html =
"<div class='progress'><div id='progressBar' class='progress-bar' role='progressbar' style='min-width: 2em;'>" + (val + '%') + "</div></div>";
bootbox.dialog({
title: '正在上传...',
message: html,
size: 'large',
onEscape: false,
backdrop: false,
buttons: {
cancel: {
label: '取消',
className: 'btn btn-outline-danger',
callback: function(){
// 中断ajax请求
if (uploadAjax != null) {
//console.log(uploadAjax);
uploadAjax.abort();
}
// 关闭对话框
bootbox.hideAll();
}
}
}
});
}
}
});
</script>