美文网首页
如何使用rrweb 做一个录屏系统?

如何使用rrweb 做一个录屏系统?

作者: 前端蜗牛老师 | 来源:发表于2021-10-12 17:29 被阅读0次

    背景:最近在做一个保险的项目 监管要求,需要对用户操作进行录屏保存。市面上有的录屏系统太大,收费的,也挺贵,大概20-30万左右,还不包括存储硬件资源,果断选择自己开发/
    技术实现:使用rrweb + pako.js 压缩文件
    技术架构: C端录制(vue+rrweb+pako.js) + java+磁盘存储 + 后端系统配置录制页面及展示视频

    具体代码写起来也不麻烦,关键是如果封装,我使用的是rrweb结合 vue插件开发一套录屏系统

    核心插件部分
    vsr.js

    import {checkRecording, setValue} from "../../api"; // 判断是否录屏后台配置那个页面需要录屏,保存数据接口
    import router from '../../router' // 引入router 
    import Cookies from 'js-cookie' 
    import md5 from 'js-md5'; // md5加密
    import {rrWebZip} from "../../utils"; // 压缩工具函数
    class vsr {
      constructor() {
        // this.operation = null;
        // this.url = ''
        // this.timer = null
        // this.needRecord = false
        // this.events = [];
      }
    
      async vsrInit() {
        let events = []; // 定义一个空数组,保存录屏数据
        let _this = this
    
        rrweb.record({
          emit(event) {
            events.push(event);
          },
          sampling: {
            // 不录制鼠标移动事件
            // mousemove: false,
            // 不录制鼠标交互事件
            // mouseInteraction: false,
            // 设置滚动事件的触发频率
            scroll: 200, // 每 200ms 最多触发一次
            // 设置输入事件的录制时机
            // input: 'last', // 连续输入时,只录制最终值
            MouseUp: false,
            MouseDown: false,
            // Click: false,
            ContextMenu: false,
            // DblClick: false,
            // Focus: false,
            // Blur: false,
            // TouchStart: false,
            // TouchEnd: false,
          },
          inlineStylesheet: true,
          slimDOMOptions: {
            svg: true,
            script: true,
            comment: true,
            headFavicon: true,
            headWhitespace: true,
            headMetaDescKeywords: true,
            headMetaSocial: true,
            headMetaRobots: true,
            headMetaHttpEquiv: true,
            headMetaAuthorship: true,
            headMetaVerification: true,
          },
          packFn: rrweb.pack, // 压缩算法
          // recordLog: true
          // checkoutEveryNth: 200, // 每 200 个 event 重新制作快照
        });
    
        // save 函数用于将 events 发送至后端存入,并重置 events 数组
        async function save() {
          const timestamp = new Date().getTime()
          let body = ''
          if (events.length > 0) {
            // console.log(JSON.stringify(events), 'JSON.stringify(events)')
            // console.log(rrWebZip(JSON.stringify(events)), 'rrWebZip(JSON.stringify(events)')
            body =  timestamp + md5(timestamp + 'zbkl') + rrWebZip(JSON.stringify(events)) // 压缩传输
            events = [] // 每次调保存接口,立即清空当前录屏数据,保证每次保存为最新数据
            await setValue(body);
          }
        }
    
    
        router.beforeEach(async (to, from, next) => { // 监听页面跳转,即调是否录屏接口
          let url = _this.getDomain() + '/#' + to.path
          const timestamp = new Date().getTime()
          if(to.name === 'Insure' || to.name === 'PayWay' || to.name === 'Succeed' || to.name === 'PayError' || to.name === 'Payment' || to.name === 'Renewal') {
            let result = await checkRecording({
              "startTime": timestamp,
              "url": url,
              'agentID': to.query && to.query.agentID
            })
            if (result.result && result.result.needRecord) {
              Cookies.set('zbklTrackMark', result.result && result.result.eventsId, 'Infinity')
              save()
              if(to.name === 'Succeed' || to.name === 'PayError' || to.name === 'Payment') {
                setTimeout(() => {
                  save()
                },2000)
              }
              this.timeSave = _this.throttling(save, 1000, true); //函数节流,保证每秒只调一次接口,以节省请求次数,减少带宽
              if(!result.result.isEndPage) {
                window.addEventListener('touchend', this.timeSave, false) // 移动端事件,点击事件结束即调板寸接口
              }else {
                window.removeEventListener('touchend', this.timeSave, false)
              }
            }else {
              window.removeEventListener('touchend', this.timeSave, false)
            }
          }else {
            events = []
            window.removeEventListener('touchend', this.timeSave, false)
          }
          next()
        })
      }
    
      throttling (fn, wait, immediate) {
        let timer;
        let context, args;
    
        let run = () => {
          timer=setTimeout(()=>{
            if(!immediate){
              fn.apply(context,args);
            }
            clearTimeout(timer);
            timer=null;
          },wait);
        }
    
        return function () {
          context=this;
          args=arguments;
          if(!timer){
            if(immediate){
              fn.apply(context,args);
            }
            run();
          }
        }
      }
    
      getDomain() { // 获取当前页面域名加页面路由名称,不带参数
        let url = window.location.href
        return url.split('://')[1].split('/#/')[0]
      }
    
    }
    
    export default vsr;
    
    

    index.js

    import Router from "../../router";
    import vsr from "./vsr";
    
    // const vsrKey = function (val) {
    //   !sessionStorage.getItem('vsrKey') && sessionStorage.setItem('vsrKey', val)
    // }
    
    // 设置一个时间,长时间停留在页面上,请求发送取消
    // const vsrKeyTime = function () {
    //   let nowTime = new Date().getTime()
    //   !sessionStorage.getItem('vsrKeyTime') && sessionStorage.setItem('vsrKeyTime', nowTime)
    // }
    // vsrKeyTime()
    
    const vsrOpt = function (opt = {
      whiteList: [],
      version: '1.0.0'
    }) {
      const VSR = new vsr(opt);
      VSR.vsrInit();
    }
    
    const install = function(Vue) {
      Vue.use(Router);
    };
    
    
    
    if (typeof window !== "undefined" && window.Vue) {
      install(window.Vue);
    }
    
    export default {
      install,
      vsrOpt,
      // vsrKey
    };
    
    

    代码
    import VueScreenRecord from "./components/vue-screen-record";

    if(finishTime() > 0) {
    // VueScreenRecord.vsrOpt()
    // Vue.use(VueScreenRecord);
    }

    直接引用即可实现,前端的录制。

    剩下的就是后端保存了,然后需要B端配置需要录屏的页面,及回放了。

    相关文章

      网友评论

          本文标题:如何使用rrweb 做一个录屏系统?

          本文链接:https://www.haomeiwen.com/subject/uofjoltx.html