参考:斗鱼开放平台 Websocket:双向通讯协议,一段客户端和服务器建立连接客户端可以给服务器发消息,服务器也可以给客户端发消息。这个链接是长连接,一定时间内不会断开。斗鱼弹幕服务器约定45s断开。 防止两端断开,需要定时发送心跳包消息。(每隔45s) http:单项通讯协议,只能客户端向服务器发送消息,服务器响应完数据就断开连接。是短连接,下次需要数据重新建立连接。
获取弹幕数据
创建websocket对象 连接弹幕接口,获取弹幕 Const ws= new Websocket(“wss://xxxx.xxx.com”) websocket类型的数据接口都是ws、wss监听open方法,便是连接成功 ws.onopen=()=>{ ws.send( ) //先向服务器发送登录请求。send内部发送的是二进制数据,如果需要的话,封装一个转化为二进制的方法 ws.send( ) // 登录成功后,再发送进入弹幕频道的消息给服务器 setInterval(()=>{ws.send(toBuffer(‘type@=joingroup/rid=${}/gid@=1/\0’)},45000)//每隔45s发送心跳消息 }监听onmessage方法,接收服务器的数据 ws.onmessage=()=>{}onclose 监听客户端服务器断开连接onerror 监听服务器异常 注意:在页面卸载的时候销毁定时器,关闭与弹幕服务器的连接,clearInterval(),ws.close() 发送的是二进制信息,获取到的也是二进制信息(弹幕信息是文本显示,可以提取文本)
展示弹幕数据
根据弹幕的类型,判断是用户进入消息、弹幕消息、礼物消息 从获取到的弹幕消息中截取type值,使用条件语句判断类型对弹幕消息进行整理,比如用户进入直播间消息对象{type:uenter,nn:‘用户昵称’},弹幕消息{type:chatmsg,nn:‘用户名称’,txt:‘消息内容’} const type=text.match(/type@=.?//)[0](表示从type@=开始,提取任意字符串.?,直到/结束)将不断获取到的新数据。Push到一个数组中。数据提取完成后就可以进行渲染,根据条件渲染,设置弹幕样式给弹幕盒子设置一个固定的高度,溢出设置为滚动overflow-y:scroll 注意:当弹幕超过盒子高度的时候,设置自动滚动到底部
欢迎
{{ danmu.nn }}
{{ danmu.nn }} :
{{ danmu.txt }}
import { reactive } from "vue";
import getRealLive_Douyu from "@/assets/斗鱼sign签名参数计算"
import { useRoute } from "vue-router"
// import http from "@/utils/http"
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import videojs from 'video.js' //播放多种直播流类型视频的播放器插件
// import 'videojs-contrib-hls'//播放m3u8格式的直播流视频的插件,和video.js搭配使用
// import "@videojs/http-streaming"//video.js获取直播流的插件
import 'video.js/dist/video-js.min.css'
import toBuffer from "@/assets/斗鱼弹幕数据转换";
const route = useRoute();
const id = route.query.id;
//声明videoUrl变量,保存.m3u8直播地址
const videoUrl = ref("")
// const data=await http(`/live/${id}/index.pageContext.json`)
console.log(route, id);
//获取直播间链接地址
let player = null;
let timer = null;
onMounted(() => {
getRealLive_Douyu(id, false, 2, (liveUrl) => {
// console.log(liveUrl);
videoUrl.value = liveUrl//直播间链接地址big赋值给videoUrl
//3. 当videoUrl.value直播地址所在的dom更新完毕之后,在实例化videojs对象。
nextTick(() => {//组件挂载完毕后执行videojs函数第一个参数为dom的id,第二个参数是一些配置对象,第三个参数为回调函数,咱执行完后播放
player = videojs("video", {
bigPlayButton: true,
controlBar: true,//显示视频控件暂停开始之类
fluid: true,
muted: true,//开启静音模式
notSupportedMessage: '此视频暂无法播放,请稍后再试'
});
})
})
});
onUnmounted(() => {
//当前组件卸载后,把player播放器也卸载,否则会报错
player.dispose()//销毁播放器
clearInterval(timer)//清除定时器
ws.close()//关闭与弹幕服务器的连接
});
//websocket:双向通讯协议,一旦客户端和服务器建立连接,客户端可以给服务器发送消息,服务器也可以主动给客户端发送消息。这个链接是长连接,一定时间内不会断开。
//防止连接断开,需要定时发送心跳包(发送间隔和约定的断开时间一致)
//1. 创建websocket对象
const ws = new WebSocket("wss://danmuproxy.douyu.com:8504/");
//监听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)
}
//监听onmessage方法,接受服务器的数据
const danmulists = reactive([]);
const danmuDom = ref(null)
ws.onmessage = async (data) => {
const text = await new Response(data.data).text()
// console.log("收到弹幕数据", text);
//从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,
type: "chatmsg",
txt,
})
}
// console.log(danmulists)
//当弹幕列表可以滚动的时候,让弹幕自动滚动到底部
danmuDom.value.scrollTop = danmuDom.value.scrollHeight - danmuDom.value.clientHeight;
}
//监听onclose方法,客户端服务器断开连接
// ws.onclose=(data)=>{
// console.log("收到弹幕数据",data);
// }
//onerror,监听服务器异常
ws.onerror = () => {
console.log("服务器异常");
}
.lives {
background: #000;
height: calc(100vh)
}
.danmu {
height: 80vh;
overflow-y: scroll;
p {
font-size: 12px;
padding: 5px;
}
}