富文本编辑器UEditor自定义工具栏(二、插入图片、音频、视频个性化功能按钮和弹层及自定义分页符)
导读:本篇将简单探讨插入图片、音频、视频的功能按钮实现方式
传送门:富文本编辑器UEditor自定义工具栏(一、基础配置与字体、背景色、行间距、超链接实现)
一、效果图
1.UEditor自定义工具栏-插入图片功能按钮效果图如下:
2.UEditor自定义工具栏-插入音频功能按钮效果图如下:
3.UEditor自定义工具栏-插入视频功能按钮效果图如下:
注:为了截图,缩小了浏览器,因此视频列表时间显示样式稍有问题,请自行忽略。
二、自定义工具栏-插入图片、音频、视频对应弹层实现方式
思路
使用Layer弹出层组件,将div等容器或节点内内容显示在弹层内,利用Ajax异步取出图片、音频、视频分组数据及对应分页数据;
1 <a href="javascript:void(0);" class="left media pic" onclick="GetMultimediaGroupData(2);GetPagedMultimediaData(2,1,pageSize);openLayer('popUpImg');" title="插入图片"><img src="@Html.SourceImageUrl("/images/personalHomepage/toolsbar-icon16.png")" width="15" height="17" /></a> 2 <a href="javascript:void(0);" class="left media voice" onclick="GetMultimediaGroupData(3);GetPagedMultimediaData(3,1,pageSize);openLayer('popUpAudio');" title="插入音频"><img src="@Html.SourceImageUrl("/images/personalHomepage/toolsbar-icon17.png")" width="15" height="17" /></a> 3 <a href="javascript:void(0);" class="left media video" onclick=" GetMultimediaGroupData(4);GetPagedMultimediaData(4,1,pageSize);openLayer('popUpVideo');" title="插入视频"><img src="@Html.SourceImageUrl("/images/personalHomepage/toolsbar-icon18.png")" width="15" height="17" /></a>
1 <div class="modal modalPic" id="popUpImg" style="display:none"> 2 <a href="javascript:void(0)" class="close" onclick="CancelInsertMultimedia(2)"></a> 3 <h1>插入图片</h1> 4 <div class="container" id="pop_multimedia_2"> 5 <div class="sideList"> 6 <ul class="dItems"></ul> 7 </div> 8 <div class="cBox"> 9 <div class="progress" id="tip_upload_progress_2" data-filename="" data-new-filename="" style="display:none"> 10 <p class="left"><span class="name" id="upload_title_2">宠物百科全书.jpg</span><span class="data">(191.8K)</span></p> 11 <div class="bar left"><span></span></div> 12 <a href="javascript:void(0)" class="left" onclick="CancelUpload(2)">取消上传</a> 13 </div> 14 <div class="oper"> 15 <input type="checkbox" class="left" id="all" onclick="ChooseAll()" /><label class="left" for="all">全选</label> 16 <div class="upload1 right" style="text-align:left;"> 17 <input type="file" name="file_upload_2" id="file_upload_2"> 18 </div> 19 </div> 20 <ul class="exhibit"></ul> 21 <div class="info"> 22 <p class="left">已选 <span>0</span> 个,可选 <i>100</i> 个</p> 23 <div class="pageY right"><a href="javascript:void(0)" class="btn1"></a><a href="javascript:void(0)" class="btn2"></a><span><i>2</i>/<i>3</i></span><a href="javascript:void(0)" class="btn3"></a><a href="javascript:void(0)" class="btn4"></a></div> 24 </div> 25 <div class="btns"> 26 <a href="javascript:void(0)" class="right cancel" onclick="CancelInsertMultimedia(2)">取 消</a> 27 <a href="javascript:void(0)" class="right sure" onclick="InsertHtmlIntoUE(2)">确 定</a> 28 </div> 29 </div> 30 </div> 31 </div>
(1)各弹层对应Html块代码分别定义一个id,如popUpImg,popUpAudio,popUpVideo,其合适子节点(用于存放分页列表数据的节点)定义后缀为多媒体类别的id,如“pop_multimedia_3“,也可以为各弹层对应Html块代码定义类似“popUp_3“含多媒体类别的popUp_3的id;
(2)GetMultimediaGroupData(2),js函数,与后台交互取出分组数据,其中括号内参数是类别,分别对应图片(2)、音频(3)、视频(4);
(3)GetPagedMultimediaData(2,1,pageSize),js函数,与后台交互取出分页的多媒体数据,第一个参数2为多媒体类别;第二个参数1为pageIndex,第1页数据;第3个参数pageSize为每页显示的数据条数,全局js变量;
(4)openLayer('popUpImg'),封装的js函数,用于打开图片弹层,参数‘popUpImg’为图片弹层对应Html块代码id;
(5)ChangePageInfo(fileType,pageIndex,totalRecord),js函数,GetMultimediaGroupData()函数里调用了此函数,用于更新分页相关信息;
1 function ChangePageInfo(fileType,pageIndex,totalRecord) { 2 var pageCount= parseInt((totalRecord + pageSize -1) / pageSize); 3 var divPage=$("#pop_multimedia_{0} .cBox .info".format(fileType)); 4 var prevPage=pageIndex<=1?1:pageIndex-1; 5 var nextPage=pageIndex+1>=pageCount?pageCount:pageIndex+1; 6 $(divPage).find(".left span").html("0");//已选 7 $(divPage).find(".left i").html(totalRecord);//可选 8 $(divPage).find(".pageY.right").find("span>i:eq(0)").html(totalRecord<=0?0:pageIndex);//当前页 9 $(divPage).find(".pageY.right").find("span>i:eq(1)").html(pageCount);//总页数 10 if (totalRecord>0) { 11 if(pageIndex<=1) $(divPage).find(".pageY.right .btn1").removeAttr("onclick").css({"cursor":"not-allowed"});//首页不可用 12 else $(divPage).find(".pageY.right .btn1").css({"cursor":""}).attr({"onclick":"GoPage({0},{1})".format(fileType,1)});//首页 13 if (pageIndex<=1) $(divPage).find(".pageY.right .btn2").removeAttr("onclick").css({"cursor":"not-allowed"});//前一页不可用 14 else $(divPage).find(".pageY.right .btn2").css({"cursor":""}).attr({"onclick":"GoPage({0},{1})".format(fileType,prevPage)});//前一页 15 if (pageIndex>=nextPage) $(divPage).find(".pageY.right .btn3").removeAttr("onclick").css({"cursor":"not-allowed"});//下一页不可用 16 else $(divPage).find(".pageY.right .btn3").css({"cursor":""}).attr({"onclick":"GoPage({0},{1})".format(fileType,nextPage)});//下一页 17 if (pageIndex>=nextPage) $(divPage).find(".pageY.right .btn4").removeAttr("onclick").css({"cursor":"not-allowed"});//尾页不可用 18 else $(divPage).find(".pageY.right .btn4").css({"cursor":""}).attr({"onclick":"GoPage({0},{1})".format(fileType,pageCount)});//尾页 19 } 20 else {//不可用 21 $(divPage).find(".pageY.right .btn1").removeAttr("onclick").css({"cursor":"not-allowed"});//首页 22 $(divPage).find(".pageY.right .btn2").removeAttr("onclick").css({"cursor":"not-allowed"});//前一页 23 $(divPage).find(".pageY.right .btn3").removeAttr("onclick").css({"cursor":"not-allowed"});//下一页 24 $(divPage).find(".pageY.right .btn4").removeAttr("onclick").css({"cursor":"not-allowed"});//尾页 25 } 26 }
ChangePageInfo函数里使用的format函数为js扩展函数,类似C#的format函数,源码如下:
1 String.prototype.format = function () { 2 var args = arguments; 3 return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) { 4 if (m == "{{") { return "{"; } 5 if (m == "}}") { return "}"; } 6 return args[n]; 7 }); 8 };
1 function GoPage(fileType,pageIndex) { 2 GetPagedMultimediaData(fileType,pageIndex,pageSize); 3 }
三、自定义工具栏-插入图片、音频、视频功能按钮-将多媒体插入编辑器
(1)封装几个js函数GetInsertHtml(fileType),InsertHtmlIntoUE(fileType) 等;
(2)GetInsertHtml(fileType)函数为取得需要插入到UEditor编辑器内的html,函数里面可以做一些处理,图片可以用img标签,音频和视频建议用audio/Video标签(只限支持H5的浏览器,IE8及其以下版本不支持H5);
(3)InsertHtmlIntoUE(fileType) 函数,调用了UEditor的插入html的命令ue.execCommand( 'inserthtml',html),其中ue为实例化出来的UEditor全局js变量,html为插入编辑器内的html源码,根据实际需求也可以在函数里做一些其他处理;
(4)插入在线音频功能,插入音频功能实现是通过输入音频的外链地址来实现,类似玩QQ空间的年代,QQ音乐外链的地址,也可以通过输入外链播放器html代码来实现,网易云音乐支持生成外链播放器;
(5)插入在线视频功能,建议使用各视频网站的视频分享的通用代码,这样也可以实现手机wap端的正常浏览(如果项目或产品有PC端也有手机wap端的话)
以爱奇艺网站为例,打开某视频的播放地址,http://www.iqiyi.com/v_19rr700mq0.html#vfrm=24-9-0-1,我们所需要的为红色箭头处的代码,根据实际需求可以更改或添加里面的属性或样式,然后执行ue.execCommand( 'inserthtml',html)命令即可插入到编辑器内;
四、自定义工具栏-自定义分页符
百度UEditor自带分页符效果如下:
自定义分页符实现思路:修改UEditor源码,添加分页符的背景图片。
按此路径“ueditor\ueditor.all.js”打开ueditor.all.js文件,在行号大约13850行修改为如下代码:
1 //分页符样式添加 2 me.ready(function(){ 3 utils.cssRule('pagebreak', '.pagebreak{display:block;clear:both !important;cursor:move !important;width: 100% !important;margin:0;background:url("' + me.options.UEDITOR_HOME_URL + '/themes/default/images/ph-jt-divide.png")' + ' no-repeat center;height:16px; border:none 0}', me.document);//自定义分隔符 4 });
百度UEditor分页符为hr标签实现:<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;" title="温馨提示:双击此分隔符可拖动。">
ue.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
注:其中“/themes/default/images/ph-jt-divide.png“为自定义分页符的背景图;
五、UEditor其他使用技巧及细节注意点
实际开发中遇到很多功能及样式研究难题,现简单梳理如下:
(1)统计多媒体数量
示例中,插入的图片、音频、视频标签,都添加了自定义属性,便于后台统计多媒体数量等,后台语言为C#,使用了C#开源Html解析组件htmlagilitypack。
(2)禁用编辑器内右键菜单
因为多媒体需要自定义属性以满足个性化需求,而且暂时没有插入表格的功能及处理远程抓取图片及复制、截图到编辑器内的功能,因此禁用了编辑器内右键菜单,除了实例化编辑器时,需要配置 enableContextMenu:false //右键菜单,还需要做如下js处理:
在UEditor的ready事件下,添加$("#ueditor_0").contents().find("body").attr({"oncontextmenu":"return false;"}),其中ueditor_0为编辑器的id,当页面只有一个编辑器时,其id即为ueditor_0。
(3)编辑器透明及无边框
在UEditor的ready事件下添加 $("#editor,#edui1,#edui1_iframeholder").css("background","transparent").css("border","0px");$("#ueditor_0").attr("allowtransparency","true");
注:如果有浏览器兼容性问题,没有实现透明,可另外为编辑器添加样式:<textarea id="editor" type="text/plain" style=" border: 0px none;"></textarea>,style="background-color: rgba(255, 255, 255, 0); border: 0px none;"。
(4)解决在线视频被浮动的工具栏遮挡的问题
添加wmoded属性
var html=$(htmlVideo).attr({"wmode":"transparent" }).prop("outerHTML");也可以根据实际需求增改其他属性。
(5)自动保存编辑内容
利用js函数setInterval,每隔一段时间(如2min)保存一次
如果标题、内容等有变动则自动保存,如果没有任何改动则不自动保存。
(6)解除提交编辑器html内容限制
Asp.Net MVC可为Action添加 [ValidateInput(false)]特性
HttpRequest 类使用输入验证标志来跟踪是否对通过 Cookies、Form 和 QueryString 属性访问的请求集合执行验证。ValidateInput 方法设置这些标志,以便在调用 Cookies、Form 或 QueryString 属性的 get 访问器时执行输入验证。验证的工作原理是,将所有输入数据与具有潜在危险的数据的硬编码列表进行对照检查。
如果页指令或配置启用了验证功能,则在页的 ProcessRequest 处理阶段调用此方法。如果未启用验证功能,则可通过代码调用 ValidateInput 方法。
(7)撤销、重做按钮样式显示
撤销、重做按钮不可操作时有edui-state-disabled样式,结合UEditor的afterSelectionChange事件监听处理即可实现
回退操作默认最多为20次(maxUndoCount:20),以重做按钮为例:
(8)默认纯文本粘贴
配置pasteplain:true //是否默认为纯文本粘贴
(9)音视频在编辑器内及预览页播放
建议使用H5标签结合H5播放器,可考虑videojs播放器
这样在编辑器内及预览页都可以进行播放,如果考虑到IE8等低版本浏览器的兼容性,音视频播放及样式问题是一系列棘手和令人比较头疼的难题;截至此文收笔时,我们采用的处理方案是编辑器内使用flash播放器,上传的视频会在服务端多次转码,利用后台处理将预览页展示的音视频换成我们自己开发的播放器;
PC端浏览效果,截的长图,自行忽略下半部分样式问题
手机wap端浏览效果
结语
本篇承接上篇,介绍了UEditor在线富文本编辑器自定义工具栏,插入图片、插入音频、插入视频、分页符等个性化功能按钮实现方式,另外简要总结了UEditor使用心得及一些细节注意事项。有很多功能及产品理念实现,没有检索到相关帖子或博客,实现的方法可能不止一种,介绍的方法是受限于产品及技术等多方面原因研究出的一种可能是首创性的实现方式,希望能抛砖引玉,给予启发性、创新性的思索和实质性的帮助,若有不足及错误之处,欢迎不吝赐教,给予斧正!