前端录制回放rrweb

news2024/11/24 7:43:09

rrweb 是 ‘record and replay the web’ 的简写,旨在利用现代浏览器所提供的强大 API 录制并回放任意 web 界面中的用户操作。

rrweb中文文档 https://github.com/rrweb-io/rrweb/blob/master/guide.zh_CN.md
本文项目地址 https://github.com/qdfudimo/vue-rrweb 大家点个星

demo介绍

该项目分为客户端服务端

  1. 客户端 vue3 cd ./rrweb-client 执行 pnpm dev
  2. 服务端使用 node 通过上传的json数据保存在本地文件中,在调用接口的时候再读取文件内容返回给后台 cd ./rrweb-serve 执行 pnpm dev

在这里插入图片描述

rrweb 介绍

rrweb 主要由 3 部分组成:

  • rrweb-snapshot,包含 snapshot 和 rebuild 两个功能。snapshot 用于将 DOM 及其状态转化为可序列化的数据结构并添加唯一标识;rebuild 则是将 snapshot 记录的数据结构重建为对应的 DOM。
  • rrweb,包含 record 和 replay 两个功能。record 用于记录 DOM 中的所有变更(mutation);replay 则是将记录的变更按照对应的时间一一重放。
  • rrweb-player,为 rrweb 提供一套 UI 控件,提供基于 GUI 的暂停、快进、拖拽至任意时间点播放等功能。

使用指南

直接通过 <script> 引入

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>

通过 npm 引入

npm install --save rrweb rrweb-player

rrweb 同时提供 commonJS 和 ES modules 两种格式的打包文件,易于和常见的打包工具配合使用。

兼容性

由于使用 MutationObserver API,rrweb 不支持 IE11 以下的浏览器。可以从这里找到兼容的浏览器列表。

隐私

页面中可能存在一些隐私相关的内容不希望被录制,rrweb 为此做了以下支持:

  • 在 HTML 元素中添加类名 .rr-block 将会避免该元素及其子元素被录制,回放时取而代之的是一个同等宽高的占位元素。
  • 在 HTML 元素中添加类名 .rr-ignore 将会避免录制该元素的输入事件。
  • 所有带有.rr-mask类名的元素及其子元素的 text 内容将会被屏蔽。
  • input[type="password"] 类型的密码输入框默认不会录制输入事件。
  • 配置中还有更为丰富的隐私保护选项。

快速开始

<template>
  <div id="replay" ref="replay" v-if="isPlaying" />
  <textarea placeholder-class="textarea-placeholder" />
  <button type="button" @click="handelStart">开始录制</button>
  <button type="button" @click="handelPasue">暂停</button>
  <button type="button" @click="handelRecord">回放</button>
  <button type="button" @click="handelReRecord">网络回放</button>
  <button type="button" @click="handelRequest">请求</button>
  <button type="button" @click="handelPayStart">支付开始</button>
  <button type="button" @click="handelPayEnd">支付结束</button>
  <div class="modal rr-mask" v-if="isRecording">正在录制</div>
</template>

录制

如果通过 <script> 的方式仅引入录制部分,那么可以访问到全局变量 rrwebRecord,它和全量引入时的 rrweb.record 使用方式完全一致,以下示例代码将使用后者。

import * as rrweb from 'rrweb';
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';
import { ref, onUnmounted } from 'vue';
import axios from "axios";
const events = ref([])
const replay = ref()
/**是否正在回放 */
const isPlaying = ref(false)
/**是否正在录制 */
const isRecording = ref(false)
let stopFn = null
let replayInstance = null;
const handelStart = () => {
  isPlaying.value = false;
  isRecording.value = true;
  events.value = []
  stopFn = rrweb.record({
    emit(event) {
      // 用任意方式存储 event
      events.value.push(event)
      // 以 rrwebEvents 的长度作为分片持续上传 防止数据过大
      if (events.value.length >= 100) {
        //超过100 上传给后台 同时重置为空
        uploadFile()
        events.value = []
      }
    },
  });
}

