jwyu пре 2 година
родитељ
комит
d0ded1977d

+ 271 - 0
components/videoBox/videoBox.vue

@@ -0,0 +1,271 @@
+<template>
+    <view class="video-wrap" @click="handleClickWrap">
+        <video
+            autoplay
+            object-fit="contain"
+            show-mute-btn
+            show-background-playback-button
+            enable-play-gesture
+            :poster="videoInfo.cover_img_url"
+            :src="videoInfo.video_url"
+            :id="videoInfo.community_video_id"
+            @ended="handleVideoEnd"
+            @pause="handleVideoPause"
+            @timeupdate="handleTimeUpdate"
+            v-if="videoInfo.id==curVideoId"
+        >
+            <view class="video-inner-right-box">
+                <view class="video-speed-btn" @click.stop="showSpeedOpt=true">倍速</view>
+            </view>
+            
+            <!-- 倍速选项模块 -->
+            <view class="speed-opt-box" v-if="showSpeedOpt">
+                <view 
+                    class="item"
+                    :style="{color:item==curSpeed?'#F3A52F':''}" 
+                    v-for="item in speedOpts" 
+                    :key="item" 
+                    @click.stop="handleVideoSpeedChange(item)"
+                >{{item}}X</view>
+            </view>
+        
+        </video>
+        <image @click="handelClickPlay" v-else class="poster" :src="videoInfo.cover_img_url" mode="aspectFill" lazy-load/>
+
+        <!-- 外面弹幕按钮 -->
+        <view class="danmu-btn-box" v-if="showDanmu">
+            <view class="big-box" v-if="!closeDM">
+                <view class="left" @click.stop="showInput=true"></view>
+                <view class="right" @click.stop="closeDM=true"></view>
+            </view>
+            <view class="small-box" v-else @click.stop="closeDM=false"></view>
+        </view>
+        
+        <!-- 弹幕输入弹窗 -->
+        <view class="flex danmu-input-box" v-if="showInput">
+            <view class="flex input-box">
+                <input 
+                    type="text" 
+                    v-model="danmuText" 
+                    placeholder="请输入弹幕~" 
+                    cursor-spacing="20" 
+                    maxlength="50" 
+                    focus 
+                    confirm-type="send"
+                    @keyboardheightchange="keyboardheightchange"
+                />
+                <text>{{danmuText.length}}/50</text>
+            </view>
+            <view class="btn">发送</view>
+        </view>
+          
+    </view>
+</template>
+
+<script>
+
+export default {
+    props:{
+        showDanmu:{
+            type:Boolean,
+            default:false
+        },//是否显示弹幕
+        videoInfo:{},//{source:2-视频社区\3-路演视频,id:视频社区id\路演视频id,...其他数据}
+        curVideoId:0,//当前正在播放的id
+    },
+    watch: {
+        curVideoId(){
+            this.curSpeed='1.0'
+        }
+    },
+    data() {
+        return {
+            curVideoIns:null,
+
+            showInput:false,//显示悬浮输入弹幕弹窗
+            closeDM:false,//是否关闭弹幕
+            danmuText:'',
+
+            showSpeedOpt:false,
+            speedOpts:['0.5','0.8','1.0','1.25','1.5','2.0'],
+            curSpeed:'1.0',
+        }
+    },
+    methods: {
+        //点击最外层盒子
+        handleClickWrap(){
+            this.showSpeedOpt=false
+        },
+
+        // 点击播放
+        handelClickPlay(){
+            this.$emit('videoPlay', this.videoInfo)
+            setTimeout(() => {
+                this.curVideoIns=uni.createVideoContext(this.curVideoId.toString(),this)//由于是在自定义组件内 所有this不可少
+            }, 300);
+        },
+        handleVideoEnd(){
+            // 此处因为如果不调用退出全屏方法 安卓和ios页面均会表现异常,安卓横屏不恢复竖屏,ios底部tabbar渲染异常
+            this.curVideoIns.exitFullScreen()
+            this.curVideoIns=null
+            this.$emit('ended')
+        },
+        handleVideoPause(){
+            this.$emit('pause')
+        },
+        handleTimeUpdate(e){
+            this.$emit('timeupdate',e)
+        },
+        
+        //键盘高度变为0 则收起悬浮弹幕输入框
+        keyboardheightchange(e){
+            if(e.detail.height===0){
+                setTimeout(() => {
+                    this.showInput=false
+                }, 60);
+            }
+        },
+
+
+        // 倍速切换
+        handleVideoSpeedChange(item){
+            const num=Number(item)
+            this.curVideoIns.playbackRate(num)
+            this.curSpeed=item
+            this.showSpeedOpt=false
+        }
+
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.video-wrap{
+    width: 100%;
+    height: 100%;
+    position: relative;
+    video,.poster{
+        width: 100%;
+        height: 100%;
+        border-radius: 20rpx;
+        position: relative;
+    }
+    .poster{
+        position: relative;
+        &::after{
+            content:'';
+            display: block;
+            position: absolute;
+            width: 120rpx;
+            height: 120rpx;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%,-50%);
+            background-image: url('@/static/video-play-btn.png');
+            background-size: cover;
+        }
+    }
+
+    .danmu-btn-box{
+        position: absolute;
+        bottom: -70rpx;
+        right: 6rpx;
+        .big-box{
+            width: 248rpx;
+            height: 50rpx; 
+            background-image: url('@/static/danmu-show-btn.png');  
+            background-size: cover; 
+            display: flex;
+            .left{
+                width: 67%;
+                height: 100%;
+                flex-shrink: 0;
+            }
+            .right{
+                flex: 1;
+                height: 100%;
+            }
+        }
+        .small-box{
+            width: 80rpx;
+            height: 50rpx; 
+            background-image: url('@/static/danmu-close-btn.png');  
+            background-size: cover; 
+        }
+    }
+
+    .danmu-input-box{
+        position: fixed;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        z-index: 999999;
+        background-color: #fff;
+        padding: 10rpx 34rpx;
+        border-top: 1px solid #E5E5E5;
+        align-content: center;
+        .input-box{
+            flex:1;
+            border-radius: 40rpx;
+            padding: 6rpx 10rpx;
+            background: #EFEFEF;
+            border: 2rpx solid #E5E5E5;
+            align-items: center;
+            font-size: 12px;
+            input{
+                flex:1;
+            }
+            text{
+                color: #999;
+            }
+        }
+        .btn{
+            width: 100rpx;
+            flex-shrink: 0;
+            color: #F3A52F;
+            font-size: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+    }
+
+
+    .video-inner-right-box{
+        position: absolute;
+        bottom: 30%;
+        right: 5%;
+    }
+
+    .video-speed-btn{
+        width: 80rpx;
+        height: 44rpx;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: rgba(0, 0, 0, 0.4);
+        border-radius: 22rpx;
+        color: #fff;
+        font-size: 12px;
+    }
+    .speed-opt-box{
+        position: absolute;
+        right: 0;
+        top: 0;
+        bottom: 0;
+        width: 20%;
+        background: rgba(0, 0, 0, 0.8);
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+        padding-top: 55rpx;
+        .item{
+            color: #fff;
+            font-size: 26rpx;
+            flex: 1;
+            width: 100%;
+            text-align: center;
+        }
+    }
+}
+</style>

+ 9 - 1
components/videoComment/comment.vue

@@ -1,6 +1,6 @@
 <template>
     <view class="video-comment-wrap">
-        <view class="flex action-wrap">
+        <view :class="['flex action-wrap',showDanmu?'showDanmu':'']">
             <view class="item" @click="handleSetLike(1)">
                 <image :src="info.op_type===1?like_act_img:like_img" mode="aspectFill"/>
                 <text>{{info.like_total>0?info.like_total:''}}</text>
@@ -74,6 +74,10 @@
 import {apiSetLike,apiHotComment,apiMyComment,apiPublishComment,apiDelComment} from '@/api/question'
 export default {
     props:{
+        showDanmu:{
+            type:Boolean,
+            default:false
+        },
         videoInfo:null,//{source:2-视频社区\3-路演视频,id:视频社区id\路演视频id,...其他数据}
     },
     data() {
@@ -234,6 +238,10 @@ export default {
             }
         }
     }
+    .showDanmu{
+        width: 50%;
+        padding: 0;
+    }
 }
 .list-commnet-box{
     margin-top: 34rpx;

+ 18 - 46
pages/video/videoList.vue

@@ -45,22 +45,18 @@
                     <image class="share-img" src="@/static/share-icon.png" mode="aspectFill"/>
                 </button>
                 <view class="time">发布时间:{{item.publish_time}}</view>
-                <video
-                    autoplay
-                    object-fit="contain"
-                    show-mute-btn
-                    show-background-playback-button
-                    :poster="item.cover_img_url"
-                    :src="item.video_url"
-                    enable-play-gesture
-                    :id="item.community_video_id"
-                    @ended="handleVideoEnd"
-                    @pause="handleVideoPause"
-                    @timeupdate="handleTimeUpdate"
-                    v-if="item.community_video_id==curVideoId"
-                ></video>
-                <image @click="handelClickPlay(item)" v-else class="poster" :src="item.cover_img_url" mode="aspectFill" lazy-load/>
-                <comment :videoInfo="getCommentData(item)"></comment>
+                <view class="video-content">
+                    <videoBox 
+                        :videoInfo="getCommentData(item)"
+                        :curVideoId="curVideoId"
+                        :showDanmu="showDanmu"
+                        @videoPlay="handelClickPlay"
+                        @ended="handleVideoEnd"
+                        @pause="handleVideoPause"
+                        @timeupdate="handleTimeUpdate"
+                    />
+                </view>
+                <comment :showDanmu="showDanmu" :videoInfo="getCommentData(item)"></comment>
             </view>
         </view>
 
@@ -124,12 +120,14 @@ import noAuth from './components/noAuth.vue'
 import dragButton from '@/components/dragButton/dragButton.vue'
 import comment from '@/components/videoComment/comment.vue'
 import collectBox from '@/components/collectBox/collectBox.vue'
+import videoBox from '@/components/videoBox/videoBox.vue'
 export default {
     components:{
         noAuth,
         comment,
         dragButton,
-        collectBox
+        collectBox,
+        videoBox
     },
     data() {
         return {
@@ -145,12 +143,13 @@ export default {
             list:[],
 
             curVideoId:0,
-            curVideoIns:null,
             curVideoTime:0,
             videoRecordId:0,
 
             isAuth:true,
             noAuthData:null,
+
+            showDanmu:true,//控制整个模块是否显示弹幕功能(没用了本来后台有个开关功能的 后来不要了 但是还是留着吧)
         }
     },
     onLoad(options){
@@ -165,7 +164,6 @@ export default {
     },
     onHide(){
         this.showFilter=false
-        // this.curVideoId=0
     },
     onShareAppMessage({from,target}) {
         console.log(from,target);
@@ -291,9 +289,6 @@ export default {
 
         handelClickPlay(item){
             this.curVideoId=item.community_video_id
-            setTimeout(() => {
-                this.curVideoIns=uni.createVideoContext(this.curVideoId.toString())
-            }, 300);
             // 记录播放
             apiVideoPlayLog({video_id:Number(item.community_video_id)}).then(res=>{
                 if(res.code===200){
@@ -305,11 +300,8 @@ export default {
 
         //视频播放结束
         handleVideoEnd(){
-            // 此处因为如果不调用退出全屏方法 安卓和ios页面均会表现异常,安卓横屏不恢复竖屏,ios底部tabbar渲染异常
-            this.curVideoIns.exitFullScreen()
             setTimeout(() => {
                 this.curVideoId=0
-                this.curVideoIns=null
             }, 200);
         },
 
@@ -415,30 +407,10 @@ export default {
                 font-size: 32rpx;
                 color: #000;
             }
-            video{
+            .video-content{
                 width: 100%;
                 height: 400rpx;
                 margin: 30rpx 0 20rpx 0;
-                border-radius: 20rpx;
-            }
-            .poster{
-                width: 100%;
-                height: 400rpx;
-                margin: 30rpx 0 20rpx 0;
-                border-radius: 20rpx;
-                position: relative;
-                &::after{
-                    content:'';
-                    display: block;
-                    position: absolute;
-                    width: 120rpx;
-                    height: 120rpx;
-                    top: 50%;
-                    left: 50%;
-                    transform: translate(-50%,-50%);
-                    background-image: url('@/static/video-play-btn.png');
-                    background-size: cover;
-                }
             }
             .time{
                 font-size: 28rpx;

BIN
static/danmu-close-btn.png


BIN
static/danmu-show-btn.png