乐趣区

uniapp开发一个小视频应用二

一、前情回顾

uni-app 开发一个小视频应用(一)

上篇文章,我们已经实现了首页的头部导航栏组件、底部的 tabBar 导航栏组件、中间的视频列表组件以及视频列表组件中的视频播放组件,传入视频列表渲染后已经可以上下滑动进行视频切换和播放,接下来我们将完成首页的剩余部分,左侧信息栏组件 右侧图标栏组件 ,以及 完善视频切换动画 播放控制 等功能。

二、创建左侧信息栏组件

左侧的信息栏组件,主要分三块: 作者名 视频标题名 音乐名 。这个左侧信息栏信息是和当前播放视频相关联的,所以应该在循环视频列表的时候,将左侧信息栏组件一起渲染出来,所以 左侧信息栏组件应该加到 <swiper-item> 中

// components/list-left.vue

<template>
    <view class="list-left">
        <view class="author">
            @祝晓晗
        </view>
        <view class="title">
            妈呀,遇到老同学了,缘分呐! @老丈人说车 @抖音小助手
        </view>
        <view class="music-box"> <!-- 该 music-box 主要是为了在 music 内容滚动的时候在超出 music-box 范围后能够隐藏超出部分 -->
            <view class="music">
                @祝晓晗创作的原声 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  @祝晓晗创作的原声
            </view>
        </view>
    </view>
</template>
<style scoped>
    .list-left{
        width: 70%;
        height: 120px;
        color: white;
    }
    .author {
        height: 35px;
        line-height: 35px;
        font-size: 17px;
    }
    .title {
        width: 100%;
        line-height: 25px;
        font-size: 12px;
        word-wrap: break-word;
        color: #FFFAF0;
    }
    .music-box {
        overflow: hidden; <!-- 滚动的时候超出部分隐藏 -->
        width: 70%;
    }
    .music {
        width: 200%;
        height: 35px;
        line-height: 35px;
        font-size: 12px;
        animation: scroll-x 5s linear 0.2s infinite; <!-- 应用动画 -->
    }
    @keyframes scroll-x{ <!-- 添加文字水平滚动动画 -->
        0% {transform: translate3d(80%, 0, 0); <!--80% 位置出现,然后向左边滚动 -->
        }
        100% {transform: translate3d(-80%, 0, 0); <!-- 动画结束后到达 -80% 位置 -->
        }
    }
</style>

// components/video-list.vue

<template>
    <view class="video-list">
        <view class="swiper-box">
            <swiper class="swiper" :vertical="true">
                <swiper-item v-for="(item,index) in videos" :key="index">
                    <view class="swiper-item">
                        <video-player                         
                             :video="item"                        
                            :index="index">
                        </video-player>
                    </view>
                    <view class="left-box"> <!-- 将左侧信息栏组件放到 <swiper-item> 中同视频一起渲染出来 -->
                        <list-left></list-left>
                    </view>
                </swiper-item>
            </swiper>
        </view>
    </view>
</template>

<style>
.left-box { <!-- 给左侧列表组件添加绝对定位 并设置 z -index 以显示到视频上方 -->
        position: absolute;
        bottom: 50px;
        left: 10px;
        z-index: 20; 
}
</style>

三、创建右侧图标栏组件

右侧图标栏组件,主要分为: 头像图标 (头像设置 border-radius)、 收藏图标 (iconfont 图标)、 评论图标 (iconfont 图标)、 分享图标 (iconfont 图标)、 音乐图标(图片设置 border-radius),右侧图标栏组件设置一个固定宽度,然后让各种图标依次排列即可,如:

// components/list-right.vue

<template>
    <view class="list-right">
        <view class="author-img">
            <img class="img" src="../static/zxh.jpg"/>
        </view>
        <view class="right-box">
            <view class="icon iconfont icon-xin"></view>
            <view class="count">72.2w</view>
        </view>
        <view class="right-box">
            <view class="icon iconfont icon-pinglun1"></view>
            <view class="count">1.8w</view>
        </view>
        <view class="right-box">
            <view class="icon iconfont icon-arrow-"></view>
            <view class="count">6645</view>
        </view>
        <view class="music-img">
            <img class="img" src="../static/music.jpg"/>
        </view>
    </view>
</template>