rrweb 在录制时会不断将各类 event 传递给配置的 emit 方法,你可以使用任何方式存储这些 event 以便之后回放。

调用 record 方法将返回一个函数,调用该函数可以终止录制:

停止录制

/**let stopFn = rrweb.record({
  emit(event) {
    if (events.length > 100) {
      // 当事件数量大于 100 时停止录制
      stopFn();
    }
  },
}); */
/**暂停录屏且上传 */
const handelPasue = () => {
  isRecording.value = false
  stopFn()
  if (events.value.length === 0) return
  uploadFile();
  events.value = []
}

上传数据

/**
 *  压缩 events 数据,并上传至后端
 *用于将 events 发送至后端存入,并重置 events 数组
 */
const uploadFile = () => {
  console.log("上传快照了");
  axios('/apis/uploadFile', {
    method: 'post',
    headers: {
      'Content-type': 'application/json'
    },
    data: JSON.stringify({
      events: events.value
    })
  })
    .then(response => {
      console.log('response', response)
    })
    .catch(error => {
      console.log('error', error)
    })
}

回放

npm install --save rrweb-player
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';
使用

通过 props 传入 events 数据及配置项

/**new rrwebPlayer({
  target: document.body, // 可以自定义 DOM 元素
  // 配置项
  props: {
    events,
  },
}); */
const handelRecord = () => {
  if (isRecording.value) {
    console.log("请先暂停录制");
    return
  }
  isPlaying.value = true
  //vue异步更新 为了获取到replay dom
  setTimeout(() => {
    replayInstance = new rrwebPlayer({
      target: replay.value, // 可以自定义 DOM 元素
      // 配置项
      props: {
        events: events.value,
        skipInactive:false,	//是否快速跳过无用户操作的阶段
        showDebug: false, //是否在回放过程中打印 debug 信息
        showWarning: false, //是否在回放过程中打印警告信息
        autoPlay: true, //是否自动播放
        showControlle :true,//是否显示播放器控制 UI
        speedOption:[1, 2, 4, 8] //倍速播放可选值
      },
    });
    replayInstance.addEventListener("finish", (payload) => {
      console.log(payload,2222);
    })
  }, 100);
}

请求后台数据

/**网络请求回放 */
const handelReRecord = () => {
  axios('/apis/getFile', {
    method: 'post'
  })
    .then(res => {
      if (res.data.code == 200) {
        let { data = [] } = res.data
        if (data.length) {
          events.value = data;
          // replayInstance.destroy()
          // replayInstance = null
          handelRecord()
        }
      }
    })
    .catch(error => {
      console.log('error', error)
    })
}

vite配置跨域

 server: {
    proxy: { // 跨域代理
      '/apis': {
        // target: 'http://' + env.VUE_APP_BASE_API,
        target: 'http://localhost:3000/', // 
        changeOrigin: true,
        logLevel: 'debug',
        rewrite: (path) => path.replace(/^\/apis/, '')
      },
    },
  }

node服务端

pnpm i express body-parser
const express = require("express")
const bodyParser = require('body-parser')
const fs = require('fs')
const path = require('path')
const app = express()
app.use(bodyParser.urlencoded({
    extended: false
}))
app.use(bodyParser.json())
app.post("/uploadFile",(req,res)=>{
    console.log(req.body,11);
    const jsonFile = path.join(process.cwd(), `./file/jsonFile${Date.now()}.json`)
    fs.writeFileSync(jsonFile, JSON.stringify(req.body.events))
    res.send({
        data:"",
        msg:"上传成功",
        code:200
    })
})
app.post("/getFile",(req,res)=>{
    const fileDirPath = path.join(process.cwd(), `./file`);
    const files = fs.readdirSync(fileDirPath);
    console.log(files);
    let file;
    if(files && files.length) {
        file = fs.readFileSync(`${fileDirPath}/${files[files.length-1]}`); // 此处只取第一个文件片段验证
    }
    res.send({
        data:JSON.parse(file),
        msg:"上传成功",
        code:200
    })
})
// 清理文件内容
app.post('/clearFile', ctx => {
    const fileDirPath = path.join(process.cwd(), `./file`);
    const files = fs.readdirSync(fileDirPath);
    if(files && files.length) {
        files.forEach(item => {
            const filePath = `${fileDirPath}/${item}`;
            fs.unlinkSync(filePath);
        })
    }
    ctx.response.body = {
        status: '00'
    }
})
app.get("/count",(req,res)=>{
    res.send("1111")
})
// 2. 设置请求对应的处理函数
//    当客户端以 GET 方法请求 / 的时候就会调用第二个参数:请求处理函数
app.get('/', (req, res) => {
  res.send('hello world')
})
 
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/622495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网安学习|Kail安全渗透测试系统之【前期信息收集】工具实践学习

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; “ 花开堪折直须折&#xff0c;莫待无花空折枝。 ” 作者主页&#xff1a;[ https://www.weiyigeek.top ] 博客&…

