詳解Vue實(shí)現(xiàn)直播功能
最近公司剛好在做直播,那么今天就記錄一下遇到的坑,公司服務(wù)器用的亞馬遜aws,所以直接看官方的api就可以了,aws官方地址aws直播api
先看下具體的實(shí)現(xiàn)后的效果圖把

按照網(wǎng)上成熟的方法,使用的是video.js,然后aws做了一層封裝,那么我們直接拿來(lái)使用把,這里使用vue版本的vue-video-player
先安裝下相關(guān)的包
npm install vue-video-player --save
在main.js引入vue-video-player
// 第一個(gè)是videoJs的樣式,后一個(gè)是vue-video-player的樣式,因?yàn)榭紤]到我其他業(yè)務(wù)組件可能也會(huì)用到視頻播放,所以就放在了main.js內(nèi)
require('video.js/dist/video-js.css')
require('vue-video-player/src/custom-theme.css')
/*導(dǎo)入視頻播放組件*/
import VideoPlayer from 'vue-video-player'
Vue.use(VideoPlayer)
導(dǎo)入組件,修改配置參數(shù)
<video-player
class="video-player vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@statechanged="playerStateChanged($event)"
></video-player>
修改參數(shù),添加src
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
autoplay: false, //如果true,瀏覽器準(zhǔn)備好時(shí)開(kāi)始回放。
controls: true, //控制條
preload: "auto", //視頻預(yù)加載
muted: true, //默認(rèn)情況下將會(huì)消除任何音頻。
loop: false, //導(dǎo)致視頻一結(jié)束就重新開(kāi)始。
language: "zh-CN",
aspectRatio: "16:9", // 將播放器置于流暢模式,并在計(jì)算播放器的動(dòng)態(tài)大小時(shí)使用該值。值應(yīng)該代表一個(gè)比例 - 用冒號(hào)分隔的兩個(gè)數(shù)字(例如"16:9"或"4:3")
fluid: true, // 當(dāng)true時(shí),Video.js player將擁有流體大小。換句話說(shuō),它將按比例縮放以適應(yīng)其容器。
sources: [
{
withCredentials: false,
type: "application/x-mpegURL",
//src: this.liveSrc
src:
"https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8"
}
],
poster: this.image, //你的封面地址
//width: 200 || document.documentElement.clientWidth,
notSupportedMessage: "此視頻暫無(wú)法播放,請(qǐng)稍后再試", //允許覆蓋Video.js無(wú)法播放媒體源時(shí)顯示的默認(rèn)信息。
controlBar: {
timeDivider: true, // 當(dāng)前時(shí)間和持續(xù)時(shí)間的分隔符
durationDisplay: true, // 顯示持續(xù)時(shí)間
remainingTimeDisplay: false, // 是否顯示剩余時(shí)間功能
fullscreenToggle: true // 是否顯示全屏按鈕
}
},
注意要先測(cè)試直播源可以成功播放才可以,否則就會(huì)報(bào)下這些錯(cuò)誤

那么我們先按照官方的搭建一個(gè)本地的直播源測(cè)試吧
先搭建html界面,注意要引入相關(guān)的js庫(kù)和文件,我這里用hbuilder,因?yàn)橛玫谋容^順手,而且預(yù)覽模式類(lèi)似于開(kāi)了一個(gè)端口,通過(guò)get方式的方法,返回了一個(gè)本地服務(wù),而不是直接本地雙擊打開(kāi)html文件,訪問(wèn)靜態(tài)文件哦~~~~
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script>
<script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script>
</head>
<body>
<div class="video-container">
<video id="amazon-ivs-videojs" class="video-js vjs-4-3 vjs-big-play-centered" controls autoplay playsinline></video>
</div>
<style>
body {
margin: 0;
}
.video-container {
width: 640px;
height: 480px;
margin: 15px;
}
</style>
<script>
(function play() {
// Get playback URL from Amazon IVS API
//var PLAYBACK_URL = 'https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8';
var PLAYBACK_URL = 'https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8'
// Register Amazon IVS as playback technology for Video.js
registerIVSTech(videojs);
// Initialize player
var player = videojs('amazon-ivs-videojs', {
techOrder: ["AmazonIVS"]
}, () => {
console.log('Player is ready to use!');
// Play stream
player.src(PLAYBACK_URL);
});
})();
</script>
</body>
</html>
通過(guò)端口訪問(wèn),

后來(lái)發(fā)現(xiàn)通過(guò)本地靜態(tài)文件,也可以實(shí)現(xiàn)在線直播源播放

