微信小程序video控件的使用

微信小程序video控件的使用

一、简介

video控件是微信小程序提供的系统组件之一,用于实现播放视频的功能。

二、属性

| 属性名 | 类型 | 默认值 | 说明 | 最低版本 |

|——–|——–|——–|——–|——–|

| src | String| | 要播放视频的资源地址 | |

| initial-time| String | | 指定视频初始播放位置| 1.6.0 |

| duration |Number|| 指定视频时长 | 1.1.0 |

| controls |Boolean |true| 是否显示默认播放控件(播放/暂停按钮、播放进度、时间)| |

| danmu-list |Object Array||弹幕列表 | |

| danmu-btn |Boolean|false | 是否显示弹幕按钮,只在初始化时有效,不能动态变更| |

| enable-danmu |Boolean|false| 是否展示弹幕,只在初始化时有效,不能动态变更 | |

|autoplay|Boolean|false|是否自动播放| |

|loop|Boolean|false|是否循环播放| 1.4.0 |

|muted|Boolean|false|是否静音播放| 1.4.0 |

|page-gesture|Boolean|false|在非全屏模式下,是否开启亮度与音量调节手势|1.6.0 |

|direction|Number||设置全屏时视频的方向,不指定则根据宽高比自动判断。有效值为 0(正常竖向), 90(屏幕逆时针90度), -90(屏幕顺时针90度)|1.7.0|

|bindplay|EventHandle||当开始/继续播放时触发play事件| |

|bindpause|EventHandle||当暂停播放时触发 pause 事件| |

|bindended|EventHandle||当播放到末尾时触发 ended 事件| |

|bindtimeupdate|EventHandle||播放进度变化时触发,event.detail = {currentTime, duration} 。触发频率 250ms 一次| |

|bindfullscreenchange|EventHandle||当视频进入和退出全屏是触发,event.detail = {fullScreen, direction},direction取为 vertical 或 horizontal| |

|objectFit|String|contain|当视频大小与 video 容器大小不一致时,视频的表现形式。contain:包含,fill:填充,cover:覆盖| 1.4.0|

|poster|String||视频封面的图片网络资源地址,如果 controls 属性值为 false 则设置 poster 无效| |

||||||

video 组件 默认宽度300px、高度225px,可通过wxss设置宽高。

三、相关实现api

1、wx.createVideoContext

创建并返回 video 上下文 videoContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 video 组件

2、videoContext对象

videoContext 通过 videoId 跟一个 video 组件绑定,通过它可以操作一个 video 组件。

videoContext 对象的方法列表:

| 方法 | 参数 | 说明 | 最低版本 |

|——–|——–|——–|——–|

|play | 无| 播放 | |

|pause| 无| 暂停 | |

|seek | position| 跳转到指定位置,单位 s| |

|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||

|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||

|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||

|playbackRate|rate|设置倍速播放,支持的倍率有 0.5/0.8/1.0/1.25/1.5|1.4.0|

|requestFullScreen|无|进入全屏,可传入{direction}参数(1.7.0起支持),详见video组件文档|1.4.0|

|exitFullScreen|无|退出全屏|1.4.0|

四、代码实现

在四川建设厅的代码实现中,我们未涉及弹幕功能的相关使用,所以以下代码不涉及弹幕的代码,如果想自己尝试使用,可以在官网查看其相关代码

实现效果,如下图

小程序视频播放UI效果图

实现原理:

在四川建设厅中,我们将视频播放控件进行了组件化的封装,将其放入一个名为courseVideoPlayer的组件中,组件的相关知识,可以查看佳斌写的自定义组件的实现,加以学习。

核心代码:

courseVideoPlayer.wxml


<view>

  <!--poster="{{coverImageUrl}}" -->

  <video id="myVideo" class="myVideo" src="{{playUrl}}" autoplay='false'  controls='true' bindtimeupdate='timeUpdate' bindended='endAction'>

    <!-- <cover-view bindtap='startFirstPlayAction' class='cover-view' wx:if="{{isShowCoverView}}"></cover-view>  -->

    <cover-view bindtap='_startFirstPlayAction' class='cover-view' wx:if="{{isShowCoverView}}">

      <cover-image class='cover-view' src="{{coverImageUrl}}" mode="aspectFill"/>

      <cover-image style='position:absolute; top:50%; left:50%; width:132rpx; height:132rpx; margin:-66rpx 0 0 -66rpx; z-index:10000' src="/image/video-play.png"/>

    </cover-view>

  </video>

</view>


这部分代码主要是视频界面部分,除了使用到video控件之外,我们还用到了cover-view以及cover-image组件,这两个组件的使用,在此,我做一下简单的介绍:

(1)cover-view:覆盖在原生组件之上的文本视图,可覆盖的原生组件包括map、video、canvas、camera,只支持嵌套cover-view、cover-image。

(2)cover-image:覆盖在原生组件之上的图片视图,可覆盖的原生组件同cover-view,支持嵌套在cover-view里。

属性:src String 图标路径,支持临时路径、网络地址(1.6.0起支持)。暂不支持base64格式。

按照功能来说,cover-view和cover-image实质上与普通的基础控件view与image无异,只是这两个控件特殊在,他可以覆盖在map、video、canvas、camera控件中,也正是因为这个特殊性,导致了他们在试用时也存在这一些差异,试用这两个控件的过程中,我们需要考虑以下几个注意点:

