最近有使用到百度的UEditor富文本编辑器,简单记录一下。
1)下载
我下载的1.4.3.3的php版本,再次说明一下,下载哪个版本没有影响,原因有二:①使用的后端是python,②使用的是前端js获取后端签名直传oss。所以不需要自带的后端服务器。
下载地址:UEditor官方下载
2)初次运行,查找图片无法上传原因
前后端能保证正常运行,映射到的前端页面为以下代码
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>ueditor demo</title>
</head>
<body>
<!-- 加载编辑器的容器 -->
<script id="container" name="content" type="text/plain">
这里写你的初始化内容
</script>
<button class="" onclick="on_click()">点击获取富文本内容
</button>
<!-- 配置文件 -->
<script type="text/javascript" src="/static/more/UE/ueditor.config.js"></script>
<!-- 编辑器源码文件 -->
<script type="text/javascript" src="/static/more/UE/ueditor.all.js"></script>
<!-- 实例化编辑器 -->
<script type="text/javascript">
var ue = UE.getEditor('container', {
initialFrameHeight: 400,
scaleEnabled:true
});
function on_click() {
alert(ue.getContent())
}
</script>
</body>
</html>
运行服务器,输入url,查看输入富文本框,发现文字都可以输入,但是无法使用图片视频等上传功能,
3)配置文件
1. 定位到ueditor.all.js文件的大概8030行,采用的是JS获取签名,不需要此处,将此处注释
2. 删除出php服务器文件,将以下图片中红色框中的php文件夹删除
3. 复制上传的js插件替换之前的php服务器文件,如图,
百度云链接:https://pan.baidu.com/s/1RrQL8ApjA_GRt309MNw7XQ , 密码:4voc, 拿走不谢
4. 配置图片js获取签名
①打开上图中的image.html,复制以下代码(我封装好的图片上传界面加js获取oss签名),
<!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" />
<script src="../../plupload/plupload.full.min.js"></script>
</head>
<body>
<div class="wrapper">
<div id="tabhead" class="panel tabhead focus">
<span class="tab focus" 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 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"> </var><input class="text" type="text" id="width"/>px </span>
<span><var id="lang_input_height"> </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>
<!--start-->
<div class="container">
<form class="form-horizontal" id="form1">
<div class="form-group" id="upload1">
<!--<div class="col-xs-9" style="display: none">-->
<!--<span>-->
<!--图片地址-->
<!--</span>-->
<!--<input type="text" class="form-control" id="photo" name="photo" readonly style="background-color: white">-->
<!--</div>-->
<div class="col-xs-9 col-xs-offset-3">
<span class="label label-default ">图片文件</span> <span id="file-text">未选择</span><br>
<button class="btn btn-primary btn-sm" id="select-btn" type="button">添加图片</button>
<!--<button class="btn btn-default btn-sm" id="upload-btn" type="button">上传图片</button>-->
</div>
<div class="col-xs-9 col-xs-offset-3 area" style="margin-top: 10px;display: none">
<div class="progress">
<div id="upload-progress" class="progress-bar" role="progressbar" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;">
0%
</div>
</div>
</div>
<div class="col-xs-9 col-xs-offset-3 area" style="margin-top: 10px;display: none">
<span class="label label-danger ">提示</span> <span id="error-text">请先选择文件</span>
</div>
</div>
</form>
</div>
<!--end-->
<div class="right"><div id="preview"></div></div>
</div>
<!-- 上传图片 -->
<div id="upload" class="panel">
<div id="queueList" class="queueList" style="display: none">
<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>
</div>
<script type="text/javascript" src="image.js"></script>
</body>
</html>
<script>
function get_oss_sign(dir) {
/*
* 获取阿里云oss直传签名给window.oss_sign
* oss_sign.make_random_filename(filename)可获取一个随机文件名
* oss_sign.oss_cdn为文件cdn的url域名
* */
if(!window.oss_sign){
window.oss_sign = null;
}
dir = dir ? dir : 'default';
var oss_sign_server = '/oss_sign/?dir=' + dir; // 获取后端签名ajax的url
function get_signature() {
//可以判断当前expire是否超过了当前时间,如果超过了当前时间,就重新取一下.3s 做为缓冲
var now = Date.parse(new Date()) / 1000;
var expire = oss_sign ? oss_sign.expire : 0;
if (expire < now + 3) {
$.ajax({
url: oss_sign_server,
method: 'GET',
data: {return_style: 'json'},
async: false,
complete: function (req, status) {
if (status == 'success') {
oss_sign = JSON.parse(req.responseText);
oss_sign.make_random_filename = make_filename;
return true;
}
}
});
}
return false;
};
function random_string(len) {
len = len || 32;
var chars = 'abcdefhijkmnprstwxyz';
var maxPos = chars.length;
var pwd = '';
for (var i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
function get_suffix(filename) {
var pos = filename.lastIndexOf('.')
var suffix = ''
if (pos != -1) {
suffix = filename.substring(pos)
}
return suffix;
}
function make_filename(filename) {
var suffix = get_suffix(filename);
return oss_sign.dir + oss_sign.time_string + random_string(4) + suffix
}
get_signature()
}
// 实例化上传文件
var uploader1 = new plupload.Uploader({
runtimes: 'html5,flash,silverlight,html4',
browse_button: $("#upload1 #select-btn")[0],
flash_swf_url: '../../plupload/Moxie.swf',
silverlight_xap_url: '../../plupload/js/Moxie.xap',
url: 'http://oss.aliyuncs.com',
multi_selection: false,
filters: {
mime_types: [
{title: "Image/jpeg", extensions: "jpg"},
{title: "Image/png", extensions: "png"},
// {title: "Video/mp4", extensions: "mp4"} // 视频文件
],
max_file_size: '5mb'
},
resize: {
quality: 30
},
init: {
PostInit: function (up) {
// $("#upload1 #upload-btn").click(function () {
// up.start()
// });
},
FilesAdded: function (up, files) {
// 只保留最后一个文件
var file_num = up.files.length;
if(file_num > 1){
up.splice(0, file_num - 1) // 移除文件
}
$("#upload1 #file-text").text(files[0].name + ' (' + plupload.formatSize(files[0].size) + ')');
$("#upload1 #upload-progress").parents(".area").hide();
$("#upload1 #error-text").parents(".area").hide()
up.start() //直接上传
},
BeforeUpload: function (up, file) {
$("#upload1 #upload-progress").text('0%');
$("#upload1 #upload-progress").css('width', '0%');
$("#upload1 #upload-progress").parents(".area").show();
// 封装请求
get_oss_sign('test/'); // 如果上传成功,会在阿里云oss客户端创建一个test文件夹,文件在其内部
file.remote_filename = oss_sign.make_random_filename(file.name); // 记录上传后文件名
var new_multipart_params = {
'key': file.remote_filename,
'policy': oss_sign.policy,
'OSSAccessKeyId': oss_sign.accessid,
'success_action_status': '200', //让服务端返回200,不然,默认会返回204
'signature': oss_sign.signature
};
up.setOption({
'url': oss_sign.host,
'multipart_params': new_multipart_params
});
},
UploadProgress: function (up, file) {
var percent = file.percent + '%';
$("#upload1 #upload-progress").text(percent);
$("#upload1 #upload-progress").css("width", percent);
},
FileUploaded: function (up, file, info) {
$("#upload1 #error-text").parents(".area").show();
if (info.status == 200) {
$("#upload1 #error-text").text("上传完成");
// $("#upload1 #photo").val(oss_sign.oss_cdn + file.remote_filename)
// $('#url').val(oss_sign.oss_cdn + file.remote_filename); // 如果有cnd
$('#url').val(oss_sign.host + '/' + file.remote_filename); // 如果没cnd
}
else {
$("#upload1 #error-text").text("上传出现未知错误,请联系管理员");
}
},
Error: function (up, err) {
$("#upload1 #error-text").parents(".area").show();
if (err.code == -600) {
$("#upload1 #error-text").text("选择的文件太大了");
}
else if (err.code == -601) {
$("#upload1 #error-text").text("传文件类型不正确");
}
else if (err.code == -602) {
$("#upload1 #error-text").text("这个文件已经上传过一遍了");
}
else {
$("#upload1 #error-text").text("未知错误,请联系管理员");
}
}
}
});
uploader1.init();
</script>
上面代码中需要注意的是 get_signature()函数,函数中的ajax请求是获取后端签名的,url要确保正确,可以自己设置,这里我的后端签名python服务器,当然可以根据自己需求改成java,php等,只要能获取到阿里云oss签名并ajax返回就行。
② 修改相对于的样式,打开image.css 文件
定位到108行,将float: left 注释,如图,
然后在尾部添加以下代码:
.container{
margin: 150px 0 0 25px;
float: left;
}
.btn-primary{
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
-webkit-appearance: none;
text-align: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
outline: 0;
margin: 0;
-webkit-transition: .1s;
transition: .1s;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
color: #fff;
background-color: #409EFF;
border-color: #409EFF;
}
5) 获取后端阿里云OSS签名(Python)
① 获取签名之前,要确保自己有阿里云账号并已开通OSS服务,可参考我的另一篇文章,Python使用阿里云对象存储OSS,可以只看登陆阿里云和购买阿里云服务、开通权限部分。
② 复制以下代码,将accesskeyid, 和accesskeyscret和host写入,
def oss_sign(request):
dir = request.GET.get("dir").strip("/")
dir = dir + '/' if dir else ''
accessKeyId = "your AccesskeyID"
accessKeySecret = "your AccesskeyScaret"
host = "your host"
expire_time = 30
upload_dir = dir
now = int(time.time())
expire_syncpoint = now + expire_time
expire = get_iso_8601(expire_syncpoint)
policy_dict = {}
policy_dict['expiration'] = expire
condition_array = []
array_item = []
array_item.append('starts-with')
array_item.append('$key')
array_item.append(upload_dir)
condition_array.append(array_item)
policy_dict['conditions'] = condition_array
policy = json.dumps(policy_dict).strip()
# policy_encode = base64.encodestring(policy)
policy_encode = base64.b64encode(policy.encode())
h = hmac.new(accessKeySecret.encode(), policy_encode, sha)
sign_result = base64.encodebytes(h.digest()).strip()
token_dict = {}
token_dict['accessid'] = accessKeyId
token_dict['host'] = host
token_dict['policy'] = str(policy_encode, 'utf-8')
token_dict['signature'] = str(sign_result, 'utf-8')
token_dict['expire'] = expire_syncpoint
token_dict['dir'] = upload_dir
token_dict['time_string'] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
# token_dict['oss_cdn'] = settings.OSS_CDN
result = json.dumps(token_dict)
response = HttpResponse(result)
response["Access-Control-Allow-Methods"] = "POST"
response["Access-Control-Allow-Origin"] = "*"
return response
def get_iso_8601(expire):
gmt = datetime.datetime.fromtimestamp(expire).isoformat()
gmt += 'Z'
return gmt
6)使用截图
1)打开富文本输入框,进去开发者模式,发现也并没有报错,
2)打开图片上传,发现自己定义的页面格式也已经生效
3)点击添加图片,选择本地图片,
如上图,会有提示上传完成,对应的地址也会写入图片地址,点击确定
如上图,上传的图片会回显到富文本界面,这时已经完成了富文本图片上传功能。
4)点击下方--点击获取富文本内容按钮
为了方便理解,我是以弹窗的形式展现出富文本内容的,如下图,图片是以一个Url来展现出来的,这个url地址是阿里云存储的地址,如果将此地址复制粘贴到浏览器中,就会显示刚才我们上传的图片
5)我们再来看一下阿里云控制中心界面的文件管理
如上图,控制台多了一个test的文件夹,这个文件夹的名称是我们在js里面设置的,
进入文件夹,如下图,就是刚才我们上传的文件,
点击最右边的设置,会展示图片详细内容,包括预览图,图片url
到此,富文本图片上传问题已经解决了,视频,文件上传跟图片上传类似,只需要改一些参数即可,图片上传的js中有说明。
阿里云oss前端获取签名直传在很多地方都可以使用,包括包括图片,视频,文件等等,方便快捷,还能提升速度,有什么不太明白的可以多交流....