最近把以前的业务场景及解决方案整理了一下,具体实现的工具如下:
监控-视频文件流==>video.js + videojs-contrib-hls
大屏适配方案==> v-scale-screen
websocket==>sockjs-client+ webstomp-client
视频监控-文件流
使用方法
下载video插件,
yarn add video.js -save -D 或者 npm i video.js -save -D
yarn add videojs-contrib-hls -save -D 或者 npm i videojs-contrib-hls -save -D
使用方法
(1)导入
//导入 css 与 videojs (可全局,可只在使用的页面)
import "video.js/dist/video-js.css";
import videojs from "video.js";
(2)模板中写入标签
<video ref="videoPlayer" style="width: 100%; height: 100%" class="video-js videoNmae"></video>
(3)页面渲染时调用函数,渲染视频
data(){
return {
optionc: {
autoplay: true,
controls: true,
muted: true,
sources: [
{
src: "视频地址",
type: "application/x-mpegURL", // 监控类直播视频流为此格式
// src: '',
// type: "video/mp4", // 本地video视频播放为此格式
},
],
},}
}
mounted() {
// 将方法包装成异步
this.$nextTick(() => {
setTimeout(() => {
this.playerd = videojs( // playerd 为data中的变量,初始值可设置为null
this.$refs.videoPlayer, // this.$refs.videoPlayer为放置视频的dom
this.options, // this.options为视频的配置,可根据官方文档自行配置,下面有我的配置项
function onPlayerReady() {
console.log("onPlayerReady", this);
}
);
this.playerda = videojs(
this.$refs.videoPlayera,
this.optionc,
function onPlayerReady() {
console.log("onPlayerReady", this);
}
);
});
})
}
// 定时器的清理
beforeDestroy() {
//clearInterval(this.int)
// var videoTime = document.getElementById("myvideo");
videoTime.pause();
}
optionc为视频的配置,具体其他配置可查看官网传送门
组件销毁时需要将视频的实例销毁,避免内存泄漏
大屏适配方案(v-scale-screen)
1、在项目初期,寻找大屏适配的方案,在比较多种方案后,决定使用v-scale-screen的方案,此插件根据CSS3的scale缩放功能对页面进行适配(不受浏览器缩放的影响)
缺点 : 页面尺寸过大时,开发时电脑屏幕无法看清楚细节,需要使用触控板进行放大
npm i v-scale-screen
// main.js中注册
import VScaleScreen from 'v-scale-screen';
Vue.component('v-scale-screen', {
name: 'v-scale-screen',
...VScaleScreen
});
Vue.use(VScaleScreen, {
designWidth: 750, // 设计稿宽度
designHeight: 1334, // 设计稿高度
});
// 使用
<v-scale-screen :size="size" :boxStyle="{background:'null'}" >
。。。。。。。
</v-scale-screen>
详情可见npm官网传送门
websocket前端
2.使用插件sockjs-client,webstomp-client(最后使用方案)
1.yarn add sockjs-client webstomp-client 或者 npm i sockjs-client webstomp-client
2.创建stomp.js文件
import SockJS from "sockjs-client";
import Stomp from "webstomp-client";
export class Websocket {
ar = new Array();
debug = false;
// 客户端连接信息
stompClient = {};
constructor() {
console.log("aaaaaaaaaa");
//首次使用构造器实例
if (!Websocket.instance) {
console.log("bbbbbbb");
this.init();
//将this挂载到Websocket这个类的instance属性上
Websocket.instance = this;
}
console.log("ccccc--->" + this.stompClient.connected);
return Websocket.instance;
}
getStompClient() {
return Websocket.instance.stompClient;
}
// 初始化
init(callBack) {
console.log("1111111111111=>", this.stompClient);
if (!this.stompClient.connected) {
console.log("222222");
const socket = new SockJS("https://sdd.cevmp.cn/wss/publicServer");//websocket请求地址
this.stompClient = Stomp.over(socket);
this.stompClient.hasDebug = this.debug;
this.stompClient.connect(
{},
(suce) => {
console.log("连接成功,信息如下 ↓");
while (this.ar.length > 0) {
let a = this.ar.pop();
// this.sub(a.addres, a.fun);
let timestamp = new Date().getTime() + a.address;
this.stompClient.subscribe(
a.addres,
(message) => {
//this.console(message, "message");
let data = JSON.parse(message.body);
console.log(
"000000000000000000000订阅消息通知,信息如下 000000000" +
a.addres
);
a.fun(data);
},
{
id: timestamp,
}
);
}
if (callBack) {
callBack();
}
},
(err) => {
if (err) {
console.log("连接失败,信息如下 ↓");
console.log(err);
}
}
);
} else {
if (callBack) {
console.log("已连接成功,无需重复创建===========================>");
callBack();
}
}
}
// 订阅
sub(address, callBack) {
console.log(address + "-->" + this.stompClient);
if (!this.stompClient.connected) {
this.ar.push({
addres: address,
fun: callBack,
});
console.log("没有连接,无法订阅", address);
this.reconnect(1);
return;
}
// 生成 id
let timestamp = new Date().getTime() + address;
console.log("订阅成功 -> " + address);
this.stompClient.subscribe(
address,
(message) => {
//this.console(message, "message");
let data = JSON.parse(message.body);
// console.log(data + " 订阅消息通知,信息如下 ↓↓↓↓↓↓↓");
callBack(data);
},
{
id: timestamp,
}
);
}
// 取消订阅
unSub(address) {
if (!this.stompClient.connected) {
console.log("没有连接,无法取消订阅 -> " + address);
return;
}
let id = "";
for (let item in this.stompClient.subscriptions) {
if (item.endsWith(address)) {
id = item;
break;
}
}
this.stompClient.unsubscribe(id);
console.log("取消订阅成功 -> id:" + id + " address:" + address);
}
// 断开连接
disconnect(callBack) {
if (!this.stompClient.connected) {
console.log("没有连接,无法断开连接");
return;
}
this.stompClient.disconnect(() => {
console.log("断开成功");
if (callBack) {
callBack();
}
});
}
// 单位 秒
reconnect(time) {
if (!this.stompClient.connected) {
console.log("连接丢失");
// console.log("重新连接中...");
//this.init();
}
}
console(msg) {
if (this.debug) {
console.log(msg);
}
}
}
3.使用方法
按需引入Websocket后,在mounted钩子里调用,使用new websocket().sub()方法 传入两个参数
第一个参数:数据格式为字符串,可传与后端约定好的标识,确定是进入的页面,推与之匹配的数据
第二个参数:传递一个函数,此函数的第一个参数即后端返回的数据
注意事项:工具函数内还有许多方法,比如取消订阅,可自行按需使用
优点:1.自动识别wss与https,ws与http的对应关系,无需再写 wss协议开头的地址 ; 2.websocket调试本地时只需更改工具函数内的地址
缺点:1.需要接入外部websocket时,由于没有与其约定,则需要使用原生格式
import { Websocket } from "@/utils/stomp";
mounted() {
let stomp = new Websocket();
// 初始化
// 初始化成功 就执行订阅
stomp.sub("/topic/orderlyCharger", (res) => {
console.log(res,"这个是后端推的数据"
);
});
},
取消订阅
beforeDestroy() {
let stomp = new Websocket();
stomp.unSub("/topic/publicCharger")
},
websocket页面之间的切换可能会造成数据污染,因此最好在组件销毁之前取消订阅
学习更多vue知识请关注CRMEB。