百度UEditor编辑器视频相关bug汇总和稳定解决方案

百度UEditor编辑器的视频是个很头疼的问题,从昨晚到今天折腾了一天,也看了不少帖子,很多都是只治标不治本,而且有很多改法也是忽略本质,不过受大神启发,自己还是琢磨出来了。

百度UEditor编辑器的视频主要容易出现几个问题:

1、添加视频之后,点击查看html源码,结果丢失src后面的链接;

2、视屏编辑器预览BUG;

3、添加视屏后百度编辑器预览BUG;

这三个问题,本文将分别讲解:

一、丢失src后面的链接问题


这个问题其实网上有很多大神已经找到关键点了:白名单!没错,就是这个!

这个问题可以参考这个两个帖子:

http://blog.csdn.net/eunyeon/article/details/52964152

扫描二维码关注公众号,回复: 225113 查看本文章

https://github.com/fex-team/ueditor/pull/2957/commits/d4b875ce165b3225929496c2d85848afbff0deeb?diff=split

其实就是在ueditor.config.js的白名单whitList:里面加上src字段,这样就不会被过滤了。

 

[html]   view plain  copy
  1. <span style="font-size:18px;">img:    ['src', 'alt', 'title', 'width', 'height', 'id', '_src', '_url', 'loadingclass', 'class', 'data-latex'], </span>  
[html]   view plain  copy
  1. <span style="font-size:18px;">//视频部分白名单********  
  2. video:  ['autoplay', 'controls', 'loop', 'preload', 'src', 'height', 'width', 'class', 'style'],    
  3. source: ['src', 'type'],    
  4. embed:  ['type', 'class', 'pluginspage', 'id', 'src', 'width', 'height', 'align', 'bgcolor', 'style', 'wmode', 'play',    
  5.     'loop', 'menu', 'allowscriptaccess', 'allowfullscreen'],  
  6. iframe: ['src', 'class', 'height', 'width', 'max-width', 'max-height', 'align', 'frameborder', 'allowfullscreen']  
  7. //********</span>  

img里面为什么要加上'_src'和'_url',第一篇博客里面说是因为编辑器在切换源码的过程中过滤掉img的_url属性(用来存储视频url)_src/plugins/video.js里处理的是_url,而不是_src。

 

然而,问题来了,居然没有用!!!!骂人

折腾了半天,最后发现只要把 whitList: 改成 whiteList:就好了。源码中少了一个e,一口血吐出来。想问百度UEditor的开发大神么英语六级过了么?


 

二、视屏编辑器预览BUG

关于视频编辑器的问题个人没找到有解释清楚的,折腾了半天还是自己看源码搞明白了,这里让我慢慢说。

视屏编辑器的bug在这里:


然而在确认之后,在UEditor的编译器上,把鼠标放在视频位置,弹出菜单,点击了下方的“修改”按钮


打开之后,奇迹出现了。。


晕死,怎么会这样。我找了半天,终于在视频编译器对应的video.js中找到问题了,就是这个方法:

 

