关于使用video js插件的坑作者用的m3u8视频流一个页面展示多个视频自动播放

废话不多说

下载并引用

import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";

video js插件是跟据他来插入dom进行视频的渲染

            <video
              :id="'video' + item.channelId"
              ref="videos"
              class="video video-js vjs-big-play-centered"
            >
              <source
                :id="'video' + item.channelId"
                src=""
                type="application/x-mpegURL"
              />
            </video>
  data() {
    return {
      timeMU: null,
      videoOptions: {
        autoplay: true,
        muted: true, //默认情况下消除任何音频
        controls: true,
        poster: "",
        sources: [
          {
            src: "",
            type: "application/x-mpegURL",
          },
        ],
      },
      player: [], //存储video 实列
      vldeoArr: [],
      channelIds: [], //id  用来获取视频
      imgUrl: require("@/assets/no-photo.png"),
    };
  },

下面我把我的代码全部贴出,说一下我页面的逻辑我这个也页面是用的组件写法,获取父组件获取来的videoList视频列表,根据视频列表的channelId来进行mutiRtspAndM3u8接口请求返回过来的是视频的url地址

但是后端有问题mutiRtspAndM3u8这个接口咩有处理好,就是说我传入9个channelId按道理他应该给我9个视频的url.....但是重点来了他返回来的有一下集中可能,一,返回来data里面只有3个,还有6个没有返回来..并且data里面的3个里面不一定都有url.可能有,可能没有,如果没有的话就接着发送这个请求,直到获取到,或者就是跳转到下一页就取消定时器...

下面是我视频播放的方法

    // 视频播放
    async getMuVideo(ids) {
      let _this = this;
      await mutiRtspAndM3u8(ids, this).then((res) => {
        this.$nextTick(async () => {
          // 清除m3u8定时器
          if (this.timeMU) {
            clearInterval(this.timeMU);
            this.timeMU = null
          }
          let arr = res.data.data;
          let bool = true; //用来判断 url  是否全部有值
          let urlArr = [];
          arr.forEach((item, index) => {
            if (item.visitUrl) {
              // 拿到所有的url去和视频列表里面判断,如果视频列表里面的是离线OFFLINE就改为在线ONLINE状态
              _this.videoList.forEach((v) => {
                //  && v.status == "OFFLINE"
                if (item.channelId == v.channelId) {
                  // v.status = "ONLINE";
                  v.loading = false;
                  if(v.status != "OFFLINE"){
                  }
                  // this.getVideoList()
                  // 因为上一步有了url视频地址,虽然这次判断更改了dom的显示,但是还是无法赋值url
                }
              });
              this.$nextTick(() => {
                let videoOptions = JSON.parse(
                  JSON.stringify(this.videoOptions)
                );
                videoOptions.sources[0].src =
                  _this.GLOBAL.BASE_URL + item.visitUrl;

                let dom =
                  "<video  id=" +
                  "video" +
                  item.channelId +
                  ' class="video-js vjs-default-skin" controls style="width:100%;height:100%"></video>';
                this.$refs["videoDiv" + item.channelId][0].innerHTML = dom;
                this.$forceUpdate();
                this.player.push(
                  videojs("video" + item.channelId, videoOptions)
                );
              });
            } else {
              bool = false;
              urlArr.push(Number(item.channelId));
            }
          });
          // channelIds 与  返回来的视频不匹对。那就把剩余的id再去发送请求
          if (this.channelIds.length != arr.length) {
            let muidArr = arr.map((item) => Number(item.channelId));
            let idArr = this.getArrDifference(this.channelIds, muidArr);
            urlArr = [...idArr, ...urlArr];
            // console.log(urlArr);
          }
          if (!bool || this.channelIds.length != arr.length) {
            let arr = urlArr.map((item) => {
              return {
                channelId: item,
              };
            });
            // console.log(arr);
            this.channelIds = urlArr;
            this.timeMU = null
            this.timeMU = setInterval(async () => {
              await this.getMuVideo(arr);
            }, 3000);
          }
        });
      });
    },

