# JsDistributeVideoPlayer **Repository Path**: yuan2022/js-distribute-video-player ## Basic Information - **Project Name**: JsDistributeVideoPlayer - **Description**: 第二期挑战赛。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-10-14 - **Last Updated**: 2021-10-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## JS 分布式流转视频播放器 ## 项目介绍 * 功能:通过简单的上下左右滑动实现对视频的上下切换,评论,和视频的跨端流转。 * 实现:通过 swiper 组件实现滑动切换视频,通过 pannel 和 list 容器实现评论的展示,通过 Js 的分布式能力实现了视频的跨端流转。 * 开发版本: sdk6, DevEcoStudio 3.0 Beta1 ## 效果演示 ![](img/videoTemplate.gif) ## 实现过程分析 根据第二期挑战赛的要求,滑动切换,视频播放,分布式流转,评论。这一共是四个需求,做一个简单的分析,所有的一切显然是建立在视频播放之上的。其他功能无论是评论,还是滑动切换,又或者是分布式流转。这所有的功能都必须建立在视频播放器的基础上。 1. 因此,开始着手做这个项目的时候,第一步是制作一个视频播放器。 而视频播放器在 HarmonyOS 中有两种方式实现,一种是通过 JavaUI 一种是通过 JavaScriptUI。根据官方提示,最后选择了使用 JavascriptUI 来实现这个功能 【 [参考 JsApi 的 video 组件](https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-media-video-0000000000611764) 】 。 2. 第二步,则是在视频播放器的基础上,添加部件。滑动切换视频,评论功能,视频流转,在这三个功能中,我选择了最简单的滑动切换视频的功能。 因为在查 JsApi 的时候,意外发现了一个容器 swiper 【 [参考 JsApi 的 swiper 组件](https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-swiper-0000000000611533) 】 似乎可以满足滑动切换的功能,需要改动的就仅仅是将 video 部件放入其中。当然,后来也发现一些问题,不过只是些小问题。 3. 第三步的话,我选择了先做评论功能,因为评论功能看起来总比听起来很陌生的分布式迁移要好实现的多。制作评论的话,为了好看又美观,在 JsApi 中找到了一个 叫 pannel 的容器,这个容器是一块滑板,是可以上下滑动来呈现内容的。这个看上去就很不错,但是后来也发现了一些小问题【 [参考 JsApi 的 pannel 组件](https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-swiper-0000000000611533) 】。至于评论这个功能其实挺简单的,需要思考的就是如何把评论和相对应的视频配合起来。不过这个问题被 swiper 中的一个 onchange 事件给解决了。onchange 方法可以监听当前 swiper 的 index。 有了这个 index ,就可以知道当前的视频是哪个,也就可以提供上对应的评论了。 4. 第四步,只剩下了分布式流转功能了。这个功能,当然可以用 Java 的模板做,但是思来想去还是决定用 JsApi 中的内容试试。【 [参考 JsApi 的分布式迁移部分](https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-distributed-migration-0000001050024965) 】。查看了 JsApi 之后发现,用 Js 来实现分布式流转看起来竟然出乎意料的简单。但是,因为没有使用过分布式的经验,文档中也没有提及需要在 Java 部分提取权限,抓掉了许多头发。 不过事实上,确实相当的简单,使用上也是,代码上也是。 ### 项目简单的代码展示 #### 一、实现上下滑动切换 html 代码如下: ```html
``` Js 代码如下: ```javascript export default { data: { videoList: [ { url: '/common/1.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!AVA'}, {comment: '大家好!我是向晚!!'}, ], }, { url: '/common/2.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!Queen'}, {comment: '大家好!我是乃琳!!是 Elin 哦~'}, ], }, ], }, shareData: { inputValue: '', isStart: false, controls: true, currentIndex: 0, }, // 视频播放相关代码 change_current_video(e) { log("change_current_video: " + e.index); this.currentIndex = e.index; if(this.currentIndex == 0) { this.$element('videoId1').pause(); this.$element('videoId0').start(); } if (this.currentIndex == 1) { this.$element('videoId0').pause(); this.$element('videoId1').start(); } }, timeupdateCallback(e){ this.videoList[this.currentIndex].starttime = e.currenttime; }, change_start_pause() { if(this.isStart) { this.$element(`videoId${this.currentIndex}`).pause(); this.isStart = false; this.controls = true; } else { log("change_start_pause: " + `videoId${this.currentIndex}`) this.$element(`videoId${this.currentIndex}`).start(); this.isStart = true; this.controls = false; } }, // .... } ``` #### 二、实现评论发表展示功能 html 代码如下: ```html
全部评论 {{$item.comment}}
``` Js 代码如下: ```javascript export default { data: { videoList: [ { url: '/common/1.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!AVA'}, {comment: '大家好!我是向晚!!'}, ], }, { url: '/common/2.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!Queen'}, {comment: '大家好!我是乃琳!!是 Elin 哦~'}, ], }, ], }, shareData: { inputValue: '', isStart: false, controls: true, currentIndex: 0, }, // 评论相关代码 input_change(e){ this.inputValue = e.value; }, button_click(e){ log("button_click: " + e.text) this.videoList[this.currentIndex].commentList.push({comment: this.inputValue}); this.inputValue = ''; }, change_current_page(msg) { log("change_current_page: " + msg.direction + " " + msg.distance); switch (msg.direction) { case "left": this.$element('commentPanel').show(); break; case "right": this.tryContinueAbility(); log("TAG: " + "log in tryContinueAbility") break; } }, close_pannel(msg) { if (msg.direction === "right") { log("close_pannel: " + msg.direction) this.$element('commentPanel').close(); } }, // .... } ``` #### 实现分布式流转功能 Java 代码如下: ```java public class MainAbility extends AceAbility { @Override public void onStart(Intent intent) { super.onStart(intent); // 动态判断权限 if (verifySelfPermission("ohos.permission.DISTRIBUTED_DATASYNC") != IBundleManager.PERMISSION_GRANTED) { // 应用未被授予权限 if (canRequestPermission("ohos.permission.DISTRIBUTED_DATASYNC")) { // 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示) requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0); } } } @Override public void onStop() { super.onStop(); } } ``` Js 代码如下: ```javascript export default { data: { videoList: [ { url: '/common/1.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!AVA'}, {comment: '大家好!我是向晚!!'}, ], }, { url: '/common/2.mov', starttime: 0, commentList: [ {comment: 'HDC2021 HarmonyOS'}, {comment: '好期待!!Queen'}, {comment: '大家好!我是乃琳!!是 Elin 哦~'}, ], }, ], }, shareData: { inputValue: '', isStart: false, controls: true, currentIndex: 0, }, tryContinueAbility: async function() { // 应用进行迁移 let result = await FeatureAbility.continueAbility(); log("tryContinueAbility result:" + JSON.stringify(result)); }, onStartContinuation() { // 判断当前的状态是不是适合迁移 log("onStartContinuation"); return true; }, onSaveData(saveData) { // 数据保存到savedData中进行迁移。 var data = { videoList: this.videoList, }; Object.assign(saveData, data); log("onSaveData"); log("data:" + JSON.stringify(data)); }, onCompleteContinuation(code) { // 迁移操作完成,code返回结果 log("CompleteContinuation: code = " + code); }, onRestoreData(restoreData) { // 收到迁移数据,恢复。 log("onRestoreData: " + JSON.stringify(restoreData)) this.videoList = restoreData.videoList; // 跳转到指定的视频 this.$element('swiper').swipeTo({index: this.currentIndex}); // 确定是否播放指定视频 this.change_start_pause(); }, // .... } ``` Json 代码如下: ```json "reqPermissions": [ { "reason": "分布式视频流转数据分享", "name": "ohos.permission.DISTRIBUTED_DATASYNC" } ], ``` ## 总结 这次练习发现了许多问题,第一次使用 JsUI,发觉相较于 JavaUI,JsUI 显然对页面的设计更加快速,高效。虽然 JavaUI 也才刚刚开始接触。 但是,相比较花了很多时间,制作出来一个老难看的页面,JsUI 却是能做出来一个看起来不差的页面,至少能够看的过去了。之后,可能会更多的考虑尝试使用 JsUI 来进行软件的开发。 不过,问题还是有的,比如说,JsApi 的文档其实并不是很详细(对分布式迁移部分的怨念)。其他的问题就是一些有些挠头的问题了。 比如说,swiper 容器装着 video 进行切换的时候,容器里的视频似乎是一直播放的(可惜听不到视频声音,不然能确定一下)。为了解决这个问题,想了一个笨办法, 当开始滑动的时候,把某某视频停下,把某某视频开始。还好只有两个视频,直接写判断语句就行。如果是好多视频,这个问题还不知道该怎么解决。 还有对 pannel 的怨念,在选择使用 pannel 之后,某次输入评论的时候,忽然发现输入的评论不见了,后来查文档发现 pannel 似乎不支持 for 之类渲染的属性。 即便我是写在 pannel 内部的 div 容器里的似乎也不行。不过将就用吧,至少看起来很好看。 哦,对了。还有分布式流转的 api 文档中的例子。对 shareData 考虑了很久,一直在想这个和 data 有什么区别。shareData 是在触发流转的时候,会跟随着绑定到 流转过来的设备上的 shareData 上的,可是上面不是已经有了一个 continueAbilityData 来装流转的数据了么?为什么还需要一个 shareData 来装数据。后来经历了 一些奇妙的 bug 之后,我决定用 shareData 来装公用的数据,而 data 中的 continueAbilityData 就装了些比较特殊的数据。也不知道是对是错,不过至少看上去 运行的没太大问题。 哦,还有。当在 Remote 端恢复数据的时候,onRestoreData 函数中似乎不能使用 ```this.$element(`videoId${this.currentIndex}`).start() ```。这个函数 也不知道是哪里的问题。但是用其他的事件却是又可以的。 总体而言是满意的,除了撞的满头是包。对了,对我这个没有其他按键,只是通过上下左右滑动实现这个项目,还是非常开心的。至少看上去很干净,也很整洁(笑)。