🎉视频播放你还在用video.js吗?快来试试西瓜播放器

15,710 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

🎯前言

视频播放可能在日常的业务场景中并不多,但绝对不陌生,选择好用的插件往往事半功倍。今天笔者将带来一个场景介绍一下由字节跳动开源的西瓜播放器(点它),功能很多很强大😎。

本文使用Vue+Xgplayer

测试视频url:sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4

videoList数据可以灵活处理, 简而言之只需要一个视频的url和一个图片的url。

🎯预期效果

西瓜视频有这样一个预览的效果(很多视频网站都有),我们今天的内容就是这个效果

video.gif

🎯最终效果

video-list.gif

🎯xgplayer简单使用

🫀安装xgplayer

    npm install xgplayer

在需要的vue组件中引入并初始化


import Player from 'xgplayer'
let player = new Player({
        id:'' ,            //标签的id名或者 使用 el:dom元素
        url: 视频url,
        videoInit: true,
        poster: 封面图,
        controls: false,      
        playbackRate: [0.5, 0.75, 1, 1.5, 2],
        whitelist: [
        ''
        ],
        fluid: false,
        // download: true,
        width: '100%',
        height: '200px'
    })

这样就能创建一个可以在指定的容器里创建一个视频播放器了。

🎯实现思路

在上文的完整效果里这个案例显然是循环出来的多个容器,这里就要考虑Player实例的问题了,创建一个还是多个,这里有两种思路,本文采用第一种。顺便一提,真实业务中数据来源于接口服务(坑在这)。

1.循环创建多个容器,并为每个创建实例,滚动加载会带来实例过多的问题;为了避免,可以采用分页的形式。

2.循环创建容器,不创建实例,只展示封面,移入容器时销毁前一个实例,创建当前实例(比较优解),读者可以尝试一下。

根据效果,不难看出,移入容器的时候视频播放,移出的时候当前视频暂停,这样保持同时只有一个在播放。 我这里准备了一个img封面层和一个video视频层,默认显示图片层,使用两个事件mouseEnter和mouseleave动态的控制对应容器的显示和隐藏(也有个小坑),并对对应索引的实例操作(暂停,销毁等)。

    startPlay(data,index){
        this.$refs['img'+index][0].style.display="none"
        this.$refs['video'+index][0].style.display="block"
        this.$nextTick(()=>{
            this.dom[index].play()
        })
    },

    move(data,index){
        this.$refs['img'+index][0].style.display="block"
        setTimeout(() => {
            this.dom[index].pause()    
        }, 0);
        this.$refs['video'+index][0].style.display="none"
    },

🎯完整代码

<template>
 <div class="video">
     <div class="video-content" id="videoScroll" ref="videoScrollBar">
        <div  class="card"    v-for="(item,index) in videoList" :key="index"   >
                <div style="width:100%;height:200px" 
                    @mouseenter="startPlay(item,index)"
                    @mouseleave="move(item,index)">
                    <div                     
                        :ref="`img${index}`"
                        style="width:100%;height:200px;background-size: cover;" 
                        :style="{'background-image':`url(${item.spsltlj+'/'+item.spslt}) `}">
                    </div>
                    <div  style="display:none;overflow:hidden"   :ref="`video${index}`">
                    </div>
                 </div>
            <div class="title">
                {{item.spmc}}
            </div>
         </div>
     </div>
 </div>
</template>
 
<script>
import Player from 'xgplayer'
import { loadVideoList } from "@/api/video"
export default {
 name: 'Video',
  components: {
    TitleField: Title
  },
 data () {
    return {
        // 视频的url由 splj+spbh组成,缩略图poster由spsltlj+spslt组成
        videoList:[
            {
                splj:'', 
                spbh:'',   
                spsltlj:'',
                spslt:''
            }
        ],
        dom:[],
    }
 },
 created() {
     this.setBaseList()
 },
 mounted() {
 },
 methods: {
   async setBaseList(){
        const res =await loadVideoList(this.form)
        this.videoList=res.data.records
        setTimeout(() => {
            if(this.videoList.length){
                     this.videoList.forEach((item,index)=>{
                        this.init(item,index)
                },1000)
            }else{
               this.dom.length=0
            }
       })
    },

    init (data,index) {
            this.dom[index]= new Player({
            el: this.$refs['video'+index][0],
            url: data.splj+'/'+data.spbh,
            videoInit: true,
            poster:data.spsltlj+'/'+data.spslt,  //封面图
            // cssFullscreen: true,
            lang: 'zh-cn',
            controls: false,
            playbackRate: [0.5, 0.75, 1, 1.5, 2],
            whitelist: [
            ''
            ],
            ignores: ['play'],
            fluid: false,
            // download: true,
            width: '100%',
            height: '200px'
        })
    },
    startPlay(data,index){
        this.$refs['img'+index][0].style.display="none"
        this.$refs['video'+index][0].style.display="block"
        this.$nextTick(()=>{
            this.dom[index].play()
        })
    },

    move(data,index){
        this.$refs['img'+index][0].style.display="block"
        setTimeout(() => {
            this.dom[index].pause()    
        }, 0);
        this.$refs['video'+index][0].style.display="none"
    },

 
 }
}
</script>
 
<style scoped lang = "less">
    .card{
      width: 18%;
      margin: 0 20px 20px 0;
      float: left;
    }
     .title{
         width: 100%;
         color: #000;
         height:40px;
         line-height: 40px;
         background-color: #ffffff;
         font-weight: 600;
         padding-left: 10px;
     }
</style>

🎯两个小坑

🫀 数据还没加载完就初始化实例的问题

这边使用定时器延时执行,如果直接循环,西瓜播放器播放时会报错,大体上就是实例没初始化完成。同理,播放的事件中也要等dom加载完成后调用play方法播放。

   async setBaseList(){
        const res =await loadVideoList(this.form)
        this.videoList=res.data.records
        setTimeout(() => {
            if(this.videoList.length){
                 this.videoList.forEach((item,index)=>{
                      this.init(item,index)   //初始化视频实例
                 },1000)
            }else{
                 this.dom.length=0
            }
       })
    },

🫀 mouseenter和mouseleave

使用v-for循环的时候,mouseenter和mouseleave要加在父元素身上。

 <div  class="card"  v-for="(item,index) in videoList" :key="index"   >
     <div style="width:100%;height:200px" 
        @mouseenter="startPlay(item,index)"
        @mouseleave="move(item,index)">
        <div                     
            :ref="`img${index}`"
            style="width:100%;height:200px;background-size: cover;" 
            :style="{'background-image':`url(${item.spsltlj+'/'+item.spslt}) `}">
        </div>
        <div  style="display:none;overflow:hidden"   :ref="`video${index}`">
        </div>
   </div>
    <div class="title">
        {{item.spmc}}
    </div>
</div>

🎯总结

以上是西瓜视频一个简单的demo使用介绍,更多强大的功能可以去官网体验,比如弹幕,画中画一些简单的配置。除此之外,这款开源插件不仅可以播放视频,还可以进行直播,不止可以用在PC端,也可以用在移动端。

🎯往期文章

🎉用Echarts写一个低仿甘特图(具体到秒)

手写一个精确到秒的低仿甘特图

Teleport,Vue3.0新特性里的"任意门

移动端Picker组件滚动穿透问题踩坑

Ant Design of Vue没有表格合计行api,换种思路