[javascript]   view plain  copy
  1. /** 
  2.      * 监听url改变事件 
  3.      * @param url 
  4.      * @modify ie9以上使用oninput属性监听,onpropertychange不稳定 
  5.      */  
  6.     function addUrlChangeListener(url){  
  7.         if (browser.ie) {  
  8.             url.onpropertychange = function () {  
  9.                     createPreviewVideo( this.value );  
  10.         } else {  
  11.             url.addEventListener( "input"function () {  
  12.                 createPreviewVideo( this.value );  
  13.             }, false );  
  14.         }  
  15.     }  



 

这个方法中,url变量是视频编译器上输入“视频网址”的html Dom对象,我这里用的IE11测试的,然后onpropertychange这个方法就出现了问题。

 

这个方法的目的是监听这个html Dom对象是否发生了value变化,但是这对于ie11而言第一次打开却不起效果?!就比如说首次加载的时候就不行,首次加载的代码在这里(我只是想向大神证明我没胡说):


由于IE11已经能支持HTML5的规范了,所以可以直接用oninput方法,这里把上述函数改为:

 

[javascript]   view plain  copy
  1. /** 
  2.      * 监听url改变事件 
  3.      * @param url 
  4.      * @modify ie9以上使用oninput属性监听,onpropertychange不稳定 
  5.      */  
  6.     function addUrlChangeListener(url){  
  7.         if (browser.ie) {  
  8.             if(browser.ie11Compat==true  
  9.                     || browser.ie9Compat == true){  
  10.                 url.oninput = function () {  
  11.                     createPreviewVideo( this.value );  
  12.                 }  
  13.             }else{  
  14.                 //ie9以下  
  15.                 url.onpropertychange = function () {  
  16.                     createPreviewVideo( this.value );  
  17.                 }  
  18.             }  
  19.         } else {  
  20.             url.addEventListener( "input"function () {  
  21.                 createPreviewVideo( this.value );  
  22.             }, false );  
  23.         }  
  24.     }  

这样首次打开就也能播放视频了。


上述browser.ie11Compat==true和browser.ie9Compat == true请参照ueditor.all.js中这部分代码:

 

[javascript]   view plain  copy
  1. browser.ie11Compat = document.documentMode == 11;  
  2.         /** 
  3.          * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式 
  4.          * @warning 如果浏览器不是IE, 则该值为undefined 
  5.          * @example 
  6.          * ```javascript 
  7.          * if ( UE.browser.ie9Compat ) { 
  8.          *     console.log( '当前浏览器运行在IE9兼容模式下' ); 
  9.          * } 
  10.          * ``` 
  11.          */  
  12.         browser.ie9Compat = document.documentMode == 9;  

 

好,这样解决了一般网络视频的播放问题,但是又有个问题来了,如果连接地址不是flash格式,而是普通的mp4文件地址问么办?

修改上述函数,在flash流路径下加上

 

[javascript]   view plain  copy
  1. type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"  


这两条属性,就可以兼容路径后缀为.mp4的视频流播放了。效果如下:

 

可以看到,这是后缀为.MP4的视屏流,也可以预览播放成功了。
网上有些人直接去掉了这两条属性,我试过这样对于flash流也能播放成功,但是很不稳定,电脑都死机过几回。。腾讯给的分享链接地址里面也是有这两条属性的,所以我建议对于flash流最好还是也带着吧。
三、添加视屏后百度编辑器预览BUG
百度编辑器预览BUG主要是因为在编译器中显示成了一张图片而不是视频。

关于这个我参考了一位作者的做法:

http://blog.csdn.net/belen_xue/article/details/73252802
个人认为其做法有点粗暴,甚至可能导致一部分问题,具体我慢慢细说。
首先,在引入js包的时候,请不要使用ueditor.all.min.js,因为这是压缩过的js,源码为ueditor.all.js,可修改。



那么接下来就要对ueditor.all.js进行操刀了!
先找到这个函数me.commands["insertvideo"] ,作者的做法直接将参数“image”改为了“embed”,认为这是视频就应该这样改:


 

改完之后,确实能确保编译器中能看到视频了,而不是图片了,但是窗口却不能关闭了,然后作者就又把上面那个for循环删了,原因是因为改完后找不到 id 这个属性了;

接下来在creatInsertStr方法中,switch的case 'embed': 分支中,str去掉了这两个属性:

 

[javascript]   view plain  copy
  1. type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"  


这样确实能保证绝大多数视频都能正常显示了,但是还是同video.js中的问题一样,稳定性不好,另外还有个非常大的问题,如果点击查看源码(那个html按钮),再返回,又会变成图片!
怎么办?

我在creatInsertStr方法下方直接发现了一个方法:

 

发现这个方法其实是在做图片和视频的切换。如果切换到查看html,或者调用获取编译器内容的getContent()方法时,会切回成embed标签,也就是嵌入视频标签,切换回预览页面时,又会切换回图片显示。也就是说,按照那位作者的做法,这个方法内容也必须注释掉,且两个IF都要注释。

 

[javascript]   view plain  copy
  1. function switchImgAndVideo(root,img2video){  
  2.         utils.each(root.getNodesByTagName(img2video ? 'img' : 'embed video'),function(node){  
  3.             //去掉转换  
  4.             var className = node.getAttr('class');  
  5. //            if(className && className.indexOf('edui-faked-video') != -1){  
  6. //                var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'embed':'image');  
  7. //                node.parentNode.replaceChild(UE.uNode.createElement(html),node);  
  8. //            }  
  9. //            if(className && className.indexOf('edui-upload-video') != -1){  
  10. //                var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'video':'image');  
  11. //                node.parentNode.replaceChild(UE.uNode.createElement(html),node);  
  12. //            }  
  13.         });  
  14.     }  

 

这样实践后,确实不会再出现切回图片的问题了,但是我在想,为何百度UEditor的开发人员非要把视频转为图片显示呢?

 

看到这个了吗,如果按照作者的做法换成视频的话,这个功能菜单自然就没有了。
另外按照作者的做法,如果这里是视频流的话,在编译器预览页面上删除视频,而视频如果正在播放,有些播放器可能会这样:


 

视频是被删了,可他附在页面上还在播放呢!

接下来我说下个人的做法:
me.commands["insertvideo"]方法,将上传和嵌入分开处理,for循环不需要删除,因为下面有办法解决(不就是少个id吗?我加上不就完了?)。

 

[javascript]   view plain  copy
  1. me.commands["insertvideo"] = {  
  2.         execCommand: function (cmd, videoObjs, type){  
  3.             videoObjs = utils.isArray(videoObjs)?videoObjs:[videoObjs];  
  4.             var html = [],id = 'tmpVedio', cl;  
  5.             for(var i=0,vi,len = videoObjs.length;i<len;i++){  
  6.                 vi = videoObjs[i];  
  7. //                cl = (type == 'upload' ? 'edui-upload-video video-js vjs-default-skin':'edui-faked-video');  
  8. //                html.push(creatInsertStr( vi.url, vi.width || 420,  vi.height || 280, id + i, null, cl, 'image'));  
  9.                 if(type == 'upload'){  
  10.                     cl = 'edui-upload-video video-js vjs-default-skin';  
  11.                     html.push(creatInsertStr( vi.url, vi.width || 420,  vi.height || 280, id + i, null, cl, 'video'));    
  12.                 }else{  
  13.                     cl = 'edui-faked-video';  
  14.                     html.push(creatInsertStr( vi.url, vi.width || 420,  vi.height || 280, id + i, null, cl, 'embed'));  
  15.                 }  
  16.             }  
  17.             me.execCommand("inserthtml",html.join(""),true);  
  18.             var rng = this.selection.getRange();  
  19.             for(var i= 0,len=videoObjs.length;i<len;i++){  
  20.                 var img = this.document.getElementById('tmpVedio'+i);  
  21.                 domUtils.removeAttributes(img,'id');  
  22.                 rng.selectNode(img).select();  
  23.                 me.execCommand('imagefloat',videoObjs[i].align);  
  24.             }  
  25.         },  

然后在creatInsertStr方法中,修改embed的处理方式:

 

 

[javascript]   view plain  copy
  1. case 'embed':  
  2.     if(utils.html(url) && utils.html(url).indexOf('.swf') != -1){  
  3.             str = '<embed type="application/x-shockwave-flash" class="' + classname + '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +  
  4.                 (id ? 'id="' + id+'"' : '') +' src="' +  utils.html(url) + '" width="' + width  + '" height="' + height  + '"'  + (align ? ' style="float:' + align + '"''') +  
  5.                 ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';  
  6.         }else{  
  7.             //非flash流采用流播放模式,同上传视频一样  
  8.             var ext = url.substr(url.lastIndexOf('.') + 1);  
  9.             if(ext == 'ogv') ext = 'ogg';  
  10.             str = '<video' + (id ? ' id="' + id + '"' : '') + ' class="' + classname + ' video-js" ' + (align ? ' style="float:' + align + '"''') +  
  11.                 ' controls autoplay="autoplay" width="' + width + '" height="' + height + '" src="' + url + '" data-setup="{}">' +  
  12.                 '<source src="' + url + '" type="video/' + ext + '" /></video>';  
  13.         }  
  14.     break;  



 

这里判断一下,如果不是flash流的话就采用上传文件的方式去显示内容,也就是用video标签这种方式,这样就不用会出现删除视频后还附在页面上播放的情况(之前那种是和播放器有关系);

 

另外,如果是flash流的话,也就是embed标签,我这里将id属性添加上了,然后再embed标签的白名单里面配置上id属性就行了这样就不需要删除前面那个函数的for循环了。如果你是按我上面的那个白名单配置的话,就已经配好咯大笑

最后就是注释掉转换函数的内容:

 

[javascript]   view plain  copy
  1. function switchImgAndVideo(root,img2video){  
  2.         utils.each(root.getNodesByTagName(img2video ? 'img' : 'embed video'),function(node){  
  3.             //去掉转换  
  4.             var className = node.getAttr('class');  
  5. //            if(className && className.indexOf('edui-faked-video') != -1){  
  6. //                var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'embed':'image');  
  7. //                node.parentNode.replaceChild(UE.uNode.createElement(html),node);  
  8. //            }  
  9. //            if(className && className.indexOf('edui-upload-video') != -1){  
  10. //                var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'video':'image');  
  11. //                node.parentNode.replaceChild(UE.uNode.createElement(html),node);  
  12. //            }  
  13.         });  
  14.     }  

 

这种做法虽然失去了那些小菜单的功能,但是测试之后,整体也是非常稳定的。


这样删除视频后不会出现附在上面继续播放的问题。

 

PS:很多属性,比如:edui-faked-video、edui-upload-video这些,其实都是开发者早就设置好为了实现某些功能的,所以随意的更改他们肯定会意味着不稳定或者功能确实等各式各样的问题。我今天研究了一天,发现其实这两个属性的目的就是为了做图片和视频转换,然后在预览界面,图片的话就可以使用那些菜单功能。所以看,其实这些问题,百度UEditor的开发者们早就想到了,而我们非要画蛇添足的去改,是不是有些“舍本逐末”的味道呢?

以前做项目遇到这种情况往往也总是不择手段,能解决问题就好,可现在却越来越重视程序的鲁棒性。其实很多开源的工具,别人能放出来给大家用,自然是稳定的,若是需求不满足,我们要改也不能改得太暴力,若不符合开发者的初衷,自然改出来的功能也容易出问题。

今天一晚上加班写的文档,可能难免有些写的不正确或者理解不到位的地方,也忘各位大神指正!

原文:http://blog.csdn.net/yingjia11/article/details/78472261

猜你喜欢

转载自937387458.iteye.com/blog/2405280
今日推荐