纯JS分布式视频播放应用 原创 精华

狼哥Army
发布于 2021-10-13 11:43
浏览
11收藏

一, 前言

       今时今日,不管是大人,还是小孩,都喜欢刷视频,生活中刷视频的APP也多得是,如:抖音,快手,视频号,今日头条,火山… 数也不数不清了,然而华为论坛鸿蒙版块搞活动,做一个属于自己的视频应用,说真的,看到这个活动我很开心,又可以用所学的鸿蒙知识来做一个小应用了,看了小提示,都是JS组件来实现的,当我看到分布式也可以用JS来写时,当时觉得JS也太强大了,因为之前写的Demo都是用Java来写分布式的,本人工作也是从事Java后台开发,对于JS前端知识,也就是入门级水平,然后就在想是用Java来写这个视频应用,还是用JS来写呢,通过看了JS参考API实例后,决定使用JS来写,简单易懂,同时也希望现在还在观望鸿蒙应用开发的前端开发人员,不要怕自己不会Java开发,而一直在观望,没有踏出第一步来写Demo,我写的这个视频应用取名为 爱视频 ,99%是用JS前端知识完成的,只有1%Java代码是复制过来的,也就是动态授权代码,所以希望还在观望的前端开发者,就从这个 爱视频 APP开始你们的第一个鸿蒙应用吧!

二, 实现效果
       开发环境下视频:https://www.bilibili.com/video/BV1kf4y177h2/?spm_id_from=333.788
       手机下视频:https://www.bilibili.com/video/BV1qr4y127s5?spm_id_from=333.999.0.0
纯JS分布式视频播放应用-鸿蒙开发者社区       
三, 创建工程

       在这当作你已经安装好最新版本DevEco-Studio开发工具, 点击File -> New -> New Project… 弹出Create HarmonyOS Project窗口, 这里我选择空白JS模板创建, 写界面还是JS比较方便些, 对于有一定前端知识的小伙伴来说.
纯JS分布式视频播放应用-鸿蒙开发者社区纯JS分布式视频播放应用-鸿蒙开发者社区

四, 主界面开发

       在展示源代码之前,先介绍一下使用到了JS哪些组件:滑动容器(swiper),视频播放(video),可滑动面板(panel),列表组件(list),图片组件(image),文本组件(text),交互式组件(input),按钮组件(button) 通过查看JS API参考文档,就可以做出你喜欢的视频应用了。
       先介绍简单的1% Java代码,如果之前做过分布式Demo,直接复制过来就可以使用:

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();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

HML代码: 重要界面布局文件

<div class="container">
    <swiper class="swiper" id="swiper" index="{{ continueAbilityData.currentIndex }}" indicator="false" loop="true" digital="false" vertical="true" onchange="changeSwiper">
        <div class = "swiperContent" >
            <video id='videoOne' src='{{ continueAbilityData.videoList[0] }}' muted='false' autoplay='true'ontimeupdate='timeupdateCallback' style="object-fit:fill; width:100%; height: 100%;" controls="false" onclick="change_start_pause_one" loop='true' starttime = '{{ ontinueAbilityData.timeupdatetime }}'></video>
        </div>
        <div class = "swiperContent">
            <video id='videoTwo' src='{{ continueAbilityData.videoList[1] }}' muted='false' autoplay='false' ontimeupdate='timeupdateCallback' style="object-fit:fill; width:100%; height: 100%;" controls="false" onclick="change_start_pause_two" loop='true' starttime = '{{ ontinueAbilityData.timeupdatetime }}'></video>
        </div>
        <div class = "swiperContent">
            <video id='videoThree' src='{{ continueAbilityData.videoList[2] }}' muted='false' autoplay='false' ontimeupdate='timeupdateCallback' style="object-fit:fill; width:100%; height: 100%;" controls="false" onclick="change_start_pause_three" loop='true' starttime = '{{ continueAbilityData.timeupdatetime }}'></video>
        </div>
    </swiper>
    <div class="btn-footer">
        <image class="comment-icon icon" src="/common/army_icon.jpg"></image>
        <text class="footer-label">#HarmonyOS挑战赛第二期#</text>
        <image class="comment-icon" src="/common/share.png" onclick="tryContinueAbility"></image>
        <image class="comment-icon" src="/common/bxs-message.png" onclick="showPanel"></image>
    </div>
    <panel id="simplepanel" type="foldable" mode="half" miniheight="400px">
        <div class="panel-div">
            <list class="todo-wrapper">
                <list-item for="{{continueAbilityData.todolist}}" class="todo-item">
                    <image class="todo-icon" src="/common/avatar04.png"></image>
                    <text class="todo-title">{{$item.title}}</text>
                </list-item>
            </list>
            <div class="inner-btn">
                <input id="input" class="input" type="text" value="{{continueAbilityData.comment}}" maxlength="20" enterkeytype="send" placeholder="请输入评论内容" onchange="changeValue" onenterkeyclick="enterkeyClick" style="margin-right: 10px;"></input>
                <button type="capsule" value="关闭" onclick="closePanel"></button>
            </div>
        </div>
    </panel>