ps:如果不想自己搭建本機(jī)服務(wù)測(cè)試,也可以直接使用awd提供的在線測(cè)試
https://replit.com/@changdong0524/amazon-ivs-player-web-sample#samples/common/form-control.ts,但是要自己注冊(cè)賬號(hào)哦
大概就是下面這樣子哦

大家自己去摸索一下就會(huì)了,修改input.value為直播源地址,然后在右邊shell控制臺(tái)啟動(dòng)就可以了
npm install && npm run start
效果如下,是一模一樣的

load這里的地址換成你自己的直播源m3u8格式就好了,我這里是已經(jīng)搭建好的在線直播源

直播源沒(méi)問(wèn)題后,接下來(lái)就直接繼續(xù)寫(xiě)項(xiàng)目代碼
<template>
<div class='demo'>
<video-player class="video-player vjs-custom-skin"
ref="videoPlayer"
:playsinline="true"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@ended="onPlayerEnded($event)"
@waiting="onPlayerWaiting($event)"
@playing="onPlayerPlaying($event)"
@loadeddata="onPlayerLoadeddata($event)"
@timeupdate="onPlayerTimeupdate($event)"
@canplay="onPlayerCanplay($event)"
@canplaythrough="onPlayerCanplaythrough($event)"
@statechanged="playerStateChanged($event)"
@ready="playerReadied"
>
</video-player>
</div>
</template>
<script>
export default {
methods: {
// 播放回調(diào)
onPlayerPlay(player) {
console.log('player play!', player)
},
// 暫停回調(diào)
onPlayerPause(player) {
console.log('player pause!', player)
},
// 視頻播完回調(diào)
onPlayerEnded($event) {
console.log(player)
},
// DOM元素上的readyState更改導(dǎo)致播放停止
onPlayerWaiting($event) {
console.log(player)
},
// 已開(kāi)始播放回調(diào)
onPlayerPlaying($event) {
console.log(player)
},
// 當(dāng)播放器在當(dāng)前播放位置下載數(shù)據(jù)時(shí)觸發(fā)
onPlayerLoadeddata($event) {
console.log(player)
},
// 當(dāng)前播放位置發(fā)生變化時(shí)觸發(fā)。
onPlayerTimeupdate($event) {
console.log(player)
},
//媒體的readyState為HAVE_FUTURE_DATA或更高
onPlayerCanplay(player) {
// console.log('player Canplay!', player)
},
//媒體的readyState為HAVE_ENOUGH_DATA或更高。這意味著可以在不緩沖的情況下播放整個(gè)媒體文件。
onPlayerCanplaythrough(player) {
// console.log('player Canplaythrough!', player)
},
//播放狀態(tài)改變回調(diào)
playerStateChanged(playerCurrentState) {
console.log('player current update state', playerCurrentState)
},
//將偵聽(tīng)器綁定到組件的就緒狀態(tài)。與事件監(jiān)聽(tīng)器的不同之處在于,如果ready事件已經(jīng)發(fā)生,它將立即觸發(fā)該函數(shù)。。
playerReadied(player) {
console.log('example player 1 readied', player);
}
},
}
</script>
定義相關(guān)的監(jiān)聽(tīng)函數(shù),可以根據(jù)自己需要加上,常用的有下面幾個(gè)
onPlayerPlay(player) {
console.log("onPlayerPlay", player);
},
onPlayerPause(player) {
console.log("onPlayerPause", player);
},
playerStateChanged(player) {
console.log("playerStateChanged", player);
},
然后啟動(dòng)服務(wù)
npm run start
發(fā)現(xiàn)報(bào)錯(cuò),無(wú)法找到相關(guān)的視頻,于是發(fā)現(xiàn)缺少相關(guān)的庫(kù),還得加上aws的庫(kù)才可以
在整個(gè)項(xiàng)目的index.html中加入下面的庫(kù)支持文件
<link rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script> <script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script>

最后完整效果就出來(lái)了

注意事項(xiàng):
video-player標(biāo)簽的class必須設(shè)置成“video-player vjs-custom-skin”,你引入的樣式才能起作用。 增加hls的支持。支持流媒體m3u8g等等格式播放。
增加hls.js支持,故此要安裝依賴,如下:
npm install --save videojs-contrib-hls
這里提供下aws的官方倉(cāng)庫(kù)啊,需要自取哦
https://github.com/aws-samples
補(bǔ)充一下:如果直接在頁(yè)面中實(shí)現(xiàn)的話,可能無(wú)法直接播放,會(huì)報(bào)錯(cuò)無(wú)法播放視頻,我猜測(cè)可能有2個(gè)原因,見(jiàn)截圖