达梦数据库与MySQL的区别及语法差异

达梦数据库与MySQL的区别及其SQL语句对比 简介&#xff1a;正文&#xff1a;1. 达梦数据库和MySQL的概述2. 特点对比3. SQL语句对比1. 数据类型&#xff1a;2. 语法&#xff1a;1. DDL&#xff08;数据定义语言&#xff09;的差异&#xff1a;2. DML&#xff08;数据操作语言&a…

面向对象——多态、抽象类、接口

学习资料来自&#xff1a;黑马程序员&#xff0c;内容仅为学习记录&#xff0c;侵删 多态 多态&#xff1a;事务存在的多种形态 多态的前提&#xff1a;1、有继承关系&#xff1b;2、重写父类方法&#xff1b;3、父类引用指向子类对象 面向对象 面向对象多态中成员访问特点…

动态测试数据处理

分类 动态测试数据&#xff1a; 1、确定性数据&#xff1a;能够用明确的数学表达式进行描述的数据称为确定性数据。 Ⅰ、周期数据 Ⅱ、非周期数据 2、随机性数据&#xff1a;无法用明确的数学表达式表述&#xff1b;若在一个…

强大的工具:APISpace IP归属地查询API

引言 IP地址在互联网世界中扮演着重要的角色&#xff0c;对于许多应用程序和服务来说&#xff0c;了解IP地址的归属地信息可以提供有价值的洞察和功能。 在本文中&#xff0c;我们将介绍一种名为IP归属地-IPv4区县级 API 的强大工具&#xff0c;它提供了查询 IP 地址归属地信…

如何解释物联网IOT平台?

物联网开发的本质是将各种物品通过网络连接在一起&#xff0c;并对这些物品进行数字化管理&#xff0c;从而实现智能自动化。在物联网的早期阶段&#xff0c;一些物联网应用程序&#xff08;例如&#xff0c;智能电表&#xff09;使用软件将信息传输到后台服务器。但随着时间的…

华为路由器:多区域OSPF协议实验

一、实验拓扑 二、ospf基本概念复习 区域划分&#xff1a;area0为骨干区域&#xff0c;其他area1、area2都为普通区域/常规区域。普通区域必须和骨干区域直接相连。ABR&#xff1a;区域边界路由器。R2、R3位于两个区域的中间&#xff0c;我们称之为区域边界路由器 &#xff1b…

ObjectARX如何监控实体双击事件(利用钩子函数或者反应器)

目录 1 实现方法1——钩子函数1.1 钩子函数的作用1.2 利用钩子函数监控双击事件 2 实现方法2——反应器2.1 反应器的作用2.2 利用编辑器反应器监控双击事件 在ObjectARX开发中&#xff0c;常常要监控鼠标的双击事件&#xff0c;比如&#xff0c;往一个实体中写了扩展数据&#…

基于html+css的图展示115

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

2023年湖北下半年中级职称申报中级职称评审申报条件是什么?

2023年湖北下半年中级职称申报中级职称评审申报条件是什么&#xff1f; 2023年湖北中级职称申报条件&#xff1a;本科毕业5年&#xff0c;专科毕业7年&#xff0c;相关专业 助工满4年这个条件目前不是硬性要求&#xff0c;意思就是有肯定更好&#xff0c;没有也没有太大的影响 …

