ionic中的在线视频播放功能

发布时间:2026/9/7 18:10:21
ionic中的在线视频播放功能 前言在ionic中处理视频播放的功能在stackoverflow, ionic-forum以及ionic的github issue中都有提及有很多相关讨论 我们只针对在线视频播放功能进行下总结之前用过videogular这款插件,但在实际播放中的效果并不是很好。在实际开发中可以使用新浪微博网页版中的视频链接做测试(备注新浪视频优化的比较好播放很流畅) 本文作为ionic中h5播放在线视频的一种思路来阐述当然还有改进的空间。效果预览必要说明其中git动画图片由于大小有限制和保持高清做了加速处理在真机上已播放的进度呈现不同颜色体验会更好。另外暂时没找到相关视频缓冲了多少的api, 所以缓冲进度没有做处理。刚刚在知乎上找到了这个Media.buffered 使用buffered.start(index)和buffered.end(index) 可以获取缓冲段, 有时间再来试下。github演示地址https://github.com/rwx-robot/ionic-samplesVideo模块中的html关键代码ion-viewcache-viewfalseclassvideong-class{cur:renderData.hideBar}ion-header-barclassbar-stablebuttonng-clickback()iclassion-arrow-left-c/iBack/buttonh1classtitlevideo预览/h1/ion-header-barion-contentscrollfalseoverflow-scrolltruedata-tap-disabletruescrollbar-yfalsehas-bouncingfalsevideo-containerx-sourcerenderData.videoSrc/video-container/ion-content/ion-view说明 其中overflow-scrolltrue与data-tap-disabletrue在视频播放中起到了关键的作用这两句话要加上其中一个。有关data-tap-disabletrue在官网上也做了一些 具体说明Video模块中的controller关键代码.controller(VideoCtrl,[$scope,$sce,appUtils,function($scope,$sce,appUtils){$scope.backappUtils.back;varrenderData$scope.renderData{};renderData.videoSrc$sce.trustAsResourceUrl(http://static.videogular.com/assets/videos/videogular.mp4);renderData.hideBarfalse;// 控制是否隐藏 bar/* 视图事件 */$scope.$on($ionicView.afterEnter,function(){// 锁定屏幕,让其全屏横屏显示if(!window.cordova){return;}window.screen.orientation.lock(landscape);});$scope.$on($ionicView.afterLeave,function(){// 还原成竖屏if(!window.cordova){return;}window.screen.orientation.lock(portrait);});// 接收广播$scope.$on(videoBarHide,function(event,data){if(!data){return;}renderData.hideBartrue;$scope.$apply();});$scope.$on(videoBarShow,function(event,data){if(!data){return;}renderData.hideBarfalse;$scope.$apply();});}]);此处有必要进行详细的说明此处的视频地址从上一个模块中挂到url上传递过来的进入视频模块中强制横屏退出视频模块时强制竖屏的一款cordova插件 cordova-plugin-screen-orientation 此插件在iOS10,11中要注意测试下, 如不工作,需要特殊处理。通过接收指令中的广播来进行动画处理header-bar 和播放控制按钮的隐藏详情请看下面的指令相关。Video模块中的指令模板关键代码divclassvideo-container!-- 视频源 --videopreloadmetadatawebkit-playsinlinewebkit-playsinlineposterimages/post-bg.gifsourceng-src{{source}}typevideo/mp4//video!-- 视频播放控制区 --divclassvideo-controll-bar clearfixng-class{cur: videoData.hide}!-- 播放,暂停 --divclassplay-btn pull-leftng-class{cur:videoData.playing}on-tapplay()spanclassplaying-btn/span/divdivclassvideo-time pull-leftspanclassnow-time{{videoData.current ? videoData.current : 00:00:00}}/span/spanclasstotal-time{{videoData.duration ? videoData.duration : 00:00:00}}/span/divdivclassvideo-progress-zone rangedivclassvideo-range-track center-center/divinputclassvideo-range-input center-centertyperangevalue0min0max{{videoData.durationOrigin}}ng-modelvideoData.currentOriginng-changeseeking()/div/div!-- 视频缓冲loading --divclassvideo-loading center-centerng-ifvideoData.isLoadingion-spinnericondots/ion-spinner/div/div说明此处不附带css样式文件的说明另在ionic中input range插件做的很好只需要改改样式就可以变成自定义的状态Video模块中的播放进度条样式和相关动画参考css 参考代码.video ion-content{margin-top:-44px;}.video .scroll{overflow:hidden;}.video-container, .video-container video{width:100%;height:100%;background:#000;}.video-controll-bar{position:fixed;bottom:0;width:100%;height:56px;line-height:56px;background-color:rgba(0,0,0,.3);transition:all .2s ease-out 0s;-webkit-transition:all .2s ease-out 0s;}.video-time{margin-left:10px;font-size:13px;color:#fff;}.play-btn{width:56px;height:56px;}.playing-btn{display:block;width:100%;height:100%;background:url(../images/play-btn.png)no-repeat center -23px;background-size:45% auto;}.play-btn.cur .playing-btn{background-position:center 18px;background-size:50% auto;}.video-progress-zone .video-range-input{width:100%;margin:0;padding:0;border:none;box-shadow:none;background:none;height:15px;}.video-progress-zone .video-range-track{width:100%;height:3px;background-color:rgba(255,255,255,.3);}.video-progress-zone{position:absolute;top:-1px;left:0;right:0;width:100%;height:0;}.video-controll-bar .video-range-input[typerange]::-webkit-slider-thumb{-webkit-appearance:none;cursor:default;top:0;height:12px;width:12px;background:#fff;border-radius:50%;box-shadow:0 0 3px #fff;overflow:visible;position:relative;}.video-controll-bar .video-range-input[typerange]::-webkit-slider-thumb:before{position:absolute;content: ;top:5px;left:-1998px;background:#fff;}.video-container .spinner{fill:#808080;}.video-container .spinner svg{width:70px;height:70px;}/* 隐藏bar的动画 */.video.cur .video-controll-bar{transform:translate3d(0,56px,0);-webkit-transform:translate3d(0,56px,0);}.video.cur ion-header-bar{transform:translate3d(0,-44px,0);-webkit-transform:translate3d(0,-44px,0);}说明样式图片需要自己来引用处理此处只作为参考Video模块中的指令逻辑关键代码.directive(videoContainer,function(appUtils){return{restrict:EA,templateUrl:components/directives/html/video.html,scope:{source:},link:function(scope,element){// 初始化数据成员// 视频默认是要点击后播放的varvideoelement.find(video)[0];// 获取视频元素varvideoFlag0;// 用于检测video播放varvideoDatascope.videoData{};videoData.playingfalse;// 控制是否播放中videoData.currentOrigin0;// 当前播放进度// 点击播放按钮或暂停功能scope.playfunction(){if(!videoData.playing){video.autoplayvideoData.playingtrue;video.play();}else{video.autoplayvideoData.playingfalse;video.pause();}};// 滑动功能实现scope.seekingfunction(){video.currentTimevideoData.currentOrigin;videoFlag0;};// 事件监听// 开始播放 , 初始化所有数据ionic.EventController.on(loadstart,function(){videoData.playingthis.autoplayfalse;// 默认是播放状态同loadingvideoData.isLoadingtrue;// 开始loadingscope.$apply();},video);// 元数据加载完成后 此时获取时长ionic.EventController.on(loadedmetadata,function(){appUtils.checkToGetMediaDuration(scope,video,videoData);videoFlag0;// 此处归零 表示视频this.autoplayvideoData.isLoadingfalse;// 为了兼容scope.$apply();},video);ionic.EventController.on(durationchange,function(){appUtils.checkToGetMediaDuration(scope,video,videoData);this.autoplaytrue;// 为了兼容scope.$apply();},video);// onprogress 正在下载中ionic.EventController.on(progress,function(){appUtils.checkToGetMediaDuration(scope,video,videoData);scope.$apply();},video);// waitingionic.EventController.on(waiting,function(){videoData.isLoadingthis.autoplaytrue;// 为了兼容 true; // 无法继续播放时loadingvideoData.playingtrue;// 同样保持播放状态scope.$apply();},video);// seekingionic.EventController.on(seeking,function(){videoData.isLoadingvideoData.playingthis.autoplaytrue;// 为了兼容 true ; seeking 保持播放状态this.play();// 强制播放scope.$apply();},video);// 在可播放时 只会触发一次 , 播放按钮状态 : 可播放ionic.EventController.on(playing,function(){appUtils.checkToGetMediaDuration(scope,video,videoData);this.autoplayvideoData.isLoadingtrue;// 为了兼容 此处 loading 应为 false ,但安卓低端机器存在问题scope.$apply();},video);// 监听暂停事件ionic.EventController.on(pause,function(){videoData.playingvideoData.isLoadingfalse;scope.$apply();},video);// 音频播放位置发生改变时触发/* 设置为自动隐藏 */ionic.EventController.on(timeupdate,function(){appUtils.checkToGetMediaDuration(scope,video,videoData);videoData.currentOriginvideo.currentTime;// 获取视频当前时间videoData.currentappUtils.handlePlayingTime(video.currentTime);// 获取格式转换之后的视频当前时间if(videoFlag1){// timeupdate 时,开始播放 兼容问题videoData.isLoadingfalse;videoData.playingtrue;// 播放按钮呈现}if(videoFlag10){videoData.hidetrue;scope.$emit(videoBarHide,1);// 发送广播, 隐藏bar}videoFlag;scope.$apply();},video);// 触摸取消隐藏ionic.EventController.on(touchstart,function(){videoFlag0;scope.$emit(videoBarShow,1);// 发送广播, 显示bar},video);// 视频可以流畅播放到结束ionic.EventController.on(canplaythrough,function(){},video);// 视频可以流畅播放ionic.EventController.on(canplay,function(){},video);// 播放完成ionic.EventController.on(ended,function(){this.pause();scope.hidefalse;// 显示scope.$apply();},video);}};});说明 关于appUtils中的方法请看前面的 博文关于兼容性目前在一些安卓系统版本中对loadstart等一系列事件支持的不太好, 但iOS和高版本的安卓系统支持的很好此种方案是一种h5视频播放的解决方案作为开发人员的一项参考。