然后那又有一个需求,在videoList视频列表有离线和在线状态,html上根据videoList视频列表返回来的data判断显示视频和不显示视频

     <div style="position: relative">
          <!-- 在线 -->
          <div
            @click="lookVideo(item.channelId, item.status, item.channelName)"
            element-loading-background="rgba(0, 0, 0, 0.1)"
            v-loading="item.loading"
            :style="height"
            :ref="'videoDiv' + item.channelId"
            v-show="item.status == 'ONLINE'"
          >
            <video
              :id="'video' + item.channelId"
              ref="videos"
              class="video video-js vjs-big-play-centered"
            >
              <source
                :id="'video' + item.channelId"
                src=""
                type="application/x-mpegURL"
              />
            </video>
          </div>
          <!-- 离线 -->
          <div
            @click.self="
              lookVideo(item.channelId, item.status, item.channelName)
            "
            :style="height"
            v-show="item.status == 'OFFLINE'"
            class="backgc-content"
          >
            <el-image
              style="width: 50%; height: 50%"
              :src="imgUrl"
              fit="fill"
            ></el-image>
          </div>
          <!-- 最下方 -->
          <div class="videoTitle" v-if="cameraname">
            <span style="color: #ffffff"
              >[{{ item.channelId }}] {{ item.channelName }}</span
            >
            <div style="position: absolute; left: 80%">
              <div>
                <i
                  :class="{
                    'el-icon-success': item.status == 'ONLINE',
                    'el-icon-error': item.status == 'OFFLINE',
                  }"
                ></i
                ><span
                  :class="{
                    online: item.status == 'ONLINE',
                    offline: item.status == 'OFFLINE',
                  }"
                  >{{ item.status == "ONLINE" ? "在线" : "离线" }}</span
                >
              </div>
            </div>
          </div>
        </div>

离线状态里没有cideo标签就无法展示视频

意思是我9个channelId里面有离线的和没离线的都去请求了,渲染的时候肯定是离线是没办法渲染上的,然后我根据判断假如离线的channelId为5,5的url回来了,我就把videoList的离线状态改成在线,然后在线的html就有video标签了,...现在问题来了,这个判断是在有这个5的url时候进行判断的,所以他已经有url了已经用video js插入dom进行渲染了

就算if了也是无法显示,所以逻辑有问题,没法进行.搞不懂为啥离线的也要发送请求,接通视频后撒撒刷新页面不就可以了

下面我把带吗全部贴出看你们可以看的懂吗,然后销毁这个video js标签也有问题,解决是插入daom元素