穿越火线几次体验良好的游戏优化方案

文章目录 介绍救世主模式终结者模式30人生化模式挑战模式英雄级武器源武器英雄级武器皮肤英雄级武器游戏玩偶英雄级武器万化包、光效英雄级武器强化英雄级武器音效卡免费获取挑战强化武器戒指击杀效果个人竞技击杀效果人机训练模式交易所火线币快速加入跳跳乐爆头战HS间谍模式地…

做了一个日内信号可视化系统

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 大家好&#xff0c;半年过去了。松鼠Quant计划6月内发布本年度最重要的一个策略:盘口策略。这个策略群友们的呼声很高&#xff0c;也是花了比较多时间去弄。整个策略有多个python脚本: CTP数据生成order…

如何提高浪涌保护器的使用寿命和安全性

浪涌保护是保护设施免受电气事件影响的基本要求。具体来说&#xff0c;浪涌保护器&#xff08;SPD&#xff09;旨在限制瞬态电压并转移浪涌电流以保护系统和设备。 SPD浪涌保护器必须考虑的一种现象是临时过电压&#xff08;TOV&#xff09;。传统设备处理 TOV 的方式可能会导…

【unity数据持久化】游戏排行榜信息简单的存储,你还知道吗?数据管理类_PlayerPrfs

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

谈一谈冷门的C语言爬虫

C语言可以用来编写爬虫程序&#xff0c;但是相对于其他编程语言&#xff0c;C语言的爬虫开发可能会更加复杂和繁琐。因为C语言本身并没有提供现成的爬虫框架和库&#xff0c;需要自己编写网络请求、HTML解析等功能。 不过&#xff0c;如果你对C语言比较熟悉&#xff0c;也可以…

FPGA认识-LCMXO3LF-9400C-5BG400C 什么是低功耗FPGA

莱迪思深力科超低密度FPGA 是最新的立即启用、非挥发性、小型覆盖区 FPGA&#xff0c;采用先进的封装技术&#xff0c;能让每个元件达到最低成本。此系列采用最新的小型封装&#xff0c;不仅具有低功率、成本优势并结合快速效能。FPGA 现场可编程逻辑器件,小尺寸&#xff0c;高…

SSRS rdlc报表 八 报表项目部署

开发环境 vs2022 sqlserver 2019 windows 11 参考文档&#xff1a;安装 SQL Server Reporting Services - SQL Server Reporting Services (SSRS) | Microsoft Learn 配置 URL (Configuration Manager) - SQL Server Reporting Services (SSRS) | Microsoft Learn 项目右键…

问道价值互联网,区块链的下一个十年 | 2023 开放原子全球开源峰会区块链分论坛即将启幕

随着全球 Web3 浪潮经由数字藏品、元宇宙的日渐普及而实现落地&#xff0c;区块链在“信息互联网”转向“价值互联网”中的重要作用正得到进一步认可。在数字经济蓬勃发展、数据成为重要生产要素的时代&#xff0c;区块链已不仅仅是一项技术、一种工具&#xff0c;更是一种思维…

大型城市综合体建筑智能消防应急照明和疏散系统的具体应用 安科瑞 许敏

摘要&#xff1a;随着我国社会经济的迅猛发展与城市化建设进程的加快&#xff0c;大型城市综合体建筑越来越多&#xff0c;随之而来的消防安全管理问题不容忽视。智能消防应急照明和疏散系统作为保证人员安全疏散不可或缺的消防设施&#xff0c;是保障消防安全的重要组成部分。…

重磅!MyBatis-Plus 可视化代码生成器来啦,开发效率提升2倍 !!

前言 一、mybatis-plus-generator-ui是什么&#xff1f; 二、 mybatis-plus-generator-ui怎么用&#xff1f; 1、maven pom引入2、新建程序入口&#xff0c;以main函数的方式运行3、实例运行 三、mybatis-plus-generator-ui代码生成 1、Table的查询和浏览2、输出配置3、策…