问题背景
PM给客户演示产品时,经常需要动态删除页面上的logo等需求,为了方便PM自行搞定,不需要前端开发定制处理,给PM提供了油猴浏览器用户自定义脚本插件。前端开发提供脚本编写文档脚本。
脚本的实现逻辑:监听每次页面加载,或者跳转到一个新的页面时机,处理图片替换的逻辑。
常见的监听URL变化方式
1. hashchange 事件
最简单的方法之一是使用 hashchange 事件监听地址中的哈希部分变化。这适用于URL中带有#号的情况。
window.onhashchange=function(event){
console.log(event);
console.log('Hash changed:', window.location.hash);
}
//或者
window.addEventListener('hashchange', function(event) {
console.log(event);
console.log('Hash changed:', window.location.hash);
// 你可以在这里根据新的hash值来加载相应的内容
});
2. popstate 事件
每当激活同一文档中不同的历史记录条目时,popstate 事件就会在对应的 window 对象上触发。如果当前处于激活状态的历史记录条目是由 history.pushState() 方法创建的或者是由 history.replaceState() 方法修改的,则 popstate 事件的 state 属性包含了这个历史记录条目的 state 对象的一个拷贝。
通俗讲解: popState可以监听浏览器除了pushState、replaceState其他三个方法history.back()、history.forward()、history.go().
window.addEventListener('popstate', function(event) {
console.log('Location changed:', window.location.pathname);
// 根据新的路径加载相应的内容
});
注意事项
react-router 中navigate实现
源码
function useNavigateStable(): NavigateFunction {
let { router } = useDataRouterContext(DataRouterHook.UseNavigateStable);
let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
let activeRef = React.useRef(false);
useIsomorphicLayoutEffect(() => {
activeRef.current = true;
});
let navigate: NavigateFunction = React.useCallback(
(to: To | number, options: NavigateOptions = {}) => {
warning(activeRef.current, navigateEffectWarning);
// Short circuit here since if this happens on first render the navigate
// is useless because we haven't wired up our router subscriber yet
if (!activeRef.current) return;
if (typeof to === "number") {
router.navigate(to);
} else {
router.navigate(to, { fromRouteId: id, ...options });
}
},
[router, id]
);
return navigate;
}
上面的代码核心功能是router.navigate(to)这个方法。在 React Router 6 中,router.navigate 的实现主要依赖于 history 包来操作浏览器的历史记录,类似下面:
const router = {
navigate(to, options = {}) {
if (typeof to === 'number') {
history.go(to);
} else {
const { replace = false, state } = options;
if (replace) {
history.replace(to, state);
} else {
history.push(to, state);
}
}
}
};
也就是说navigate方法的修改的url地址的改变,其实主要用到history的replace和push两个方法,而这两个方法引起的更改popState是无法监听到的
监听navigate跳转的方式
const pushState = history.pushState;
const replaceState = history.replaceState;
// 重新监听浏览器地址改变,
history.pushState = function(state, title, url) {
// 执行相关的操作
return pushState.apply(history, arguments);
};
history.replaceState = function(state, title, url) {
// 执行相关的操作
return replaceState.apply(history, arguments);
};