<style scoped>
    .list-right {width: 60px;}
    .author-img {
        width: 60px;
        text-align: center;
    }
    .img {
        width: 50px;
        height: 50px;
        border-radius: 50%;
    }
    .author-img img{border: 2px solid #FFFFFF;}
    .right-box {
        margin: 20px auto;
        color: white;
        text-align: center;
        font-size: 12px;
    }
    .icon {font-size: 40px;}
    .music-img {
        width: 60px;
        height: 51px;
        text-align: center;
        margin-top: 20px;
        animation: around 1.5s linear 0.2s infinite; <!-- 使用动画 -->
    }
    @keyframes around { <!-- 添加 360 环绕旋转动画 -->
        0% {transform: rotate(0deg);
        }
        100% {transform: rotate(360deg);
        }
    }
</style>

四、给右侧图标组件添加上相应的事件

当点击头像下部的加号图标,可以对该用户进行关注,即 隐藏加号图标 ,还有就是 收藏爱心图标颜色切换,当点击收藏爱心图标,爱心图标变成红色,再次点击收藏爱心图标,爱心图标变回白色,这里先只处理颜色的变化,具体后台交互暂不处理。

// 在头像图标下方通过绝对定位添加一个加号图标,并定位到头像底部

<view class="author-img">
    <img class="img" src="../static/zxh.jpg"/>
    <view class="follow iconfont icon-jiahao" v-show="showFollow" @click="hideFollow"><!-- 添加一个加号图标,以及监听 hideFollow 事件 -->
    </view>
</view>

<view class="right-box">
    <view class="icon iconfont icon-xin" :class="{fav: isFav}" @click="changeColor"></view><!-- 监听切换收藏爱心图标颜色 -->
    <view class="count">72.2w</view>
</view>

<script>
    export default {data() {
            return {
                showFollow: true,
                isFav: false
            }
        },
        methods: {hideFollow() { // 隐藏关注加号图标
                this.showFollow = false;
            },
            changeColor() {this.isFav = !this.isFav; // 切换收藏爱心颜色}
        }
    }
</script>
<style scoped>
.follow {
        color: white;
        position: absolute;
        width: 18px;
        height: 18px;
        line-height: 18px;
        background: red;
        border-radius: 50%;
        text-align: center;
        left: 23px;
        bottom: -5px;
        font-weight: bold;
}
.fav {color:red;}
</style>

五、实现滑动播放功能

所谓滑动播放,即向上滑动的时候,暂停当前播放视频并且播放下一个视频,向下滑动的时候,暂停当前播放视频,播放上一个视频,而这最关键的就是 如何判断是向上滑动还是向下滑动 <swiper> 组件给我们提供了一个 change 事件,我们可以监听这个 change 事件, 拿到滑动完成后滑动到了第几页 ,即 <swiper-item> 的序号(从 0 开始),然后与滑动前的当前 page 相比较,就可以知道是向上滑还是向下滑了。
判断好了是上滑还是下滑后,我们还需要对上滑和下滑作出正确的处理,我们需要能够拿到每个视频播放组件,然后调用视频播放组件上的相关方法对播放进行控制,这就是涉及到了 父组件如何调用子组件上方法 ,父组件要想调用子组件上的方法, 关键是父组件要能够拿到子组件对象 ,我们可以通过ref 实现,因为每一个视频播放组件是 video-list 视频列表组件的一个子组件,所以我们可以 在 video-list 视频列表组件中给每一个 video-player 视频播放组件添加上一个 ref=”player”,即可拿到对应的视频播放组件了。

// components/video-list.vue

<swiper class="swiper" :vertical="true" @change="slider"> <!-- 监听 change 事件 -->
    <swiper-item v-for="(item,index) in videos" :key="index">
        <view class="swiper-item">
            <video-player
                ref="players" <!-- 给每一个视频播放组件添加一个 ref 标识 -->
                :video="item"                        
                :index="index">
            </video-player>
        </view>
    </swiper>
</swiper>
<script>
export default {data() {
        return {currentPage: 0 // 保存当前 page 的编号}
    },
    methods: {slider(e) {
            const targetPage = e.detail.current;
            if (targetPage === this.currentPage + 1) {console.log("向上滑动");
                this.$refs.players[this.currentPage + 1].playFromHead(); // 下一个开始播放并且从头开始播放
                this.$refs.players[this.currentPage].pause(); // 当前视频暂停播放} else if(targetPage === this.currentPage - 1) {console.log("向下滑动");
                this.$refs.players[this.currentPage - 1].playFromHead(); // 上一个开始播放并且从头开始播放
                this.$refs.players[this.currentPage].pause(); // 当前视频暂停播放}
                this.currentPage = targetPage;
        }
    }
}
</script>

需要注意的是,this.$refs.players 返回的是一个数 组,即 所有播放组件的实例 ,我们通过不同的索引即可取得对应的视频播放组件,然后进行相应的播放控制了,接下来就是要给每一个视频播放组件添加上播放控制的方法,我们 需要给 <video> 组件添加上一个 id,然后 通过这个 id 可以创建出 video 上下文 ,即可调用 play()、pause()、seek() 等相关方法对播放进行控制。

// components/video-player.vue

<template>
    <view class="video-player">
        <video class="video"
               id="myVideo" <!-- 给 video 组件添加一个 id,以便获取到 video 上下文对象 -->
               :src= "video.src" 
               :controls="false"
               :loop="true">
        </video>
    </view>
</template>
<script>
export default {onReady() {this.videoContext = uni.createVideoContext("myVideo", this); // 获取 video 上下文对象
    },
    methods: {play() {this.videoContext.play();
        },
        pause() {this.videoContext.pause();
        },
        playFromHead() { // 跳转到开始位置并播放
            this.videoContext.seek(0);
            this.play();}
    }
}
</script>

六、实现单击播放暂停切换以及双击关注用户功能

要想实现单击视频播放组件,视频可以进行播放和暂停切换,那么我们 需要给视频播放组件添加一个 isPlay 属性表示视频是否处于播放中 ,如果是播放中,那么点击就暂停,如果不是播放中,那么点击就播放,同时,由于uni-app 不支持 vue 的 dblclick 事件 的,所以我们还 需要对单击和双击操作进行判断,我们需要定义一个变量用于记录用户点击次数,如果 300ms 内用户点击次数大于等于 2,那么就是双击,否则就是单击,如:

<template>
    <view class="video-player">
        <video class="video"
               id="myVideo"
               :src= "video.src" 
               :controls="false"
               :loop="true"
               @click="doClick"><!-- 添加 click 事件进行视频播放和暂停的切换 -->
        </video>
    </view>
</template>
<script>
    let timer = null; // 定义一个定时器
    export default {data() {
            return {
                isPlay: false, // 当前视频是否在播放中,默认为 false
                clickCount: 0 // 记录当前用户点击次数,默认为 0
            }
        },
        methods: {play() {this.videoContext.play();
                this.isPlay = true; // 进入视频播放状态设置 isPlay 为 true
            },
            pause() {this.videoContext.pause();
                this.isPlay = false; // 进入视频暂停状态设置 isPlay 为 false
            },
            playFromHead() {this.videoContext.seek(0);
                this.play();},
            doClick() { // 进行视频播放和暂停的切换
                if (timer) {clearTimeout(timer);
                }
                this.clickCount++; // 每次单击视频播放组件,点击次数加 1
                timer = setTimeout(() => {if (this.clickCount >=2) { // 如果 300ms 内点击次数大于等于 2 就表示是双击了
                        console.log("双击");
                        this.$emit("follow"); // 双击的话向 video-list 父组件 (视频列表组件) 发送一个 follow 事件
                    } else {console.log("单击");
                        if (this.isPlay) {this.pause();
                        } else {this.play();
                        }
                    }
                    this.clickCount = 0; // 重置点击次数为 0
                }, 300);
            }
        }
    }
</script>

双击的时候会向 video-list 父组件 (视频列表组件) 发送一个 follow 事件,video-list 组件监听到 follow 事件后再通知 <list-right> 组件调用其方法让其爱心图标变红即可,如:

<template>
    <video-player
        @follow="follow">
    </video-player>
    <view class="right-box">
        <list-right ref="listRight"></list-right> <!-- 给 list-right 组件添加 ref 标识 -->
    </view>
</template>
<script>
    export default {follow() {this.$refs.listRight[0].follow();}
    }
</script>

七、实现首个视频自动播放功能

之前我们的视频播放组件接收了一个 index 属性,即当前视频对应的索引号,我们可以通过这个索引号判断当前视频是否是第一个,然后将其 video 组件的 autoPlay 设置为 true 即可自动播放。

<template>
    <view class="video-player">
        <vide :autoplay="auto> <!-- 绑定 autoplay 属性控制是否自动播放 -->
        </video>
    </view>
</template>
<script>
    export default {data() {
            return {auto: false // 是否自动播放}
        },
        methods: {autoPlay() {if (this.index === 0) {this.auto = true;}
            }
        },
        created() {this.autoPlay();
        }
    }
</script>

至此,首页已经完成。

退出移动版