1、安装 video.js 和 videojs-contrib-hls 插件:
npm install video.js --save
vue3 暂时用不了
// npm install videojs-contrib-hls --save
// npm install @videojs/http-streaming --save
2、需要加载视频的页面
<template>
<div class="Camera" v-if="Camera">
<!-- id属性一定要配置,因为js初始化video.js 实例时,
会和这个dom进行绑定。通过video.js实例对象,来控制这个视频播放器。-->
<video
ref="video"
id="video"
class="video-js vjs-default-skin"
controls
width="400px"
height="400px"
object-fit:cover
preload="auto">
<source :src="videoUrl" type="application/x-mpegURL">
</video>
</div>
</template>
3.引入文件
<sctript>
import videojs from 'video.js' //是播放多种直播流类型的播放插件
import 'video.js/dist/video-js.min.css
vue3暂时用不了
// import 'videojs-contrib-hls' //负责播放 m3u8 格式的直播数据的插件,和viedeo.js搭配使用
// import "@videojs/http-streaming"//video.js获取直播流的插件, 和video.js搭配使用
</script>
4.直播
//1 声明 videoUrl 变量,保存 .m3u8 直播地址
const videoUrl = ref(“”);
let player = null;
//页面关闭 卸载组件
onUnmounted(()=>{
//当前组件被卸载的时候,要把播放器对象 player 也删除,
// 否则当前组件被卸载,但是 player播放器对象却没有被卸载,
// 导致下一次进入播放页面时,无法正常播放
player.dispose();
})
//进入页面 注册组件 需要用到声明周期
onMounted(()=>{
//获取直播间地址
getRealLive_Douyu(id,false,2,(liveUrl)=>{
//2.获取直播间链接地址,并赋值给videoUrl
vidoUrl.value = liveUrl;
//nextTick 页面加载完毕在加载里面内容
nextTick(()=>{
//3.当 videoUrl.value 直播地址所在的dom video 更新完毕之后,在实例化
// video.js 对象
//video("参数":是dom的id属性值,{配置})
player = videojs("video",{
autoplay:true,//true , 浏览器准备好开始播放
muted:false,//静音模式
loop:true,//导致视频一结束就重新开始
controls:true,//显示播放器
preload:"auto",//auto 浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language:'zh-CN',//汉化
bigPlayButton:false,//播放器中的播放按钮
controlBar:true,//显示视频控件
notSupportedMessage:'此视频暂无播放,请稍后再试'
})
})
})
})
5.直播弹幕
需要用到 websocket:双向通讯协议,一旦客户端和服务器建立链接,客户端可以给服务器发送消息,服务器也可以主动给客户端发消息。这个链接是长链接,一定时间不会断开。像斗鱼弹幕服务器约定45s断开;连接。防止两端断开链接,需要定时发送心跳包信息,只能客户端向服务器发送消息,服务器响应完数据以后,就断开链接了,是短连接
let timer = null;
//1.创建 websocket 对象
const ws = new WebSocket("wss://danmuproxy.douyu.com:8505/")
//2.监听 open 方法, 表示链接成功
ws.onopen = ()=>{
console.log("链接成功");
//获取弹幕流程
//2.1先向服务器发送登录的消息 (可参考斗鱼开发平台弹幕接口)
ws.send(
//必需要转为二进制
toBuffer(
`type@=loginreq/roomid@=${id}/username@=visitor7102488/
uid@=1198284824/
ver@=20190610/aver@=218101901/ct@=0/dfl@=/\0`
)
);
// 2.2 登录成功,在发送进入房间弹幕频道的消息给服务器
ws.send(toBuffer(`type@=joingroup/rid@=${id}/gid@=1/\0`));
//2.3 45s 心跳信息
timer = setInterval(()=>{
ws.send(toBuffer(`type@=mrkl/\0`));
},45000);
};
//3.监听 onmessage 方法,接收服务器数据
const danmulists = reactive([]);
const danmDom = ref(null);
ws.onmessage = async(data)=>{
//获取Blod的值,需要把二进制转为字符串
const text = await new Response(data.data).text();
console.log(text);
//3.1 从 text 中提取type的值,判断消息类型:uenter是新进直播间。chatmsg是弹幕消息
//.*?指的是任意字符 , 一直匹配到“/” 为止
const type = text.match(/tayp@=.*?\//)[0];
if(type.includes('uenter')){
//新进用户
let nn = text.match(/nn@=.*?\//)[0].split('=').replace('/','');
danmulists.push({
nn,
type:'uenter'
});
}else if(type.includes('chatmsg')){
//弹幕消息
let nn = text.match(/nn@=.*?\//)[0].split('=')[1].replace('/','');
let txt = text..match(/text@=.*?\//)[0].split('=')[1].replace('/','');
danmulists.push({
nn,
txt,
type:'chatmsg'
});
}
}
//4. 监听onclose方法,客户端服务器断开链接
ws.onclose = ()=>{
console.log('服务器断开');
}
//5.onerror 监听服务器异常
ws.onerror = ()=>{
console.log('服务器异常')
}
//页面关闭 卸载组件
onUnmounted(()=>{
clearInterval(timer);
ws.close();
})
最后全部代码部分
1.HTML部分
<template>
<!-- id 属性一定要配置,因为js初始化videojs实例时,会和这个dom进行绑定。通过video js 实例对象,来控制这个视频播放器 -->
<video
v-if="videoUrl"
ref="video"
id="video"
class="video-js vjs-default-skin"
controls
width="100vw"
height="400px"
object-fit:cover
preload="auto"
>
<source :src="videoUrl" type="application/x-mpegURL" />
</video>
<div class="danmu" ref="danmDom">
<div v-for="(danmu, index) in danmulists" :key="index">
<p v-if="danmu.type == 'uenter'" class="greet">
欢迎<span class="name1">{{ danmu.nn }}</span>
</p>
<p v-if="danmu.type == 'chatmsg'" class="news">
<span class="name2">{{ danmu.nn }}:</span><span class="txt">{{ danmu.txt }}</span>
</p>
</div>
</div>
</div>
</template>
2.JavaScript部分
<script setup>
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
//目标路由组件通过vue-router ;路由组合式api
import getRealLive_Douyu from '@/assets/斗鱼sign签名参数计算';
import toBuffer from '@/assets/斗鱼弹幕数据转换';
import { useRoute } from 'vue-router';
import videojs from 'video.js'; //是播放多种直播流类型的播放器插件
/* import 'videojs-contrib-hls'; //负责播放 m3u8 格式的直播数据插件,和videojs使用
import '@videojs/http-streaming'; //videojs获取直播流的插件*/
import 'video.js/dist/video-js.min.css';
const route = useRoute(); //返回值route是一个响应式对象Proxy,因此它也可以用watch监听。
const id = route.query.id; // 获取直播间id
// const data = await http(`/live/${id}/index.pageContext.json`);
//1.声明 videoUrl 变量,保存 .m3u8直播地址
const videoUrl = ref('');
let player = null;
let timer = null;
//卸载 组件
onUnmounted(() => {
//当前组件被卸载的时候,要把播放器对象 player 也删除,否则当前组件被卸载,但是 player 播放器对象却没有被卸载,导致下一次进入播放页面的时候,无法正常播放
player.dispose();
clearInterval(timer);
ws.close();
});
//注册组件
onMounted(() => {
//获取直播间链接地址。
getRealLive_Douyu(id, false, 2, (liveUrl) => {
//2.获取直播间链接地址,并赋值给videoUrl
videoUrl.value = liveUrl;
nextTick(() => {
//3.当 videoUrl.value 直播地址所在的dom video 更新完毕之后,在实例化vido.js 对象
//videojs("参数1":是dom的id属性值,{配置})
player = videojs('video', {
autoplay: true, //true,浏览器准备好时开始播放。
muted: false, //静音模式
loop: true, //导致视频一结束就重新开始。
controls: true, //显示播放器
preload: 'auto', //auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: 'zh-CN', //汉化
fluid: true, //当true时,
bigPlayButton: false, //播放器中的播放按钮
controlBar: true, //显示视频控件
notSupportedMessage: '此视频暂无法播放,请稍后再试'
});
});
});
});
//websocket:双向通讯协议,一旦客户端和服务器建立链接,客户端可以给服务器发送消息,服务器也可以主动给客户端发消息。这个链接是长链接,一定时间内不会断开。像斗鱼弹幕服务器约定45s断开链接。防止两端断开链接,需要定时发送心跳包消息,只能客服端向服务器发送消息,服务器响应完数据以后,就断开链接了。是短链接,
//1.创建websocket对象
const ws = new WebSocket('wss://danmuproxy.douyu.com:8505/');
//2.监听open方法,表示链接成功
ws.onopen = () => {
console.log('链接成功');
//获取弹幕数据流程
//2.1先向服务器发送登录的消息
ws.send(
toBuffer(
`type@=loginreq/roomid@=${id}/username@=visitor7102488/uid@=1198284824/ver@=20190610/aver@=218101901/ct@=0/dfl@=/\0`
)
);
//2.2登录成功,在发送进入房间弹幕频道的消息给服务器
ws.send(toBuffer(`type@=joingroup/rid@=${id}/gid@=1/\0`));
//2.3 45s心跳消息
timer = setInterval(() => {
ws.send(toBuffer(`type@=mrkl/\0`));
}, 45000);
};
//3. 监听 onmessage方法,接收服务器的数据
const danmulists = reactive([]);
const danmDom = ref(null);
ws.onmessage = async (data) => {
//获取Blod的值
const text = await new Response(data.data).text();
console.log(text);
//3.1 从text 中提取type的值,判断消息类型:uenter是新进直播间。chatmsg是弹幕消息
const type = text.match(/type@=(.*?)\//)[0];
if (type.includes('uenter')) {
//新进用户
let nn = text
.match(/nn@=.*?\//)[0]
.split('=')[1]
.replace('/', '');
danmulists.push({
nn,
type: 'uenter'
});
} else if (type.includes('chatmsg')) {
//是弹幕消息
let nn = text
.match(/nn@=.*?\//)[0]
.split('=')[1]
.replace('/', '');
let txt = text
.match(/txt@=.*?\//)[0]
.split('=')[1]
.replace('/', '');
danmulists.push({
nn,
txt,
type: 'chatmsg'
});
}
//3.2 当弹幕列表可以滚动的时候,让弹幕div自动滚动到底部
danmDom.value.scrollTop = danmDom.value.scrollHeight - danmDom.value.clientHeight;
};
//4. 监听onclose方法,客户端服务器断开链接
//5. onerror,监听服务器一次
ws.onerror = () => {
console.log('服务器异常');
};
</script>
3. CSS部分
<style lang="less" scoped>
*{
margin: 0;
padding: 0;
}
.live {
background-color: #181315;
height: 98vh;
}
.danmu {
height: 67%;
overflow-y: scroll;
p{
background-color: rgba(0, 0, 0, 0.5);
}
.greet {
font-size: 3.46667vw;
font-weight: 400;
margin: 0.8vw 0;
padding: 0.8vw 2.13333vw;
word-wrap: break-word;
border-radius: 2.66667vw;
max-width: 75.33333vw;
color: #fff;
.name1 {
color: #ff921c;
margin-left: 1.33333vw;
opacity: 1;
}
}
.news {
font-size: 3.46667vw;
margin: 0.8vw 0;
padding: 0.8vw 2.13333vw;
word-wrap: break-word;
border-radius: 2.66667vw;
max-width: 75.33333vw;
width: -moz-fit-content;
width: fit-content;
word-break: break-all;
color: #fff;
.name2 {
color: #999;
}
.txt {
padding-left: 2vw;
}
}
}
</style>
运行结果
注:由于一些直播类开放平台不支持个体验用户注册 无法正常获取直播或弹幕 此文章只提供参考。