video.js 相關實現文檔

前言

jq事件:https://www.jb51.cc/js/153165.html

示例代碼

<!DOCTYPE html>
<html>

<head>
  <script src="./video.js"></script>
  <link href="./video-js.css" rel="stylesheet" />
  <script src="./videojs-contrib-hls.min.js"></script>
  <script src="./jquery-3.5.0.min.js"></script>
</head>

<body>
  <video id="myVideo" class="video-js vjs-default-skin" controls preload="auto" width="1000" height="500"
    data-setup='{}'>
  </video>
  <script>
        /**
        * 邏輯:
        * 1.進入頁面,頁面獲取到請求參數
        * 2.頁面通過ajax進行請求,獲取到文件信息
        * 3.開始播放時,獲取下一集的文件信息
        * 4.播放結束時,更新視頻地址,繼續播放下一集
        *
        */
        // 第一步
        var num = 0
        var id = GetPar('id')
        // 第二步
        var url = 'http://localhost:8001/file/playOnline/' + id
        $.get(url, function(res) {
            if (res.code == 200) {
                localStorage.setItem("currentId", id)
                localStorage.setItem("currentUrl", res.data)
                var player = videojs('myVideo',{
                   
                    // 播放速度
        playbackRates: [0.7, 1.0, 1.5, 2.0],
        // 如果true,瀏覽器準備好時開始回放。
        autoplay: true,
        //  默認情況下將會消除任何音頻。
        muted: false,
        //  導致視頻一結束就重新開始。
        loop: false,
        //  建議瀏覽器在<video>加載元素後是否應該開始下載視頻數據。auto瀏覽器選擇最佳行爲,立即開始加載視頻(如果瀏覽器支持)
        preload: 'auto',
        sources: [
          {
            // 這裏的種類支持很多種:基本視頻格式、直播、流媒體等,具體可以參看git網址項目
            type: 'application/x-mpegURL',
            src: ''
          }
        ],
                });

                videojs("myVideo").ready(function(){
                player.ready(function() {
                    this.src({
                        src: localStorage.getItem('currentUrl'),
                        type: 'application/x-mpegURL',
                    });
                    this.on("play", function() {
                        console.log("我走了Play")
                        num++
                        if (num == 1) {
                            // 第三步
                            getNextEpisode(localStorage.getItem('currentId'))
                        }
                    });
                    this.on("ended", function() {
                        debugger
                        // 第四步
                        num = 0
                        var nextUrl = localStorage.getItem("nextUrl")
                        if(nextUrl != null && typeof(nextUrl) != 'undefined' && nextUrl != ''){
                            this.src({
                                src: nextUrl,
                                type: 'application/x-mpegURL',
                            });
                        }

                    });
                });
            });
            }
        })

        // 獲取下一集信息
        function getNextEpisode(id) {
            var url = "http://localhost:8001/file/getNextEpisode";
            $.ajax({
                url: url,
                type: "POST",
                data: JSON.stringify({
                    id: id
                }),
                contentType: "application/json",
                dataType: "json",
                success: function(res) {
                    debugger
                    if(res.code == 200){
                        if(res.data == null){
localStorage.setItem('nextUrl', '')
                        }else{
localStorage.setItem('nextUrl', res.data.m3u8Url)
                    localStorage.setItem('nextId', res.data.id)
                        }
                    }
                    
                }

            });
        }

        // 獲取瀏覽器請求參數
        function GetPar(name) {
            var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
            var r = window.location.search.substr(1).match(reg)
            if (r != null) return decodeURIComponent(r[2])
            return null
        }
    </script>

</html>

vue中使用video.js。代碼僅做個人備份

功能:點擊進行播放,當前播放完畢自動跳到下一集。全部播放完畢暫停。 PC手機都可以