<template>
  <div>
    <el-row style="margin-top: 20px">
      <el-col
        v-for="(item, index) of vldeoArr"
        :key="index"
        :span="span"
        style="border: 2px solid #344563"
      >
        <div style="position: relative">
          <!-- 在线 -->
          <div
            @click="lookVideo(item.channelId, item.status, item.channelName)"
            element-loading-background="rgba(0, 0, 0, 0.1)"
            v-loading="item.loading"
            :style="height"
            :ref="'videoDiv' + item.channelId"
            v-show="item.status == 'ONLINE'"
          >
            <video
              :id="'video' + item.channelId"
              ref="videos"
              class="video video-js vjs-big-play-centered"
            >
              <source
                :id="'video' + item.channelId"
                src=""
                type="application/x-mpegURL"
              />
            </video>
          </div>
          <!-- 离线 -->
          <div
            @click.self="
              lookVideo(item.channelId, item.status, item.channelName)
            "
            :style="height"
            v-show="item.status == 'OFFLINE'"
            class="backgc-content"
          >
            <el-image
              style="width: 50%; height: 50%"
              :src="imgUrl"
              fit="fill"
            ></el-image>
          </div>
          <!-- 最下方 -->
          <div class="videoTitle" v-if="cameraname">
            <span style="color: #ffffff"
              >[{{ item.channelId }}] {{ item.channelName }}</span
            >
            <div style="position: absolute; left: 80%">
              <div>
                <i
                  :class="{
                    'el-icon-success': item.status == 'ONLINE',
                    'el-icon-error': item.status == 'OFFLINE',
                  }"
                ></i
                ><span
                  :class="{
                    online: item.status == 'ONLINE',
                    offline: item.status == 'OFFLINE',
                  }"
                  >{{ item.status == "ONLINE" ? "在线" : "离线" }}</span
                >
              </div>
            </div>
          </div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import {
  rtspAndM3u8,
  getRtspAndM3u8,
  mutiRtspAndM3u8,
} from "@/api/videoSquare.js";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";
export default {
  name: "videps",
  props: {
    // 宫格
    spanNum: {
      type: Number,
      default: 1,
    },
    //多少页
    currentPage: {
      type: Number,
      default: 1,
    },
    //获取的id 根据id用来请求视频流
    videoList: {
      type: Array,
      default: () => [],
    },
    // 摄像头是否显示
    cameraname: {
      type: Boolean,
      default: true,
    },
    // 父组件的方法
    getVideoList: {
      type: Function,
      default: null,
    },
  },
  computed: {
    height() {
      let num = Math.sqrt(this.spanNum);
      let h = "550px";
      if (this.spanNum == 12) {
        num = 3;
      }
      if (this.$store.getters.flagName) {
        h = "85vh";
      }
      return {
        height: `calc(${h} / ${num})`,
        width: "100%",
      };
    },
    span() {
      let num = Math.sqrt(this.spanNum);
      if (this.spanNum == 12) {
        num = 4;
      }
      return 24 / num;
    },
  },
  data() {
    return {
      timeMU: null,
      videoOptions: {
        autoplay: true,
        muted: true, //默认情况下消除任何音频
        controls: true,
        poster: "",
        sources: [
          {
            src: "",
            type: "application/x-mpegURL",
          },
        ],
      },
      player: [], //存储video 实列
      vldeoArr: [],
      channelIds: [], //id  用来获取视频
      imgUrl: require("@/assets/no-photo.png"),
    };
  },
  mounted() {},
  methods: {
    //点击播放视频
    lookVideo(channelId, status, channelName) {
      // return;
      const loading = this.$loading({
        lock: true,
        text: "Loading",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.3)",
        target: document.querySelector(".click_" + channelId),
      });

      let data = {
        channelId: channelId,
      };
      rtspAndM3u8(data)
        .then((res) => {
          if (res.data.code == 200) {
            let visitUrl = res.data.data.visitUrl;
            //请求地址不为空
            if (visitUrl != null) {
              this.visitUrl = this.GLOBAL.BASE_URL + visitUrl;
              // this.visitUrl = res.data.data.visitUrl;
              loading.close();
              this.$router.push({
                name: "videoPlay",
                query: {
                  channelId: channelId,
                  channelName: channelName,
                  visitUrl: this.visitUrl,
                },
              });
            } else {
              //请求地址为空
              let _this = this;
              _this.playTimer = setInterval(function () {
                //获取m3u8播放地址
                let params = {
                  channelId: channelId,
                };
                getRtspAndM3u8(params)
                  .then((res) => {
                    if (res.data.code == 200) {
                      let visitUrl = res.data.data;
                      if (visitUrl != null) {
                        _this.visitUrl = _this.GLOBAL.BASE_URL + visitUrl;
                        // loading.close();
                        clearInterval(_this.playTimer);
                        _this.playTimer = null;
                        _this.$router.push({
                          name: "videoPlay",
                          query: {
                            channelId: channelId,
                            channelName: channelName,
                            visitUrl: _this.visitUrl,
                          },
                        });
                      } else {
                        _this.$message.error(res.data.msg);
                        return false;
                      }
                    } else {
                      // _this.$message.error(res.data.msg);
                      //清除延迟定时器
                      /*clearInterval(this.playTimer);
                    this.playTimer = null;
                    return false;*/
                    }

                    if (status == "OFFLINE") {
                      // _this.$message.error(res.data.msg);
                      loading.close();
                      return false;
                    }
                  })
                  .catch((error) => {});
              }, 5000);
            }
          } else {
            this.$message.error(res.data.msg);
            return false;
          }
        })
        .catch((error) => {});
    },

    Destroy() {
      // 销毁视频实例
      if (this.player.length) {
        this.player.forEach((item) => {
          item.dispose();
        });
        this.player = [];
      }
    },
    // 父组件keepalive钩子函数离开页面调用
    keepDestory(){
      if (this.timeMU) {
        clearInterval(this.timeMU);
        this.timeMU = null
      }
      this.Destroy(); //销毁视频实例
    },
    getArrDifference(arr1, arr2) {
      return arr1.concat(arr2).filter(function (v, i, arr) {
        return arr.indexOf(v) === arr.lastIndexOf(v);
      });
    },
    // 取消请求
    cancelQuest() {
      if (typeof this.source === "function") {
        // console.log("取消上一次请求");
        this.source("终止请求"); //取消请求
      }
    },
    // 视频播放
    async getMuVideo(ids) {
      let _this = this;
      await mutiRtspAndM3u8(ids, this).then((res) => {
        this.$nextTick(async () => {
          // 清除m3u8定时器
          if (this.timeMU) {
            clearInterval(this.timeMU);
            this.timeMU = null
          }
          let arr = res.data.data;
          let bool = true; //用来判断 url  是否全部有值
          let urlArr = [];
          arr.forEach((item, index) => {
            if (item.visitUrl) {
              // 拿到所有的url去和视频列表里面判断,如果视频列表里面的是离线OFFLINE就改为在线ONLINE状态
              _this.videoList.forEach((v) => {
                //  && v.status == "OFFLINE"
                if (item.channelId == v.channelId) {
                  // v.status = "ONLINE";
                  v.loading = false;
                  if(v.status != "OFFLINE"){
                  }
                  // this.getVideoList()
                  // 因为上一步有了url视频地址,虽然这次判断更改了dom的显示,但是还是无法赋值url
                }
              });
              this.$nextTick(() => {
                let videoOptions = JSON.parse(
                  JSON.stringify(this.videoOptions)
                );
                videoOptions.sources[0].src =
                  _this.GLOBAL.BASE_URL + item.visitUrl;

                let dom =
                  "<video  id=" +
                  "video" +
                  item.channelId +
                  ' class="video-js vjs-default-skin" controls style="width:100%;height:100%"></video>';
                this.$refs["videoDiv" + item.channelId][0].innerHTML = dom;
                this.$forceUpdate();
                this.player.push(
                  videojs("video" + item.channelId, videoOptions)
                );
              });
            } else {
              bool = false;
              urlArr.push(Number(item.channelId));
            }
          });
          // channelIds 与  返回来的视频不匹对。那就把剩余的id再去发送请求
          if (this.channelIds.length != arr.length) {
            let muidArr = arr.map((item) => Number(item.channelId));
            let idArr = this.getArrDifference(this.channelIds, muidArr);
            urlArr = [...idArr, ...urlArr];
            // console.log(urlArr);
          }
          if (!bool || this.channelIds.length != arr.length) {
            let arr = urlArr.map((item) => {
              return {
                channelId: item,
              };
            });
            // console.log(arr);
            this.channelIds = urlArr;
            this.timeMU = null
            this.timeMU = setInterval(async () => {
              await this.getMuVideo(arr);
            }, 3000);
          }
        });
      });
    },
  },
  beforeDestroy() {
    if (this.timeMU) {
      clearInterval(this.timeMU);
      this.timeMU = null
    }
    this.Destroy();
  },
  watch: {
    videoList: {
      async handler(val) {
        this.cancelQuest(); // 请求发送前调用  切换栅格时  把之前的接口清空
        await this.Destroy();
        this.channelIds = [];
        this.vldeoArr = val;
        let arrId = [];
        // 判断是否离线 只取在线  改为不判断离线和不离线都发请求
        this.vldeoArr.forEach((item) => {
          //  console.log(this.$refs["videoDiv" + item.channelId]);
          item.loading = true;
          arrId.push({ channelId: item.channelId });
          this.channelIds.push(Number(item.channelId));
        });
        this.$forceUpdate();
        if (arrId.length) {
          this.getMuVideo(arrId);
        }
      },
      deep: true,
    },
  },
};
</script>

<style scoped lang="scss">
.video {
  width: 100%;
  height: 100%;
}
.backgc-content {
  display: flex;
  justify-content: center;
  align-items: center;
  background: #000000;
  // height: 306px;
  text-align: center;
}
/*标题样式*/
.videoTitle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 93%;
  position: absolute;
  bottom: 15px;
  left: 20px;
  span {
    font-size: 14px;
    font-family: Microsoft YaHei;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.85);
  }

  div {
    /*在线icon样式*/
    .el-icon-success:before {
      font-size: 12px;
      color: #4cd964;
      margin-right: 5px;
    }

    .el-icon-error:before {
      font-size: 12px;
      color: #ff3a3a;
      margin-right: 5px;
    }

    span.online {
      font-size: 12px;
      color: #4cd964;
    }

    span.offline {
      font-size: 12px;
      color: #ff3a3a;
    }
  }
}
</style>

不喜勿喷,多交流多探讨

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值