* Bug & Tips *

tip: 基础库 1.6.0 起支持css transition动画,transition-property只支持transform (translateX, translateY)与opacity。

tip: 基础库 1.6.0 起支持css opacity。

tip: 只可嵌套在原生组件map、video、canvas、camera内,避免嵌套在其他组件内。

tip: 事件模型遵循冒泡模型,但不会冒泡到原生组件。

tip: 文本建议都套上cover-view标签,避免排版错误。

tip: 只支持基本的定位、布局、文本样式。不支持设置单边的border、background-image、shadow、overflow等。

tip: 建议子节点不要溢出父节点

courseVideoPlayer.js


let studyPlayerManager = require('../../../../utils/studyManager/studyPlayerManager.js')

let currentTime = 0

let videoCtx = null

let app = getApp()

Component({

  /**

   * 组件的属性列表

   */

  properties: {

    playUrl:{

      type:String,

      value:'',

      observer: function (newVal, oldVal) {

        if (newVal.length){

          videoCtx.play()

        }

      }

    },

    totalSecondsTime:{

      type:Number,

      value:10

    },

    playInfo:{

      type: Object,

      value: {},

      observer: function (newVal, oldVal) {

      }

    },

    coverImageUrl:{

      type: String,

      value: '../../../image/course-img.jpg',

      observer: function (newVal, oldVal) {

      }

    },

    isShowCoverView:{

      type:Boolean,

      value:true,

      observer: function (newVal, oldVal) {

      }

    },

    // 初始播放时间

    initialTime : {

      type:Number,

      value:0

    }

  },



  /**

   * 组件的初始数据

   */

  data: {

    lastTime: 0,

    zindex: Math.max,

    currentTime: 0,

    isTest:false

  },

  attached: function () {

    wx.setStorageSync('lastTime', '0');

    wx.setStorageSync('maxTime', '0');

    videoCtx = wx.createVideoContext('myVideo', this)

    // 初始化toast

    new app.WeToast(this)

    studyPlayerManager.initStudyPlayerManager(this)

  },

  moved: function () {

  },

  detached: function () {

    this.studyPlayerManager.deallocStudyPlayerManager()

  },

  /**

   * 组件的方法列表

   */

  methods: {

    play() {

      videoCtx.play()

    },

    pause() {

      videoCtx.pause()

    },

    timeUpdate(e) {

      this.triggerEvent("videoTimeUpdate", e.detail.currentTime)

      var maxTime = parseInt(wx.getStorageSync('maxTime'));

      console.log('maxTime:' + maxTime);

      var lastTime = parseInt(wx.getStorageSync('lastTime'));

      console.log('lastTime:' + lastTime);

      currentTime = e.detail.currentTime;

      console.log('currentTime:' + currentTime)

      if (currentTime != 0 && ((currentTime - lastTime) < 3)) {

        wx.setStorageSync('lastTime', currentTime);

      }

      if (currentTime != 0 && currentTime > maxTime && (((currentTime - lastTime) > 0) && ((currentTime - lastTime) < 3))) {

        wx.setStorageSync('maxTime', currentTime);

        console.log('设置最大时间!')

      }

      if (!this.data.isTest && currentTime > maxTime) {

        if ((currentTime - lastTime) > 3) {

          //跳转到上次的进度

          videoCtx.seek(maxTime);

          wx.setStorageSync('lastTime', maxTime);

          this.wetoast.toast({

            title: '不能进行跳转!请认真学习'

          })

        }

      }

    },

    endAction(e) {

      let maxTime = parseInt(wx.getStorageSync('maxTime'));



      if (!this.data.isTest && ((this.properties.totalSecondsTime - maxTime) > 3)) {

        this.wetoast.toast({

          title: '不能进行跳转!请认真学习'

        })

        videoCtx.seek(maxTime)

        videoCtx.play()

      }else{

        this.triggerEvent("videoPlayEndEvent")

        this._playEndAction()

      }

    },

    fullScreenChangeAction(e) {

      console.log(e)

    },

    changeScreenTap() {

      this.videoCtx.requestFullScreen({ direction: 90 })

    },

    // 跳转到某个点

    seekToPoint(time){

      console.log('跳转到时间:'+time)

      videoCtx.seek(time)

    }

  }

})

代码中,主要实现了对video控件的进度条的拖拽进行了控制,如果在用户将进度条拖拽到还未观看过的视频位置,那么视频将会跳回到用户观看过的最大位置,并提示用户不能进装操作。

由于系统未提供video进度条拖拽的事件监听接口,我们只能“绕个弯”实现该功能。

实现的原理就是通过监听video控件开放的bindtimeupdate播放过程中的进度监听事件,我们通过监听进度条当前的进度与上一次回调的进度进行比较,如果两者之差大于3,便视为用户进行了拖拽操作,具体的代码,查看上述的timeUpdate(e)与endAction(e)事件中的相关代码。

起初,原本想自定义控制器来实现监听视频进度条拖拽的相关功能,但通过实践,我们发现,在video上的cover-view中无法嵌套系统提供的slider组件,同时在video控件上,无法进行自定义拖拽事件的监听(开发工具上可以监听,真机上无法进行监听,具体的原因还需考察),所以目前只能通过该方法实现控制拖拽进度条的操作。

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值