<template>
  <el-card class="box-card">
    <div class="block-search">
      <el-input
        class="width-190"
        v-model="queryParam.keyword"
        placeholder="請輸入文件名稱"
        size="medium"
        clearable
      ></el-input>
      <el-select
        v-model="queryParam.fileType"
        placeholder="全部類型"
        class="width-190"
        size="medium"
        clearable
      >
        <el-option
          v-for="item in optionsByFileType"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        ></el-option>
      </el-select>
      <el-button type="primary" plain size="medium" icon="el-icon-search" @click="_search">搜索</el-button>
    </div>
    <el-table :data="tableData" border style="width: 100%" size="mini">
      <el-table-column fixed prop="id" label="文件id" width="60"></el-table-column>
      <el-table-column prop="oldName" label="原文件名稱" width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="newName" label="新文件名稱" width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="fileSize" label="文件大小" width="120" show-overflow-tooltip>
        <template slot-scope="scope">{{scope.row.fileSize + 'kb'}}</template>
      </el-table-column>
      <el-table-column prop="fileType" label="文件類型" width="120" show-overflow-tooltip>
        <template slot-scope="scope">{{_getFileTypeStr(scope.row)}}</template>
      </el-table-column>
      <el-table-column prop="suffixName" label="擴展名" width="120" v-if="false"></el-table-column>
      <el-table-column prop label="二維碼" width="120">
        <template slot-scope="scope">
          <el-popover placement="bottom" title="手機掃碼在線觀看" width="200" trigger="hover" content>
            <canvas :id="'QRCode_'+scope.row.id"></canvas>
            <i class="fa fa-qrcode" slot="reference" @mouseenter="generatorQrcode(scope.row)"></i>
          </el-popover>
        </template>
      </el-table-column>
      <el-table-column
        prop="downloadPath"
        label="文件路徑"
        width="300"
        show-overflow-tooltip
        v-if="true"
      ></el-table-column>
      <el-table-column prop="lastEpisodeName" label="上一集名稱" width="120" show-overflow-tooltip>
        <template slot-scope="scope">{{scope.row.lastEpisodeName | columnDefauleValue}}</template>
      </el-table-column>
      <el-table-column prop="nextEpisodeName" label="下一集名稱" width="120" show-overflow-tooltip>
        <template slot-scope="scope">{{scope.row.nextEpisodeName | columnDefauleValue}}</template>
      </el-table-column>
      <el-table-column prop="createDate" label="上傳時間" width="170">
        <template slot-scope="scope">{{scope.row.createDate | timestampFormatTime}}</template>
      </el-table-column>
      <el-table-column fixed="right" label="操作" width="400">
        <template slot-scope="scope">
          <el-button size="mini" type="default" @click="_download(scope.row)">
            <i class="fa fa-cloud-download"></i>下載
          </el-button>
          <el-button
            size="mini"
            type="default"
            @click="_toFileConfig(scope.row)"
            v-if="parseInt(scope.row.fileType) === 4"
          >
            <i class="fa fa-retweet"></i>配置
          </el-button>
          <el-button
            size="mini"
            type="primary"
            disabled
            v-if="parseInt(scope.row.fileType) === 4 && scope.row.transcodingStatus=== 2"
          >
            <i class="fa fa-spinner fa-pulse"></i>轉碼中
          </el-button>
          <el-button
            size="mini"
            type="primary"
            @click="_playOnline(scope.row)"
            v-else-if="parseInt(scope.row.fileType) === 4 &&(scope.row.transcodingStatus=== 1|| scope.row.transcodingStatus=== 3)"
          >
            <i class="fa fa-video-camera"></i>在線播放
          </el-button>
          <el-button size="mini" type="danger" @click="_delete(scope.row)">
            <i class="fa fa-trash-o"></i>刪除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 文件配置 -->
    <el-dialog
      :title="$jsConstants.title"
      :visible.sync="dialogVisibleByConfig"
      width="30%"
      :before-close="handleCloseByConfig"
    >
      <el-form
        ref="fileConfig"
        :model="fileConfig"
        label-width="100px"
        size="small"
        v-if="currentFile"
      >
        <el-form-item label="原文件名稱" class>{{currentFile.oldName}}</el-form-item>
        <el-form-item label="新文件名稱" class>{{currentFile.newName}}</el-form-item>
        <el-form-item label="上一集">
          <el-input v-model="fileConfig.lastEpisode" placeholder="請輸入文件id"></el-input>
        </el-form-item>
        <el-form-item label="下一集">
          <el-input v-model="fileConfig.nextEpisode" placeholder="請輸入文件id"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleCloseByConfig">取 消</el-button>
        <el-button type="primary" @click="_updateFileInfo">確 定</el-button>
      </span>
    </el-dialog>

    <el-dialog
      :title="$jsConstants.title"
      :visible.sync="isShow"
      width="50%"
      :before-close="handleClose"
      @open="handleOpen"
    >
      <video
        id="myVideo"
        ref="myVideoRef"
        controls
        preload="auto"
        class="video-js vjs-big-play-centered vjs-fluid vjs-16-9 vjs-big-play-centered"
        data-setup="{}"
      >
        <source :src="playVideoUrl" type="application/x-mpegURL" />
      </video>
    </el-dialog>

    <span ref="testRef"></span>
  </el-card>
