官方文档:https://github.com/rrweb-io/rrweb/blob/master/guide.zh_CN.md
一、rrweb录屏
安装依赖:
npm install --save rrweb
组件代码:
<template>
<div></div>
</template>
<script>
import * as rrweb from "rrweb";
export default {
name: "HmRrwebRecord",
props: {
/**
* 保存接口
*/
url: {
type: String,
default: "",
},
/**
* 额外保存参数
*/
params: {
type: Object,
default: function () {
return {}
}
},
/**
* 最大操作次数
*/
maxCount: {
type: Number,
default: -1,
},
/**
* 保存频率(秒)
*/
cycle: {
type: Number,
default: 10,
},
/**
* 是否增量保存
*/
incremental: {
type: Boolean,
default: true
},
/**
* 页面切换是否停止
*/
routeStop: {
type: Boolean,
default: true
},
},
data() {
return {
cUrl: "",
cMaxCount: -1,
cCycle: 10,
cParams: {},
events: [],
cRouteStop:true,
};
},
watch: {
url(value) {
this.cUrl = value;
},
maxCount(value) {
this.cMaxCount = value;
},
cycle(value) {
this.cCycle = value;
},
params(value) {
this.cParams = value;
},
routeStop(value) {
this.cRouteStop = value;
},
},
mounted() {
this.cUrl = this.url;
this.cMaxCount = this.maxCount;
this.cCycle = this.cycle;
this.cParams = this.params;
this.cRouteStop = this.routeStop;
//开始录制
//this.start();
this.currentRoute = this.$route.path;
},
methods: {
start: function (e) {
let self = this;
self.stopFn = rrweb.record({
emit(event) {
if (self.cMaxCount && self.cMaxCount != -1 && self.events.length > self.cMaxCount) {
// 当事件数量大于 maxCount 时停止录制
self.stopFn();
}
// 将 event 存入 events 数组中
self.events.push(event);
},
packFn: rrweb.pack,//数据压缩
});
// 每 cycle 秒调用一次 save 方法
if (self.cCycle && self.cCycle != -1) {
//开启定时器存储
self.startSaveInterval();
}
/**
* 开始录制
* @params e
* @event start
*/
this.$emit("start", self.events);
},
stop: function (e) {
//停止录制
if (typeof this.stopFn === 'function') {
this.stopFn();
}
// 停止循环定时
clearInterval(this.recordInterval);
/**
* 停止录制
* @params e
* @event stop
*/
this.$emit("stop", this.events);
},
startSaveInterval: function(e){
let self = this;
//定时保存录屏数据
let time = self.cCycle * 1000;
self.recordInterval = setInterval(() => {
self.save();
}, time);
},
save: function (e) {
let self = this;
//console.log(self.currentRoute+" <---> "+self.$route.path);
//路由变化自动停止录屏,可防止其他页面也被录进去
if(self.cRouteStop && self.currentRoute != self.$route.path){
self.stop();
return;
}
if (!self.cUrl || self.cUrl == '' || self.events.length == 0) {
return;
}
let eventData = self.events;
//是否增量更新
if (self.incremental) {
self.events = [];
}
let params = { ...self.cParams, events: JSON.stringify(eventData) };
self.$postAction(self.cUrl, params).then((resp) => {
/**
* 保存录制数据
* @params e
* @event save
*/
self.$emit("save", self.events, resp);
//未授权时停止录屏
if(resp.code && resp.code == 401){
self.stop();
}
});
},
},
destroyed(e) {
// 停止循环定时
clearInterval(this.recordInterval);
},
};
</script>
<style scoped></style>
二、rrweb-player录屏播放器
安装依赖:
npm install --save rrweb-player
组件代码:
<template>
<div id="playback" class="player-body">
<div :class="cLoading?'spin-active':'spin-hide'">
<a-spin tip="Loading..." size="large" :spinning="cLoading" />
</div>
</div>
</template>
<script>
import * as rrweb from "rrweb";
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';
export default {
name: "HmRrwebPlayer",
props: {
/**
* 播放器配置
*/
config: {
type: Object,
default: function () {
return {
events: [],//包含回放所需的数据
width:1024,//播放器宽度
height:576,//播放器高度
autoPlay:true,//是否自动播放
mouseTail:false,//是否在回放时增加鼠标轨迹
speedOption: [1, 2, 5, 10],//倍速播放可选值
showController:true,//是否显示播放器控制 UI
}
}
},
/**
* loading
*/
loading: {
type: Boolean,
default: true
},
},
data() {
return {
replayer:null,
cConfig: [],
cLoading:true,
};
},
watch: {
config(value) {
this.cConfig = value;
},
loading(value) {
this.cLoading = value;
},
},
mounted() {
this.cConfig = this.config;
this.cLoading = this.loading;
},
methods: {
play: function (e) {
let self = this;
self.destroyPlayer();
//至少包含2个以上事件时为正常录屏数据
if(self.cConfig.events.length>2){
self.cLoading = false;
}
self.replayer = new rrwebPlayer({
target: document.getElementById("playback"),
// 配置项
props: {
...self.cConfig,
unpackFn: rrweb.unpack,//数据解压
},
});
/**
* 播放
* @params e
* @event play
*/
this.$emit("play", this.cEvents);
},
destroyPlayer: function (e) {
let self = this;
if(self.replayer){
// 假设rrwebPlayer元素的类名为"rr-player"
let rrwebPlayers = document.getElementsByClassName("rr-player");
// 从DOM中移除所有具有"rr-player"类名的rrwebPlayer元素
while (rrwebPlayers.length > 0) {
rrwebPlayers[0].parentNode.removeChild(rrwebPlayers[0]);
}
self.replayer =null;
}
}
},
};
</script>
<style scoped>
.player-body{
display: flex;
justify-content: center;
align-items: center;
}
.spin-active {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
z-index: 99999;
}
.spin-hide {
display: none;
}
</style>
三、使用示例
<template>
<div>
<HmRrwebRecord ref="hmRrwebRecord"></HmRrwebRecord>
<HmRrwebPlayer ref="hmRrwebPlayer"></HmRrwebPlayer>
<div>
<button type="primary" @click="count">点击计数器</button>
</div>
<div>计数:{{ sum }}</div>
<div>
<button type="primary" @click="start">开始录屏</button>
<button type="primary" @click="stop">停止录屏</button>
<button type="primary" @click="play">查看回放</button>
</div>
</div>
</template>
<script>
import HmRrwebRecord from '/@/components/rrweb/HmRrwebRecord.vue'
import HmRrwebPlayer from '/@/components/rrweb/HmRrwebPlayer.vue'
export default {
components: {
HmRrwebRecord,
HmRrwebPlayer
},
data() {
return {
sum: 0,
}
},
mounted() {
},
methods: {
count: function (e) {
this.sum++;
console.log(this.$refs.hmRrwebRecord.events)
},
start(){
this.$refs.hmRrwebRecord.start();
},
stop(){
this.$refs.hmRrwebRecord.stop();
},
play: function (e) {
this.$refs.hmRrwebPlayer.cConfig.events = this.$refs.hmRrwebRecord.events;
this.$refs.hmRrwebPlayer.play();
}
}
}
</script>
<style></style>