1:異步獲取后臺(tái)返回的拉流地址的時(shí)候,需要一定的時(shí)間,這個(gè)時(shí)間直播組件已經(jīng)初始化完畢,但是還沒(méi)有獲取到直播源地址,所以會(huì)報(bào)錯(cuò)找不到直播地址
2:直播組件也有自己一整套完整的生命周期,我們可以檢測(cè)不同的生命周期,然后把直播源地址,在請(qǐng)求完畢后放入合適的時(shí)間,直播組件會(huì)一直請(qǐng)求這個(gè)直播地址,從而實(shí)現(xiàn)在線直播
這里我為了偷懶,暫時(shí)沒(méi)有那么多時(shí)間去研究一下,等空了會(huì)去仔細(xì)研究一下,我是把他抽離出一個(gè)單組的子組件,通過(guò)props來(lái)實(shí)現(xiàn)地址的傳遞


效果一樣一樣的,也可以方便其他組件調(diào)用

最后為了方便管理,雙手奉上最后的全部代碼
start
1:main.js
// 第一個(gè)是videoJs的樣式,后一個(gè)是vue-video-player的樣式,因?yàn)榭紤]到我其他業(yè)務(wù)組件可能也會(huì)用到視頻播放,所以就放在了main.js內(nèi)
require('video.js/dist/video-js.css')
require('vue-video-player/src/custom-theme.css')
/*導(dǎo)入視頻播放組件*/
import VideoPlayer from 'vue-video-player'
Vue.use(VideoPlayer)
2:videoPlayer.vue
<template>
<video-player
class="video-player vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@statechanged="playerStateChanged($event)"
></video-player>
</template>
<script >
//import { registerIVSTech } from "amazon-ivs-player";
export default {
name: "",
props: ["src", "image"],
data() {
return {
// liveSrc:
// "https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8",
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
autoplay: false, //如果true,瀏覽器準(zhǔn)備好時(shí)開(kāi)始回放。
controls: true, //控制條
preload: "auto", //視頻預(yù)加載
muted: false, //默認(rèn)情況下將會(huì)消除任何音頻。
loop: false, //導(dǎo)致視頻一結(jié)束就重新開(kāi)始。
language: "zh-CN",
aspectRatio: "16:9", // 將播放器置于流暢模式,并在計(jì)算播放器的動(dòng)態(tài)大小時(shí)使用該值。值應(yīng)該代表一個(gè)比例 - 用冒號(hào)分隔的兩個(gè)數(shù)字(例如"16:9"或"4:3")
fluid: true, // 當(dāng)true時(shí),Video.js player將擁有流體大小。換句話說(shuō),它將按比例縮放以適應(yīng)其容器。
sources: [
{
withCredentials: false,
type: "application/x-mpegURL",
src: this.src
// "https://50f5175980ea.us-east-1.playback.live-video.net/api/video/v1/us-east-1.003054160756.channel.bSt8OCsmBtFq.m3u8"
}
],
poster: this.image, //你的封面地址
//width: 200 || document.documentElement.clientWidth,
notSupportedMessage: "此視頻暫無(wú)法播放,請(qǐng)稍后再試", //允許覆蓋Video.js無(wú)法播放媒體源時(shí)顯示的默認(rèn)信息。
controlBar: {
timeDivider: true, // 當(dāng)前時(shí)間和持續(xù)時(shí)間的分隔符
durationDisplay: true, // 顯示持續(xù)時(shí)間
remainingTimeDisplay: false, // 是否顯示剩余時(shí)間功能
fullscreenToggle: true // 是否顯示全屏按鈕
}
}
};
},
// livePlays() {
// this.playerOptions.sources[0].src = this.liveSrc;
// var obj = {};
// obj.withCredentials = false;
// obj.type = "application/x-mpegURL";
// obj.src = this.pullUrl;
// this.playerOptions.sources.append(obj);
// },
computed: {
player() {
return this.$refs.videoPlayer.player;
}
},
computed: {
player() {
return this.$refs.videoPlayer.player;
}
},
methods: {
onPlayerPlay(player) {
console.log("onPlayerPlay", player);
},
onPlayerPause(player) {
console.log("onPlayerPause", player);
},
playerStateChanged(player) {
console.log("playerStateChanged", player);
}
}
};
</script>
3:detail.vue 父組件
<template>
<d2-container>
<div>
<div class="webTitle">直播管理 > 大型直播 > 詳情</div>
<el-table :data="list" border stripe>
<el-table-column align="center" label="直播ID">
<template slot-scope="scope">
<span>{{ scope.row.id }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="直播標(biāo)題">
<template slot-scope="scope">
<span>{{ scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="賬號(hào)">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="直播開(kāi)始時(shí)間">
<template slot-scope="scope">
<span>{{ scope.row.liveStart | timestampFormat }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="觀看人數(shù)">
<template slot-scope="scope">
<span>{{ scope.row.watchNumber }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="評(píng)論數(shù)">
<template slot-scope="scope">
<span>{{ scope.row.reserveNumber }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="購(gòu)票金額(GP)">
<template slot-scope="scope">
<span>{{scope.row.preSaleType == 1 ? scope.row.preSaleBalance*1 + scope.row.preSaleDeposit *1+ scope.row.fullPayment*1 : scope.row.fullPayment}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="禮物金額">
<template slot-scope="scope">
<span>{{ scope.row.reserveNumber }}</span>
</template>
</el-table-column>
</el-table>
<div class="playWrap">
<div class="livePicture">
<vueVideoPlayers :src="src" :image="image" />
</div>
<div class="liveCommet"></div>
</div>
<div class="playWrap">
<div class="playLeft">
<p>基本信息</p>
<ul class="leftInfo">
<li class="playItem">
<span class="playTitle">分類(lèi)</span>
<span class="playContent">{{typeName}}</span>
</li>
<li class="playItem">
<span class="playTitle">預(yù)售類(lèi)型</span>
<span class="playContent">{{formData.preSaleType == 1 ? "預(yù)售" :"非預(yù)售"}}</span>
</li>
<li class="playItem">
<span class="playTitle">是否錄播</span>
<span class="playContent">{{formData.isRecordedBroadcast ==1 ? "錄播" : "不錄播"}}</span>
</li>
<li class="playItem">
<span class="playTitle">演員列表</span>
<span class="playContent">{{formData.actor}}</span>
</li>
<li class="playItem">
<span class="playTitle">直播介紹</span>
<span class="playContent">{{formData.liveIntroduce}}</span>
</li>
</ul>
<p>預(yù)售信息</p>
<ul class="leftInfo">
<li class="playItem">
<span class="playTitle">預(yù)售時(shí)段</span>
<span class="playContent">
{{formData.preSaleStart}}
<span style="color:#333;margin:0 5px">-</span>
{{formData.preSaleEnd}}
</span>
</li>
<li class="playItem">
<span class="playTitle">成型人數(shù)</span>
<span class="playContent">{{formData.formingNum ? formData.formingNum : 0}}</span>
</li>
<li class="playItem">
<span class="playTitle">成型狀態(tài)</span>
<span
class="playContent"
>{{formData.reserveNumber > formData.reserveNumber ? "已成型":"未成型" }}</span>
</li>
</ul>
<p>非預(yù)售信息</p>
<ul class="leftInfo">
<li class="playItem">
<span class="playTitle">售票開(kāi)始時(shí)間</span>
<span class="playContent">{{formData.ticketingStart}}</span>
</li>
</ul>
<p>票價(jià)</p>
<ul class="leftInfo">
<li class="playItem">
<span class="playTitle">預(yù)售定金</span>
<span class="playContent">{{formData.preSaleDeposit ? formData.preSaleDeposit : 0}}</span>
</li>
<li class="playItem">
<span class="playTitle">預(yù)售尾款</span>
<span class="playContent">{{formData.preSaleBalance ? formData.preSaleBalance : 0}}</span>
</li>
<li class="playItem">
<span class="playTitle">全款價(jià)格</span>
<span class="playContent">{{formData.fullPayment ? formData.fullPayment : 0}}</span>
</li>
<li class="playItem">
<span class="playTitle">回放價(jià)格</span>
<span class="playContent">{{formData.playbackPrice ? formData.playbackPrice : 0}}</span>
</li>
</ul>
</div>
<div class="playRight">
<p>圖像資料</p>
<ul class="leftInfo">
<li class="playItem">
<span class="playTitle">宣傳視頻</span>
<span class="playContent">
<img
v-if="formData.propagandaVideoUrl"
:src="videoPng"
class="playImage"
@click="showVideo(formData.propagandaVideoUrl,true)"
/>
<span v-else style="color:#cfcfcf">暫無(wú)視頻</span>
</span>
</li>
<li class="playItem">
<span class="playTitle">回訪視頻</span>
<span class="playContent">
<img
v-if="formData.recordedBroadcastUrl"
:src="videoPng"
class="playImage"
@click="showVideo(formData.recordedBroadcastUrl,false)"
/>
<span v-else style="color:#cfcfcf">暫無(wú)視頻</span>
</span>
</li>
<li class="playItem">
<span class="playTitle">分享海報(bào)</span>
<span class="playContent">
<el-image
class="matchImg"
:src="formData.shareImage"
:preview-src-list="[formData.shareImage]"
/>
</span>
</li>
<li class="playItem">
<span class="playTitle">封面圖片</span>
<span class="playContent">
<el-image
class="matchImg"
v-for="(item,index) in JSON.parse(formData.coverImage)"
:src="item"
:key="index"
:preview-src-list="[item]"
/>
</span>
</li>
</ul>
<!-- <p>圖像資料</p>
<ul class="leftInfo"></ul>-->
</div>
</div>
</div>
<el-button @click="backPage">返回</el-button>
<el-dialog title="查看" :visible.sync="videoVisible" width="850px">
<div v-if="video">
<video :src="tempSrc" controls="controls" width="800" height="600">您的瀏覽器不支持 video 標(biāo)簽。</video>
</div>
<div v-else>
<vueVideoPlayers :src="tempSrc" :image="image" />
</div>
</el-dialog>
</d2-container>
</template>
<script >
import { getLiveDetail, getLiveSellDetail } from "@/api/3d/liveApi";
import videoPng from "@/assets/img/video.jpg";
import { timestampFormat } from "@/common/filters";
//import { registerIVSTech } from "amazon-ivs-player";
import vueVideoPlayers from "./videoPlayer";
export default {
name: "",
data() {
return {
src: "", //直播源視頻
image: "",
videoPng: videoPng,
video: true,
videoVisible: false,
// videoSrc: "", //宣傳視頻
// recordedBroadcastUrl:'', //回放視頻
tempSrc: "",
list: [],
id: "",
typeName: "",
pullUrl: "",
formData: {
id: "",
pullUrl: "",
pushUrl: "",
title: "",
liveIntroduce: "",
actor: "",
typeId: "",
isRecordedBroadcast: 2,
coverImage: "",
propagandaVideoUrl: "",
formingNum: "",
preSaleDeposit: "", //預(yù)售定金價(jià)格
preSaleBalance: "", //預(yù)售尾款價(jià)格
fullPayment: "", //全款價(jià)格
playbackPrice: "", //回放價(jià)格
preSale: [], //預(yù)售時(shí)間
preSaleStart: "",
preSaleEnd: "",
liveStart: "", //直播開(kāi)始時(shí)間
isSpeak: 1,
priority: "",
shareImage: ""
}
};
},
created() {
this.getLiveSell();
this.getData();
},
mounted() {},
components: {
vueVideoPlayers
},
methods: {
backPage() {
this.$router.push("/liveMange/largeBrand");
},
//售票情況
getLiveSell() {
var id = this.$route.params.id;
getLiveSellDetail(id).then(res => {
const result = res.data;
});
},
//彈框打開(kāi)看視頻
showVideo(playSrc, mark) {
this.videoVisible = true;
this.video = mark;
this.tempSrc = playSrc;
},
getData() {
var id = this.$route.params.id;
this.id = id;
//var localMatchTypeId=localStorage.getItem('matchTypeId')
//var localPriority = localStorage.getItem('priority')
// var data = { id, page: 1, limit: 10 };
getLiveDetail(id).then(res => {
const result = res.data;
//沒(méi)有分類(lèi)ID取本地
// if(!result.matchTypeId){
// result.matchTypeId = localMatchTypeId
// }
// if(!result.priority){
// result.priority = localPriority
// }
this.formData = result;
let { pullUrl, pushUrl, coverImage } = result;
this.src = pullUrl;
this.image = JSON.parse(coverImage)[0];
const {
id,
title,
liveStart,
ticketingStart,
playbackPrice,
preSaleDeposit,
preSaleBalance,
fullPayment
} = result;
const objData = {
id,
title,
name: "admin",
liveStart,
watchNumber: localStorage.getItem("watchNumber") | 0,
reserveNumber: localStorage.getItem("reserveNumber") | 0,
preSaleDeposit,
preSaleBalance,
fullPayment,
ticketingStart,
playbackPrice
};
this.list.push(objData);
// this.formData.registrationStart=result.registrationStart + ''
// this.formData.registrationEnd = result.registrationEnd + ''
// this.formData.voteStart = result.voteStart + ''
// this.formData.voteEnd = result.voteEnd + ''
//投票時(shí)段
// var preSaleStart = moment(parseInt(result.preSaleStart)).format(
// "YYYY-MM-DD hh:mm:ss:SSS"
// );
// var preSaleEnd = moment(parseInt(result.preSaleEnd)).format(
// "YYYY-MM-DD hh:mm:ss:SSS"
// );
//賽事結(jié)束時(shí)段
// this.formData.liveStart = new Date(result.liveStart);
//this.formData.registration.push(start)
//this.formData.registration.push(end)
//手動(dòng)賦值
// this.$set(this.formData, "preSale", [preSaleStart, preSaleEnd]);
//this.$set(this.formData, "vote", [voteStart, voteEnd]);
//日期格式化
//預(yù)售 時(shí)間段
this.formData.preSaleStart = result.preSaleStart
? timestampFormat(result.preSaleStart)
: "";
this.formData.preSaleEnd = result.preSaleEnd
? timestampFormat(result.preSaleEnd)
: "";
//非預(yù)售 開(kāi)始售票時(shí)間
this.formData.ticketingStart = result.ticketingStart
? timestampFormat(result.ticketingStart)
: "";
this.typeName = localStorage.getItem("typeName") || "";
});
}
}
};
</script>
<style scoped>
.playWrap {
display: flex;
background: #fff;
margin-top: 20px;
}
.leftInfo {
list-style: none;
border: 1px solid #cfcfcf;
}
.playLeft {
width: 48%;
/* border: 1px solid #f5f5f5; */
}
.playRight {
width: 48%;
margin-left: 2%;
}
.playItem {
display: flex;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #cfcfcf;
}
.playItem:last-child {
border-bottom: none;
}
.playContent {
margin-left: 20px;
color: #999;
}
.matchImg {
width: 80px;
height: 80px;
margin-right: 10px;
}
.playImage {
width: 80px;
height: 80px;
}
.playWrap {
display: flex;
}
.livePicture {
width: 40%;
height: 400px;
}
</style>
3:index.html記得加入如下代碼
<link rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.11.4/video.min.js"></script> <script src="https://player.live-video.net/1.4.0/amazon-ivs-videojs-tech.min.js"></script>
end
加油~~~~
到此這篇關(guān)于Vue實(shí)現(xiàn)直播功能的文章就介紹到這了,更多相關(guān)Vue實(shí)現(xiàn)直播內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue綁定class和綁定內(nèi)聯(lián)樣式的實(shí)現(xiàn)方法
本文主要介紹了Vue綁定class和綁定內(nèi)聯(lián)樣式的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
VSCode開(kāi)發(fā)UNI-APP 配置教程及插件
uni-app 是一個(gè)使用 Vue.js 開(kāi)發(fā)所有前端應(yīng)用的框架,今天通過(guò)本文給大家分享VSCode開(kāi)發(fā)UNI-APP 配置教程及插件推薦與注意事項(xiàng),感興趣的朋友一起看看吧2021-08-08
關(guān)于ElementPlus中的表單驗(yàn)證規(guī)則詳解
這篇文章主要介紹了關(guān)于ElementPlus中的表單驗(yàn)證,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
vue?select組件綁定的值為數(shù)字類(lèi)型遇到的問(wèn)題
這篇文章主要介紹了vue?select組件綁定的值為數(shù)字類(lèi)型遇到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Vue 使用formData方式向后臺(tái)發(fā)送數(shù)據(jù)的實(shí)現(xiàn)
這篇文章主要介紹了Vue 使用formData方式向后臺(tái)發(fā)送數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
關(guān)于Vue的?Vuex的4個(gè)輔助函數(shù)
這篇文章主要介紹了關(guān)于Vue的?Vuex的4個(gè)輔助函數(shù),輔助函數(shù)的好處就是幫助我們簡(jiǎn)化了獲取store中state、getter、mutation和action,下面我們一起來(lái)看看文章具體的舉例說(shuō)明吧,需要的小伙伴也可以參考一下2021-12-12
解決VUE mounted 鉤子函數(shù)執(zhí)行時(shí) img 未加載導(dǎo)致頁(yè)面布局的問(wèn)題
這篇文章主要介紹了解決VUE mounted 鉤子函數(shù)執(zhí)行時(shí) img 未加載導(dǎo)致頁(yè)面布局的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07

