zoukankan      html  css  js  c++  java
  • 手把手从零开始---封装一个vue视频播放器组件

    现在,在网页上播放视频已经越来越流行,但是网上的资料鱼龙混杂,很难找到自己想要的,今天小编就自己的亲身开发体验,手把手从零开始---封装一个vue视频播放器组件。

    作为一个老道的前端搬砖师,怎么可能会一心闭门造车呢?还是先去网上找找轮子吧

    经过在网上不断的查阅之后,我最终选择了video.js这个轮子,作为我的播放器。好,现在轮子找好了,乍一看,天,好像有点丑。不着急,我再来把它美化美化(二次封装)。

    引入video.js

    安装

    //安装video.js插件
    npm install video.js -S 
    
    //如果需要播放rtmp直播流,需安装一下插件
    npm install videojs-flash -S
    
    

    在组件中简单使用插件

    template
    <template>
      <div>
        <div data-vjs-player>
          <video ref="videoNode" class="video-js vjs-default-skin">抱歉,您的浏览器不支持</video>
        </div>
    </template>
    
    script
    import videojs from "video.js";
    //播放器中文,不能使用.js文件
    import videozhCN from "video.js/dist/lang/zh-CN.json";
    //样式文件注意要加上
    import "video.js/dist/video-js.css"; 
    //如果要播放RTMP要使用flash 需要先npm i videojs-flash
    import "videojs-flash";
    export default {
        data() {
            return {
              player: null,
            };
        },
        //初始化播放器
        mounted(){
            let options = {
                autoplay: true, //自动播放
                language: "zh-CN",
                controls: this.controls, //控制条
                preload: "auto", //自动加载
                errorDisplay: true, //错误展示
                // fluid: true, //跟随外层容器变化大小,跟随的是外层宽度
                 "500px",
                height: "500px",
                // controlBar: false,  // 设为false不渲染控制条DOM元素,只设置controls为false虽然不展示,但是存在
                // textTrackDisplay: false,  // 不渲染字幕相关DOM
                userActions: {
                  hotkeys: true //是否支持热键
                },
                notSupportedMessage: "此视频暂无法播放,请稍后再试",
                techOrder: ["h5","flash"],//定义Video.js技术首选的顺序
                sources: [
                  {
                    src: '视频或者直播地址',
                    type: 'video/mp4',
                    //type: 'rtmp/flv',
                  }
                ]
            };
            this.player = videojs(
                this.$refs.videoNode,
                options,
                function onPlayerReady() {
                  videojs.log(`Your player is ready!`);
                }
            );
            videojs.addLanguage("zh-CN", videozhCN);
        },
        beforeDestroy() {
            if (this.player) {
              this.player.dispose();
            }
        }
    }
    

    这样一个简单的视频播放功能就实现了。这里小编也给大家整理了一些video.js常用的配置项:

    常用选项
    • autoplay:true/false 播放器准备好之后,是否自动播放 【默认false】
    • controls:true/false 是否拥有控制条 【默认true】,如果设为false ,那么只能通过api进行控制了。也就是说界面上不会出现任何控制按钮
    • height: 视频容器的高度,字符串或数字 单位像素 比如: height:300 or height:‘300px‘
    • 视频容器的宽度, 字符串或数字 单位像素
    • loop : true/false 视频播放结束后,是否循环播放
    • muted : true/false 是否静音
    • poster: 播放前显示的视频画面,播放开始之后自动移除。通常传入一个URL
    • preload:预加载 ‘auto‘ 自动、、’metadata‘ 元数据信息,比如视频长度,尺寸等、‘none‘ 不预加载任何数据,直到用户开始播放才开始下载
    Video.js特定的选项

    除非另有说明,否则默认情况下每个选项undefined

    aspectRatio

    类型: string

    将播放器置于流体模式,并在计算播放器的动态大小时使用该值。该值应表示比率 - 由冒号(例如"16:9"或"4:3")分隔的两个数字。

    autoSetup

    类型: boolean

    阻止播放器为具有data-setup属性的媒体元素运行autoSetup 。

    注意:必须在与videojs.options.autoSetup = falsevideojs源加载生效的同一时刻全局设置。

    fluid

    类型: boolean

    设置为true,Video.js播放器将具有流畅的大小。换句话说,它将扩展以适应其容器。

    此外,如果元素具有"vjs-fluid",则此选项自动设置为true。

    inactivityTimeout

    类型: number

    Video.js表示用户通过"vjs-user-active"和"vjs-user-inactive"类以及"useractive"事件与玩家进行交互。

    在inactivityTimeout决定了不活动的许多毫秒声明用户闲置之前是必需的。值为0表示没有inactivityTimeout,用户永远不会被视为非活动状态。

    language

    键入:string,默认值:浏览器默认值或’en’

    与播放器中的一种可用语言匹配的语言代码。这为播放器设置了初始语言,但始终可以更改。

    在Video.js中了解有关语言的更多信息。

    languages

    类型: Object

    自定义播放器中可用的语言。此对象的键将是语言代码,值将是具有英语键和翻译值的对象。

    在Video.js中了解有关语言的更多信息

    注意:通常,不需要此选项,最好将自定义语言传递给videojs.addLanguage()所有玩家!

    nativeControlsForTouch

    类型: boolean

    明确设置关联技术选项的默认值。

    notSupportedMessage

    类型: string

    允许覆盖Video.js无法播放媒体源时显示的默认消息。

    playbackRates

    类型: Array

    严格大于0的数字数组,其中1表示常速(100%),0.5表示半速(50%),2表示双速(200%)等。如果指定,Video.js显示控件(类vjs-playback-rate)允许用户从选择数组中选择播放速度。选项以从下到上的指定顺序显示。

    例如:

    videojs('my-player', {
      playbackRates: [0.5, 1, 1.5, 2]
    });
    
    
    sources

    类型: Array

    一组对象,它们反映了本机元素具有一系列子元素的能力。这应该是带有src和type属性的对象数组。例如:

    videojs('my-player', {
      sources: [{
        src: '//path/to/video.mp4',
        type: 'video/mp4'
      }, {
        src: '//path/to/video.webm',
        type: 'video/webm'
      }]
    });
    
    

    使用元素将具有相同的效果:

    <video ...>
      <source src="//path/to/video.mp4" type="video/mp4">
      <source src="//path/to/video.webm" type="video/webm">
    </video>
    
    
    techCanOverridePoster

    类型: boolean

    使技术人员有可能覆盖玩家的海报并融入玩家的海报生命周期。当使用多个技术时,这可能很有用,每个技术都必须在播放新源时设置自己的海报。

    techOrder

    输入:Array,默认值:[‘html5’]

    定义Video.js技术首选的顺序。默认情况下,这意味着Html5首选技术。其他注册的技术将在此技术之后按其注册顺序添加。

    nativeVideoTracks

    类型: boolean

    可以设置为false禁用本机视频轨道支持。最常用于videojs-contrib-hls。

    nativeControlsForTouch

    类型: boolean

    只有技术支持Html5,此选项可以设置true为强制触摸设备的本机控件。

    美化video.js轮子

    播放按钮居中

    按照上面简单的使用方式使用之后,我们会发现视频播放待播放页面是这样的:

    播放按钮默认在左上角,是作者认为会遮挡内容考虑的,不过这个是可以根据参数修改的,我们只需要给video标签加一个class(vjs-big-play-centered)就可以了。

    <video ref="videoNode" class="video-js vjs-default-skin vjs-big-play-centered"></video>
    

    加完之后效果如下:

    加载中状态美化

    video.js在播放视频的时候,有一个默认的加载中,这里我根据自己的想法提供了一种自定义加载中页面的思路,如有错,请大佬指正。

    主要思路:

    在播放器的上面悬浮覆盖一层div,用于显示自定义加载中的内容,再通过一个变量值控制这个div是否加载,通过监听视频的一个加载状态更新变量的值,以达到自定义加载中页面的目的。

    主要代码:

    template
    注:不是完整代码,只是关键代码

    <div :style="{'100%',position:'relative',height:height}">
        <div data-vjs-player style="100%">
          <video ref="videoNode" class="video-js vjs-default-skin vjs-big-play-centered">抱歉,您的浏览器不支持</video>
        </div>
        <div
          v-if="loading"
          :style="{'100%',height:height,position:'absolute',left:'0px',top:'0px'}"
        >
          <img
            :style="{'100%',height:height}"
            src="https://img.zcool.cn/community/0113b1576a43e90000018c1b87042d.gif"
          />
        </div>
    </div>
    

    script
    注:不是完整代码,只是关键代码

    data() {
        return {
          loading: false
        };
     },
     let options = {
        autoplay: false, //自动播放
        .....省略代码
     };
    this.player = videojs(
        this.$refs.videoNode,
        options,
        function onPlayerReady() {
          videojs.log(`Your player${self.index} is ready!`);
          _this.loading = true;
          _this.player.play();
          _this.player.one("playing", function() {
            // 监听播放
            // console.log("播放器开始播放");
            _this.loading = false;
          });
        
        }
    );
    

    效果如下:

    当然,内容你也可以自定义。

    视频打点

    平时生活中,我们在看视频的时候,经常会看到,有些视频的进度条上面有一些小点,然后鼠标放上去会出现一些文字提示,那么我们的web播放器上面能不能也添加这个功能呢?当然是可以的!

    首先还是去找了一波轮子,最后找到了videojs-markers这个轮子来实现该功能。

    安装videojs-markers
    npm i videojs-markers -S
    
    引入videojs-markers
    import "videojs-markers";
    //引入样式
    import "videojs-markers/dist/videojs.markers.css";
    
    使用videojs-markers
    this.player.markers({
      markerStyle: {
        // 标记点样式
         "0.7em",
        height: "0.7em",
        bottom: "-0.20em",
        "border-radius": "50%",
        "background-color": "orange",
        position: "absolute"
      },
      //鼠标移入标记点的提示
      markerTip: {
        display: true,//是否显示
        /*
          用于动态构建标记提示文本的回调函数。
          只需返回一个字符串,参数标记是传递给插件的标记对象
         */
        text: function(marker) {
          return marker.text;
        }
      },
      markers: [
            {
              time: 20,
              text:'点位一'
            },
            {
              time: 40,
              text:'点位二'
            },
            {
              time: 130,
              text:'点位三'
            },
            {
              time: 200,
              text:'点位四'
            }
        ],
    });
    

    效果如下:

    封装组件

    播放器基本功能实现了,那么最后一步就是封装组件了。封装的思路很简单,就是将一些变化的属性通过props的方式从父组件中传入。

    常用需要封装的属性

    注:此处只列举了部分,可以示实际情况添加或者删除

    • src : 视频或者直播的地址
    • height :播放器的高度
    • controls :控制条是否需要显示
    • markers :视频打点的数据源
    • type :播放视频的类型

    根据这些属性,我们来改造一下我们的组件

    template

    <template>
      <div :style="{'100%',position:'relative',height:height}">
        <div data-vjs-player style="100%">
          <video ref="videoNode" class="video-js vjs-default-skin vjs-big-play-centered">抱歉,您的浏览器不支持</video>
        </div>
        <div
          v-if="loading"
          :style="{'100%',height:height,position:'absolute',left:'0px',top:'0px'}"
        >
          <img
            :style="{'100%',height:height}"
            src="https://img.zcool.cn/community/0113b1576a43e90000018c1b87042d.gif"
          />
        </div>
      </div>
    </template>
    

    script

    data() {
        return {
          player: null,
          loading: false
        };
    },
    
    
    let options = {
            // autoplay: true, //自动播放
            language: "zh-CN",
            controls: this.controls, //控制条
            preload: "auto", //自动加载
            errorDisplay: true, //错误展示
            // fluid: true, //跟随外层容器变化大小,跟随的是外层宽度
             "100%",
            height: this.height,
            // controlBar: false,  // 设为false不渲染控制条DOM元素,只设置controls为false虽然不展示,但还是存在
            // textTrackDisplay: false,  // 不渲染字幕相关DOM
            userActions: {
              hotkeys: true //是否支持热键
            },
            notSupportedMessage: "此视频暂无法播放,请稍后再试",
            techOrder: ["flash"],
            sources: [
              {
                src: this.src,
                type: this.type
              }
            ]
          };
          let _this = this;
          this.player = videojs(
            this.$refs.videoNode,
            options,
            function onPlayerReady() {
              videojs.log(`Your player${self.index} is ready!`);
              _this.loading = true;
              _this.player.play();
              _this.player.one("playing", function() {
                // 监听播放
                // console.log("播放器开始播放");
                _this.loading = false;
              });
            }
          );
          videojs.addLanguage("zh-CN", videozhCN);
          if (this.markers) {
            this.player.markers({
              markerStyle: {
                // 标记样式
                 "0.7em",
                height: "0.7em",
                bottom: "-0.20em",
                "border-radius": "50%",
                "background-color": "orange",
                position: "absolute"
              },
              markerTip: {
                display: true,
                /*
                  用于动态构建标记提示文本的回调函数。
                  只需返回一个字符串,参数标记是传递给插件的标记对象
                 */
                text: function(marker) {
                  return marker.text;
                }
              },
              markers: this.markers,
            });
          }
    

    动态切换视频封装

    在视频播放的时候,我们经常会有视频切换之类的需求,那么这个怎么封装呢?很简单,只需要在组件中监听src的变化,如果src发生了变化,那么就重新加载视频,播放视频,代码如下:

    watch: {
        src() {
          if (this.player) {
            let _this = this;
            this.loading = true;//重新显示加载状态
            let myPlayer = this.player;
            myPlayer.off("timeupdate");//清空时间
            myPlayer.reset();//重置播放器
            myPlayer.pause();//暂停播放
            myPlayer.src([//重新设置播放源
              {
                src: this.src,
                type: "rtmp/flv"
              }
            ]);
            myPlayer.load(this.src);//重新加载视频
            myPlayer.play();//播放视频
            myPlayer.one("playing", function() {
              // 加载完成,开始播放
              // console.log("播放器开始播放");
              _this.loading = false;//隐藏加载状态
            });
          }
        }
    },
    

    这样一个简单的视频播放器就封装好了。

    使用示例

    组件封装完成,免不了使用一下,代码如下:

    <template>
      <basic-container>
        <el-row class="video-test">
          <el-col :span="16" class="video-test-left">
            <videoPlayer :controls="true" height="600px" :src="url" type="video/mp4" :markers="markers"/>
          </el-col>
        </el-row>
      </basic-container>
    </template>
    <script>
    import videoPlayer from "@/components/videoPlayer/videoPlayer";
    export default {
      components: { videoPlayer },
      data() {
        return {
          url: "http://127.0.0.1/test.mp4",
          markers: [
            {
              time: 20,
              text:'点位一'
            },
            {
              time: 40,
              text:'点位二点位二点位二点位二点位二点位二点位二点位二'
            },
            {
              time: 130,
              text:'点位三点位三点位三点位三点位三点位三'
            },
            {
              time: 200,
              text:'点位四点位四点位四点位四点位四点位四'
            }
          ]
        };
      }
    };
    </script>
    <style lang="scss">
    </style> 
    

    参考:

    videojs中文文档详解 https://blog.csdn.net/a0405221/article/details/80923090

  • 相关阅读:
    -bash: fork: Cannot allocate memory 问题的处理
    Docker top 命令
    docker常见问题修复方法
    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
    What's the difference between encoding and charset?
    hexcode of é î Latin-1 Supplement
    炉石Advanced rulebook
    炉石bug反馈
    Sidecar pattern
    SQL JOIN
  • 原文地址:https://www.cnblogs.com/monkeySoft/p/13292943.html
Copyright © 2011-2022 走看看