</div>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

JS代码: 重要逻辑代码,各组件事件

// @ts-nocheck
import app from '@system.app';
export default {
    data: {
        img: "resources/media/pic_tv.png",
        continueAbilityData: {
            currentIndex: 0,
            videoList: [
                "/common/000001.mp4",
                "/common/000002.mp4",
                "/common/000003.mp4"
            ],
            timeupdatetime: 2,
            isStart: true,
            todolist: [
                {title: 'HDC2021活动门票进行中'},
                {title: '我期待HarmonyOS生态越来越完善'},
                {title: 'HarmonyOS你值得拥有'}],
            comment: ''
        }
    },
    onInit() {
    },
    changeSwiper(e) {
        console.info("onRestoreData:changeSwiper");
        this.switchPlay(e.index);
    },
    switchPlay(index) {
        console.info("onRestoreData:onShow <> " + index);
        this.continueAbilityData.currentIndex = index;
        if(index == 0) {
            this.$element('videoOne').start();
            this.$element('videoTwo').pause();
            this.$element('videoThree').pause();
            console.info("onRestoreData:videoOne <> start " + this.$element('videoOne').starttime);
        }else if(index == 1) {
            this.$element('videoOne').pause();
            this.$element('videoTwo').start();
            this.$element('videoThree').pause();
            console.info("onRestoreData:videoTwo <> start " + this.$element('videoTwo').starttime);
        }else if(index == 2) {
            this.$element('videoOne').pause();
            this.$element('videoTwo').pause();
            this.$element('videoThree').start();
            console.info("onRestoreData:videoThree <> start " + this.$element('videoThree').starttime);
        }
    },

    //流转事件
    tryContinueAbility: async function() {
        // 应用进行迁移
        let result = await FeatureAbility.continueAbility();
        console.info("result:" + JSON.stringify(result));
    },
    onStartContinuation() {
        // 判断当前的状态是不是适合迁移
        console.info("onStartContinuation");
        return true;
    },
    onCompleteContinuation(code) {
        // 迁移操作完成,code返回结果
        console.info("CompleteContinuation: code = " + code);
        app.terminate();

    },
    onSaveData(saveData) {
        // 数据保存到savedData中进行迁移。
        var data = this.continueAbilityData;
        console.info("onSaveData:" + JSON.stringify(data));
        Object.assign(saveData, data)
    },
    onRestoreData(restoreData) {
        console.info("onRestoreData:" + JSON.stringify(restoreData));
        // 收到迁移数据,恢复。
        this.continueAbilityData = restoreData;

        var currentIndex = this.continueAbilityData.currentIndex;
        var currentTime = this.continueAbilityData.timeupdatetime;

        this.$element('videoOne').pause();
        this.$element('videoTwo').pause();
        this.$element('videoThree').pause();

        this.$element('videoOne').starttime = currentTime;
        this.$element('videoTwo').starttime = currentTime;
        this.$element('videoThree').starttime = currentTime;

        this.switchPlay(currentIndex);
    },

    //评论事件
    showPanel() {
        this.$element('simplepanel').show()
    },
    closePanel() {
        this.$element('simplepanel').close()
    },
    changeValue(e) {
        this.continueAbilityData.comment = e.value;
    },
    enterkeyClick(e) {
        this.continueAbilityData.todolist.push({title: this.continueAbilityData.comment});
        this.continueAbilityData.comment = "";
    },
    timeupdateCallback:function(e){ this.continueAbilityData.timeupdatetime = e.currenttime;},
    change_start_pause_one: function() {
        if(this.continueAbilityData.isStart) {
            this.$element('videoOne').pause();
            this.continueAbilityData.isStart = false;
        } else {
            this.$element('videoOne').start();
            this.continueAbilityData.isStart = true;
        }
    },
    change_start_pause_two: function() {
        if(this.continueAbilityData.isStart) {
            this.$element('videoTwo').pause();
            this.continueAbilityData.isStart = false;
        } else {
            this.$element('videoTwo').start();
            this.continueAbilityData.isStart = true;
        }
    },
    change_start_pause_three: function() {
        if(this.continueAbilityData.isStart) {
            this.$element('videoThree').pause();
            this.continueAbilityData.isStart = false;
        } else {
            this.$element('videoThree').start();
            this.continueAbilityData.isStart = true;
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.

CSS代码: 重要化妆技术

.container {
    width: 100%;
    height: 100%;
    flex-direction: column;
}

.img {
    object-fit: cover;
    background-color: #808080;
}

.swiper {
    flex-direction: column;
    align-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
    background-color: black;
}
.swiperContent {
    height: 100%;
    justify-content: center;
    background-color: black;
}

.btn-footer {
    height: 60px;
    line-height: 60px;
    width: 100%;
    background-color: black;
    flex-direction: row;
}
.footer-label {
    font-size: 16px;
    color: white;
    padding-top: 0px;
    flex-weight: 1;
    line-height: 20px;
}
.comment-icon {
    width: 32px;
    height: 32px;
    margin: 8px;
}
.icon {
    border-radius: 16px;
}

.panel-div {
    flex-direction: column;
    align-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
}
.inner-btn {
    height: 70px;
    padding: 10px;
}
.todo-wrapper {
    width: 100%;
    height: 100%;
}
.todo-item {
    width: 100%;
    height: 30px;
    padding-left: 10px;
    padding-right: 10px;
}
.todo-icon {
    width: 16px;
    height: 16px;
    margin-top: 10px;
    margin-right: 10px;
}
.todo-title {
    width: 100%;
    height: 100%;
    text-align: left;
    font-size: 14fp;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.

代码就写到此了,不要忘记了config.json文件的权限配置哦,在module下添加

"reqPermissions": [
   {
      "name": "ohos.permission.DISTRIBUTED_DATASYNC"
   }
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

五, 总结

       说实存的,当看到这个活动时间才几天时,感觉时间不太够用,要滑动视频,要评论功能,要分布式的,加上都是用空闲时间来做的,然而当深入去理解相关组件用法后,发现应该一天时间就可以了。
       有兴趣的小伙伴可以下载源码查看, 项目代码写得还不算靓仔, 很多为了实现效果,都是Hardcode的,有空可以把重复代码抽出来,视频源也可以放到服务器上,然后就可以更愉快的刷更多视频了,源码同步到gitee码云,项目素材没有上传,自行添加。

源码在这: https://gitee.com/army16/qin-hong-jun-video

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-10-13 11:43:03修改
15
收藏 11
回复
举报
15
3
11
3条回复
按时间正序
/
按时间倒序
SummerRic
SummerRic

纯JS分布式视频播放应用,没得说,超棒的。

回复
2021-10-13 11:51:29
狼哥Army
狼哥Army 回复了 SummerRic
纯JS分布式视频播放应用,没得说,超棒的。

代码量也超级少了,真的是程序员注重逻辑就可以了。

回复
2021-10-13 14:47:58
时空未宇
时空未宇

完美🥰 🥰 

回复
2021-10-14 09:17:35


回复
    相关推荐