目录
首先!埋点和监控是有区别的 !
什么是埋点?
定义:
前端埋点指的是在前端代码中,通过埋入特定的事件监听和数据采集代码,来跟踪用户在网站或应用上的各种行为,如点击、页面浏览、输入等。埋点数据通常会被上报到后台,用于后续的分析和优化。
前端埋点的作用:
-
用户行为分析:通过埋点数据,分析用户如何与应用交互,例如:点击了哪些按钮、浏览了哪些页面、提交了哪些表单等。
-
产品优化:通过了解用户的行为路径和操作习惯,帮助产品团队优化用户体验、调整功能设计、提升转化率。
-
营销效果评估:帮助营销团队评估广告、促销活动等的效果,比如广告点击率、活动参与度、用户转化等。
-
A/B 测试:收集不同版本页面的用户行为数据,比较不同版本之间的表现差异,帮助决策优化。
前端埋点的实现方式:
-
手动埋点:开发人员在代码中明确指定哪些行为需要收集和上报。
-
可视化埋点:通过可视化工具,前端开发无需修改代码,直接在页面元素上配置需要跟踪的事件。
-
无埋点:通过自动化工具,捕获所有的用户操作数据,无需开发人员手动指定。
用户行为(埋点)
1.首先创一个空react框架
npx create-react-app user-behavior-tracker
cd user-behavior-tracker
npm start
2. 设计行为埋点
我们将通过以下几个常见行为来进行数据收集:
-
点击事件:用户点击按钮或链接。
-
滚动事件:用户滚动页面时。
-
页面加载事件:用户加载页面时。
-
输入事件:用户在表单输入框中输入数据。
-
页面停留时间:用户在页面上的停留时长。
3. 实现埋点逻辑
在 src
目录下,我们可以创建一个新的文件 trackEvents.js
来处理事件收集。
// 节流函数:防止事件过于频繁触发
const throttle = (func, delay) => {
let lastTime = 0; // 记录上次执行时间
return function (...args) {
const now = Date.now(); // 获取当前时间
if (now - lastTime >= delay) { // 如果当前时间与上次执行时间的差值大于等于指定的延迟时间
func(...args); // 执行传入的函数
lastTime = now; // 更新最后一次执行时间
}
};
};
// 事件追踪函数:负责将事件数据记录并输出
export const trackEvent = (eventType, data) => {
const eventData = {
eventType, // 事件类型(例如:点击、滚动等)
timestamp: new Date().toISOString(), // 事件发生的时间,采用 ISO 格式
...data, // 扩展其它事件数据(例如:页面地址、滚动位置等)
};
console.log("Event Data: ", eventData); // 输出事件数据(可以在控制台查看)
// 如果需要将事件数据发送到后端接口(例如进行数据分析),可以解除注释并配置 API
// fetch('/api/track', { method: 'POST', body: JSON.stringify(eventData) });
};
// 页面加载事件追踪
export const trackPageLoad = () => {
const startTime = Date.now(); // 页面加载时记录开始时间
trackEvent('PAGE_LOAD', {
url: window.location.href, // 当前页面的 URL
referrer: document.referrer, // 页面来源(即从哪个页面跳转过来)
userAgent: navigator.userAgent, // 浏览器的用户代理信息(包含操作系统、浏览器类型等)
});
// 页面卸载时追踪停留时间
window.addEventListener('beforeunload', () => {
const endTime = Date.now(); // 页面离开时记录结束时间
const stayTime = endTime - startTime; // 计算停留时间(单位:毫秒)
trackPageStayTime(stayTime); // 调用追踪停留时间的函数
});
};
// 页面停留时间追踪
export const trackPageStayTime = (stayTime) => {
trackEvent('PAGE_STAY_TIME', {
stayTime, // 页面停留的时长
});
console.log(`Page Stay Time: ${stayTime} ms`); // 在控制台输出页面停留时间
};
// 点击事件追踪
export const trackClick = (event) => {
const target = event.target; // 获取事件的目标元素(即点击的 DOM 元素)
if (target && target.nodeName) { // 如果目标元素存在且是有效的 DOM 元素
trackEvent('CLICK', {
targetType: target.nodeName, // 目标元素的标签名(例如:BUTTON、DIV 等)
targetId: target.id, // 目标元素的 ID(如果有)
targetClass: target.className, // 目标元素的类名(如果有)
pageX: event.pageX, // 鼠标点击时的横坐标
pageY: event.pageY, // 鼠标点击时的纵坐标
});
} else {
console.error("Error: event.target is undefined or null", event); // 如果目标元素无效,打印错误信息
}
};
// 滚动事件追踪
export const trackScroll = () => {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 获取当前页面滚动的距离
trackEvent('SCROLL', {
scrollTop, // 记录滚动的距离
});
};
// 输入框事件追踪
export const trackInput = (event) => {
const inputElement = event.target; // 获取事件目标元素(输入框)
if (inputElement) { // 如果输入框存在
trackEvent('INPUT', {
inputType: inputElement.type, // 输入框的类型(例如:text、password 等)
inputValue: inputElement.value, // 输入框当前的值
inputId: inputElement.id, // 输入框的 ID(如果有)
});
}
};
// 搜索事件追踪
export const trackSearch = (searchQuery) => {
trackEvent('SEARCH', {
searchQuery, // 记录搜索的关键字或查询内容
});
};
// 使用节流来限制滚动事件触发频率,设置为每 1000 毫秒触发一次
export const trackScrollWithThrottle = throttle(trackScroll, 1000);
// 启动页面加载时的追踪
trackPageLoad();
在 src
目录下,我们可以创建一个新的文件 Home.js
来处理事件收集。
import React, { useEffect, useState } from "react";
import { trackPageLoad, trackClick, trackScrollWithThrottle, trackInput, trackPageStayTime, trackSearch } from './trackEvents';
const Home = () => {
const [startTime, setStartTime] = useState(null);
const [searchQuery, setSearchQuery] = useState(""); // 用于存储搜索框的内容
// 页面加载时,收集数据
useEffect(() => {
const loadTime = Date.now();
setStartTime(loadTime);
trackPageLoad(); // 只在页面加载时执行一次
// 页面滚动监控
const scrollHandler = () => {
trackScrollWithThrottle(); // 使用节流后的滚动事件
};
window.addEventListener("scroll", scrollHandler);
// 页面卸载时,记录离开时间并计算页面停留时间
const unloadHandler = () => {
const unloadTime = Date.now();
trackPageStayTime(loadTime, unloadTime); // 计算停留时间
};
window.addEventListener("unload", unloadHandler);
// 清理事件监听器
return () => {
window.removeEventListener("scroll", scrollHandler);
window.removeEventListener("unload", unloadHandler);
};
}, []); // 确保此处依赖项是空数组,表示只在组件加载时执行一次
// 输入框事件
const handleInputChange = (event) => {
setSearchQuery(event.target.value); // 更新搜索框的内容
trackInput(event);
};
// 搜索按钮点击事件
const handleSearchClick = () => {
trackSearch(searchQuery); // 记录最终的搜索内容
console.log("搜索内容:", searchQuery); // 你也可以在这里进行搜索操作
};
// 按钮点击事件
const handleButtonClick = (event) => {
trackClick(event); // 传递原生事件对象
};
return (
<div style={{ padding: "20px" }}>
<h1>用户行为追踪</h1>
<button id="myButton" onClick={handleButtonClick}>
点击我
</button>
<div style={{ marginTop: "20px" }}>
<label htmlFor="inputField">请输入内容:</label>
<input
id="inputField"
type="text"
onChange={handleInputChange} // 捕获输入框变化
placeholder="输入一些内容"
/>
<button onClick={handleSearchClick}>搜索</button> {/* 点击搜索时触发 */}
</div>
<div style={{ marginTop: "20px" }}>
<p>请滚动页面,行为会被追踪...</p>
<div style={{ height: "1500px", backgroundColor: "#f0f0f0" }}>
<p style={{ paddingTop: "500px" }}>滚动到底部,查看滚动行为追踪</p>
</div>
</div>
</div>
);
};
export default Home;
页面和效果:
什么是监控?
定义:
前端监控是指在前端应用中,通过采集和分析应用性能、错误信息、资源加载情况等数据,来监控应用的健康状态和用户体验。它主要关注系统的运行状况、性能瓶颈、错误信息等,确保前端应用的稳定性和流畅性。
前端监控的作用:
-
错误监控:捕获和记录前端的 JavaScript 错误、网络请求失败、资源加载错误等异常情况,帮助开发团队及时发现和修复问题。
-
性能监控:监控页面加载时间、资源请求速度、用户交互响应速度等,识别并优化性能瓶颈,提高用户体验。
-
用户体验监控:通过捕获页面加载时间、错误堆栈、资源失败等问题,帮助团队理解用户在应用中遇到的困难和不流畅的地方。
-
网络请求监控:记录和分析 API 请求的成功率、响应时间等,确保后端接口的稳定性,及时发现接口性能问题或错误。
前端监控的实现方式:
-
错误上报:使用
try-catch
语句、全局事件监听、Promise 错误捕获等方式,捕获和上报 JavaScript 错误。 -
性能指标:通过
performance API
或第三方库(如Web Vitals
)监控页面加载时间、白屏时间、可交互时间等指标。 -
网络请求监控:捕获并分析 HTTP 请求的成功率、响应时间、错误信息等。
js错误总结图:
监控代码实现
目录:
/vue-error-monitor
├── /node_modules
├── /public
│ └── index.html
├── /src
│ ├── /assets
│ ├── /components
│ ├── /views
│ ├── App.vue
│ ├── main.js
│ ├── style.css
└── package.json
main.js文件
import { createApp } from 'vue';
import App from './App.vue';
import axios from 'axios';
const app = createApp(App);
// 1. 捕获全局 JavaScript 错误
window.addEventListener('error', function (e) {
console.error('捕获到全局 JavaScript 错误:', e.message);
}, true);
// 2. 捕获未处理的 Promise 错误
window.addEventListener('unhandledrejection', function (e) {
console.error('捕获到未处理的 Promise 错误:', e.reason);
}, true);
// 3. 捕获资源加载失败(如图片、JS、CSS)
window.addEventListener('error', function (e) {
if (e.target instanceof HTMLImageElement) {
console.error('图片加载失败:', e.target.src);
} else if (e.target instanceof HTMLScriptElement) {
console.error('JavaScript 文件加载失败:', e.target.src);
} else if (e.target instanceof HTMLLinkElement && e.target.rel === 'stylesheet') {
console.error('CSS 文件加载失败:', e.target.href);
}
}, true);
// 4. 捕获 axios 请求错误
axios.interceptors.response.use(
response => response,
error => {
if (error.response) {
console.error('后端接口错误:', error.response.status, error.response.data);
} else if (error.request) {
console.error('请求路径错误,未收到响应:', error.request);
} else {
console.error('请求错误:', error.message);
}
return Promise.reject(error);
}
);
window.onerror = function (message, source, lineno, colno, error) {
console.error('浏览器兼容性错误:', message);
console.error('发生错误的脚本:', source);
console.error('发生错误的行号:', lineno);
console.error('错误详情:', error);
// 记录到 localStorage 或上报后端
localStorage.setItem('compatibilityError', JSON.stringify({
message,
source,
lineno,
colno,
error
}));
return true; // 防止浏览器默认错误提示
};
app.mount('#app');
App.js文件:
<template>
<div id="app">
<button @click="throwError">抛出组件内错误</button>
</div>
</template>
<script>
export default {
methods: {
throwError() {
// 模拟一个组件内部的错误
throw new Error('这是组件内的错误');
}
},
// errorCaptured(err, vm, info) {
// console.error('捕获到组件错误:', err.message);
// console.error('组件信息:', vm.$options.name);
// console.error('错误信息:', info);
// // 记录到 localStorage 或上报后端
// localStorage.setItem('componentError', JSON.stringify({
// message: err.message,
// stack: err.stack || '未知',
// component: vm.$options.name,
// info
// }));
// return false; // 阻止错误继续向上传播
// }
}
</script>