最近项目遇到一个需求,需要一轮播图的形式展示几个实时的监控视频,这就需要用到swiper和video.js,因为视频格式是m3u8格式的,所以原生video标签不支持
先安装swiper和videojs所需的依赖包
// swiper的包
npm i swiper vue-awesome-swiper
npm i swiper@5
// videojs的包
npm install video.js --save // 视频播放器插件
npm install videojs-contrib-hls --save // 播放hls流插件
在main.js中引入
// 引入swiper
import 'swiper/swiper-bundle.css'
import VueAwesomeSwiper from 'vue-awesome-swiper'
Vue.use(VueAwesomeSwiper)
// 引入videojs和样式
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";
使用
不说废话直接上代码
<!-- The ref attr used to find the swiper instance -->
<template>
<swiper
:options="swiperOption"
:not-next-tick="notNextTick"
ref="mySwiper"
class="sw"
>
<!-- @click="Monitoring" -->
<!-- slides -->
<swiper-slide v-for="item,index in monitor" :key="item.id"
><div class="monitorItem">
<div class="imgArea">
<div class="vidioArea">
<video
:id="`my-video${index}`"
class="video-js vjs-default-skin videos"
muted
>
<source
:src="item.encryption_height"
type="application/x-mpegURL"
/>
</video>
</div>
<div class="bottomText">
<span>{{ item.shop_name }}</span>
</div>
<div class="ladder">
<div class="ladderson">{{ item.title }}</div>
</div>
</div>
</div>
</swiper-slide>
<!-- Optional controls -->
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-prev" slot="button-prev" ></div>
<div class="swiper-button-next" slot="button-next" ></div>
<div class="swiper-scrollbar" slot="scrollbar"></div>
</swiper>
</template>
<script>
// swiper options example:
import videojs from "video.js";
import "videojs-contrib-hls";
import loading from "@/components/loading/loading.vue";
export default {
name: "carrousel",
data() {
return {
monitor: [],
player: [],
// notNextTick是一个组件自有属性,如果notNextTick设置为true,组件则不会通过NextTick来实例化swiper,也就意味着你可以在第一时间获取到swiper对象,假如你需要刚加载遍使用获取swiper对象来做什么事,那么这个属性一定要是true
notNextTick: true,
swiperOption: {
// swiper options 所有的配置同swiper官方api配置
autoplay: 10000, // 自动播放的时间间隔
slidesPerView: 3, //一次显示的数量
direction: "horizontal", // 水平轮播
grabCursor: true,
setWrapperSize: true,
autoHeight: true,
pagination: ".swiper-pagination",
paginationClickable: true,
prevButton: ".swiper-button-prev",
nextButton: ".swiper-button-next",
scrollbar: ".swiper-scrollbar",
mousewheelControl: true,
observeParents: true,
// if you need use plugins in the swiper, you can config in here like this
// 如果自行设计了插件,那么插件的一些配置相关参数,也应该出现在这个对象中,如下debugger
// debugger: true,
// swiper callbacks
// swiper的各种回调函数也可以出现在这个对象中,和swiper官方一样
onTransitionStart(swiper) {
// console.log(swiper);
},
// more Swiper configs and callbacks...
// ...
},
};
},
// you can find current swiper instance object like this, while the notNextTick property value must be true
// 如果你需要得到当前的swiper对象来做一些事情,你可以像下面这样定义一个方法属性来获取当前的swiper对象,同时notNextTick必须为true
computed: {
swiper() {
return this.$refs.mySwiper.swiper;
},
},
mounted() {
// you can use current swiper instance object to do something(swiper methods)
// 然后你就可以使用当前上下文内的swiper对象去做你想做的事了
// console.log('this is current swiper instance object', this.swiper)
// this.swiper.slideTo(3, 1000, false)
// this.goVideo(this.monitor)
},
methods: {
Monitoring() {
this.$router.push("/monitoringlive");
},
getmonitorList(index){
this.$axios.post("接口名",{page:index}).then(
(res)=>{
if(res.data.code === 200){
// this.monitor = res.data.data.data
this.monitor.push(...res.data.data.data)
console.log(this.monitor);
this.goVideo(this.monitor)
}
console.log(res);
}
)
},
goVideo(data) {
this.videoList = data;
console.log(this.videoList);
if (data.length == 0) {
this.$message({
showClose: true,
message: "暂无视频~",
});
} else {
// this.videoisShow = true;
this.$nextTick(() => {
this.videoList.forEach((item, index) => this.getVideo(index));
});
}
},
getVideo(i) {
let res = videojs(
`my-video${i}`,
{
bigPlayButton: true,
textTrackDisplay: false,
posterImage: false,
errorDisplay: false,
controls: true,
hls: {
withCredentials: true,
},
controlBar: {
fullscreenToggle: true,//显示全屏按钮,默认为true
pictureInPictureToggle: false,//隐藏画中画按钮,默认为true
volumePanel: false,//隐藏声音面板
//currentTimeDisplay: true,//显示当前播放时间
//timeDivider: true,//显示时间分割线
//durationDisplay: true,//显示总时间
//remainingTimeDisplay: false,//隐藏剩余时间,
}
},
function () {
this.play();
}
);
this.player.push(res);
},
videoClose() {
this.player.forEach((item) => item.dispose());
this.player = [];
this.videoList = [];
},
},
components: {
// loading,
videojs,
},
created () {
this.getmonitorList(1)
var timer = 0
this.echartsset = setInterval(() => {
timer++
this.getmonitorList(2);
if(timer === 1){
clearInterval(this.echartsset)
}
}, 10000);
},
beforeDestroy(){
this.videoClose()
}
};
</script>
<style scoped lang = "less">
/* sw为自己定义的样式 */
/* .sw {
--swiper-navigation-size:0;
} */
/* .sw img {
height: 270px;
width: 95%;
} */
.monitorItem {
margin: 15px;
cursor: pointer;
border: 5px solid rgb(1, 114, 255);
.imgArea {
position: relative;
width: 100%;
height: 100%;
.bottomText {
font-size: 12px;
/* position: absolute; */
left: 0;
bottom: -10px;
width: 100%;
color: white;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ladder {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 0;
border-top: 20px solid rgb(1, 114, 255);
border-right: 20px solid transparent;
text-align: center;
.ladderson {
color: #fff;
font-size: 12px;
margin-top: -18px;
/* margin-left: 3px; */
}
}
}
}
.sw img[data-v-31d8b10e] {
height: 100%;
width: 100%;
}
.swiper-button-prev,
.swiper-button-next {
width: calc(var(--swiper-navigation-size) / 44 * 0);
font-weight: 1000;
}
.swiper-button-prev:after,
.swiper-button-next:after {
font-size: 35px;
}
.videos {
width: 100%;
height: 120px;
object-fit: cover;
}
.video-js .vjs-tech .videos{
width: 100%;
/* height: 100%; */
object-fit: cover;
}
</style>
最终效果
![](https://img-blog.csdnimg.cn/img_convert/f4dc8b81503a1345dbe7d6b776e7d347.png)