</template>

<script>
import QRCode from 'qrcode'
import { mapState, mapActions } from 'vuex'
import {
  getNextEpisode,
  updateFileInfo,
  delFile,
  getFilesByTtanscoded,
  playOnline,
  queryFileInfoPageList,
  download,
  getFileTypes
} from '@/api/logic/api-file'
export default {
  data() {
    return {
      // 第一次播放標誌
      playFlagForTheFirstTime: 0,
      // 播放地址
      playVideoUrl: 'http://192.168.17.46:8001/158304068-bkmmp4/ts/bkm.m3u8',
      // 當前文件
      currentFile: {},
      // 文件配置
      fileConfig: {
        id: null,
        lastEpisode: null,
        nextEpisode: null
      },
      dialogVisibleByConfig: false,
      // 刷新數組
      transcodingArr: [],
      // 在線播放
      playOnlineUrl: null,
      // 查詢參數
      queryParam: {
        pageInfoDto: {
          pageNum: 0,
          pageSize: 10
        },
        keyword: null,
        fileType: null
      },
      // 文件類型
      optionsByFileType: [],
      // 列表數據
      tableData: []
    }
  },
  components: {
    QRCode
  },
  computed: {
    ...mapState('StoreModuleFile', ['video']),
    player() {
      return this.$refs.videoPlayer.player
    },
    isShow: function() {
      return this.$store.state.StoreModuleFile.video.isShow
    },
    getPlayOnlineUrl() {
      return this.video.url
    }
  },
  created() {
    this._getFileTypes()
    this._search()
  },
  onload() {},
  onShow() {
    debugger
    console.log(this)
  },
  mounted() {},
  methods: {
    ...mapActions('StoreModuleFile', ['setVideo']),
    // 下一集
    _getNextEpisode(currentId, currentUrl = null) {
      getNextEpisode({ id: currentId }).then(res => {
        if (res.code === this.$jsConstants.SUCCESS) {
          // 獲取video信息
          let video = JSON.parse(
            JSON.stringify(this.$store.state.StoreModuleFile.video)
          )
          // 保存第一集視頻地址
          if (video.firstId) {
            video.firstId = video.firstId
            video.firstUrl = video.firstUrl
          } else {
            video.firstId = currentId
            video.firstUrl = currentUrl
          }
          if (res.data != null) {
            // 如果沒有下一集
            video.currentId = res.data.id
            video.currentUrl = res.data.m3u8Url
            video.nextEpisodeId = null
            video.nextEpisodeUrl = null
          } else {
            video.currentId = null
            video.currentUrl = null
            video.nextEpisodeId = null
            video.nextEpisodeUrl = null
          }
          this.setVideo(video)
        }
      })
    },
    // 在線播放
    _playOnline(row) {
      this.setVideo({
        isShow: true
      })
      playOnline(row.id).then(res => {
        let that = this
        if (res.code === this.$jsConstants.SUCCESS) {
          that.setVideo({
            isShow: true,
            currentId: row.id,
            currentUrl: res.data,
            nextEpisodeId: null,
            nextEpisodeUrl: null,
            firstId: row.id,
            firstUrl: res.data
          })
          that.playVideoUrl = res.data
          // 設置視頻源
          let myVideo = document.getElementById('myVideo')
          myVideo = myVideo === null ? that.$refs.viodeRef : myVideo
          var options = {}
          var player = that.$video(myVideo, options, function() {
            player.ready(function() {
              this.src({
                src: res.data,
                type: 'application/x-mpegURL'
              })
              this.on('play', function() {
                let video = that.$store.state.StoreModuleFile.video
                if (video.isOK) {
                  myVideo.pause()
                  // 清空暫停狀態
                  let newVideo = JSON.parse(JSON.stringify(video))
                  newVideo.isOK = false
                  that.setVideo(newVideo)
                  return false
                }
                // 播放開始,取當前文件id,查詢下一集的信息,存儲到狀態管理
                // 查詢下一集;此處之所以判斷是否第一次播放,是因爲視頻暫停時,也會觸發該事件
                that.playFlagForTheFirstTime++
                if (that.playFlagForTheFirstTime === 1) {
                  that._getNextEpisode(video.currentId, video.currentUrl)
                }
              })
              this.on('ended', function() {
                let video = that.$store.state.StoreModuleFile.video
                // 當前這一集視頻播放結束,play次數更新爲獲0
                that.playFlagForTheFirstTime = 0
                // 更新播放器視頻地址爲下一集
                let currentUrl = video.currentUrl
                if (currentUrl) {
                  player.src({
                    src: video.currentUrl
                  })
                } else {
                  // 最後一集播放完畢,把視頻地址更換爲第一集地址;更新狀態管理播放文件信息;然後設置停止播放。
                  video.currentId = video.firstId
                  video.currentUrl = video.firstUrl
                  player.src({
                    src: video.firstUrl,
                    autoplay: false
                  })
                  // 添加暫停狀態,否則會循環播放
                  let newVideo = JSON.parse(JSON.stringify(video))
                  newVideo.isOK = true
                  that.setVideo(newVideo)
                }
              })
            })
          })
        }
      })
    },
    //  關閉
    handleClose() {
      // 更新單個視頻獲取下一集次數
      this.playFlagForTheFirstTime = 0
      this.setVideo({ isShow: false })
    },
    //  打開
    handleOpen() {
      // 更新單個視頻獲取下一集次數
      this.playFlagForTheFirstTime = 0
    },
    // 初始化video
    initVideo() {
      debugger
      this.setVideo({ isShow: true })
      // 初始化視頻方法
      let myVideo = document.getElementById('myVideo')
      myVideo = myVideo === null ? this.$refs.myVideoRef : myVideo
      if (myVideo) {
        this.$video(myVideo, {
          // 確定播放器是否具有用戶可以與之交互的控件。沒有控件,啓動視頻播放的唯一方法是使用autoplay屬性或通過Player API。
          controls: true,
          // 自動播放屬性,muted:靜音播放
          autoplay: 'muted',
          // 建議瀏覽器是否應在<video>加載元素後立即開始下載視頻數據。
          preload: 'auto',
          // 設置視頻播放器的顯示寬度(以像素爲單位)
          width: '800px',
          // 設置視頻播放器的顯示高度(以像素爲單位)
          height: '400px',
          hls: {
            withCredentials: true
          }
        })
      }
    },
    // 獲取二維碼地址
    generatorQrcode(row) {
      // 二維碼地址
      let val = 'http://192.168.17.46:8080/static/h5/index.html?id=' + row.id
      // 獲取頁面的canvas
      var msg = document.getElementById('QRCode_' + row.id)
      // 將獲取到的數據(val)畫到msg(canvas)上
      QRCode.toCanvas(msg, val, function(error) {
        console.log(error)
      })
    },
    // 關閉config
    handleCloseByConfig() {
      this.dialogVisibleByConfig = false
      this.currentFile = {}
      this.fileConfig = {}
    },
    // 文件配置
    _updateFileInfo() {
      updateFileInfo(this.fileConfig).then(res => {
        if (this.$jsConstants.SUCCESS === res.code) {
          this.dialogVisibleByConfig = false
          this.currentFile = {}
          this.fileConfig = {}
          this.$notify({
            title: '成功',
            message: '配置成功',
            type: 'success'
          })
          this._search()
        }
      })
    },
    _toFileConfig(row) {
      // 文件配置
      this.fileConfig.id = row.id
      this.fileConfig.lastEpisode = row.lastEpisode
      this.fileConfig.nextEpisode = row.nextEpisode
      // 當前文件
      this.currentFile = row
      this.dialogVisibleByConfig = true
    },
    // 文件下載
    _download(row) {
      download(row.id)
    },
    // 查詢
    _search() {
      queryFileInfoPageList(this.queryParam).then(res => {
        console.log('res', res)
        if (this.$jsConstants.SUCCESS === res.code) {
          this.tableData = res.data.list
          // 過濾出轉碼中的數據,然後每10秒刷新一次狀態
          this.transcodingArr = []
          this.tableData.forEach(obj => {
            if (obj.transcodingStatus === 2) {
              this.transcodingArr.push(obj.id)
            }
          })
          this._RefreshStatus(this.transcodingArr)
        }
      })
    },
    // 刷新狀態
    _RefreshStatus(ids) {
      let that = this
      if (ids === null || ids.length === 0) {
        return false
      }
      let timeId = null
      timeId = setInterval(function() {
        getFilesByTtanscoded({ fileIds: ids }).then(res => {
          if (that.$jsConstants.SUCCESS === res.code) {
            if (res.data != null && res.data.length > 0) {
              res.data.forEach(obj => {
                // 彈框顯示轉碼成功
                that.$notify({
                  title: '成功',
                  message: obj.newName + ' 轉碼成功',
                  type: 'success'
                })
                // 刪除該刷新元素
                that.transcodingArr.some((item, index) => {
                  if (item === obj.id) {
                    that.transcodingArr.splice(index, 1)
                    // 如果沒有轉碼中的數據,則關閉定時器
                    if (that.transcodingArr.length === 0) {
                      clearInterval(timeId)
                    }
                  }
                })
                // 更新列表狀態
                that.tableData.some((updateObj, updateIndex) => {
                  if ((updateObj.id = obj.id)) {
                    updateObj.transcodingStatus = 3
                  }
                })
              })
            }
          }
        })
      }, 3000)
    },
    // 刪除
    _delete(row) {
      if (row.transcodingStatus === 2) {
        this.$notify({
          title: '警告',
          message: '文件正在轉碼,請稍後操作',
          type: 'warning'
        })
        return false
      }
      this.$confirm('你確定要刪除嗎?')
        .then(_ => {
          // 二次確定
          delFile({ id: row.id }).then(res => {
            if (this.$jsConstants.SUCCESS === res.code) {
              this.$notify({
                title: '成功',
                message: '刪除成功',
                type: 'success'
              })
              this._search()
            }
          })
        })
        .catch(_ => {})
    },
    // 獲取文件類型
    _getFileTypeStr(row) {
      let str = ''
      this.optionsByFileType.forEach(element => {
        if (parseInt(element.value) === parseInt(row.fileType)) {
          str = element.label
        }
      })
      return str
    },
    // 遍歷選項
    _getFileTypes() {
      getFileTypes().then(res => {
        this.optionsByFileType = []
        res.data.forEach(element => {
          this.optionsByFileType.push({
            label: element.typeDescription,
            value: element.typeId
          })
        })
      })
    }
  }
}
</script>

<style lang="less" scoped>
</style>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章