一、需求
对某个使用了Vue框架的页面,编写一些脚本操作修改DOM元素。需求之一就是监听URL地址变化,例如:从http://localhost:8080/#/abc
切换到http://localhost:8080/#/def
。URL有变化就触发执行某些操作。
二、问题
一般来说,监听window的hashchange
事件就可以了。例如:
window.onhashchange = function(event) {
// 当location变化时,这个函数会被调用
console.log("Location changed:", window.location.href);
};
当使用window.location.hash = path;
修改hash时,会触发。
但是用了Vue-router的网页就不一定行了。因为Vue的处理逻辑是:hash模式下符合条件时调用的实际上是pushState方法,而pushState和replaceState是无法触发onhashchange事件的,导致无法被监听到。
以下是Vue-router源码情况:
function pushState (url, replace) {
saveScrollPosition();
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
var history = window.history;
try {
if (replace) {
history.replaceState({ key: _key }, '', url);
} else {
_key = genKey();
history.pushState({ key: _key }, '', url);
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url);
}
}
...
function pushHash (path) { // this.$router.push时触发
if (supportsPushState) {
pushState(getUrl(path));
} else {
window.location.hash = path;
}
}
...
可以看到如果支持 pushState,就使用 pushState,而不是调用 window.location.hash = path;
解决方法
重写并覆盖原有的 pushState
和 replaceState
方法,然后手动触发 hashchange
事件。
// 保存原始的 pushState() 方法的引用
var historyPushState = history.pushState;
// 封装 pushState() 方法
function myPushState(state, title, url) {
// 调用原生的 pushState() 方法
historyPushState.call(history, state, title, url);
// 手动触发 hashchange 事件
console.log('由pushState()手动触发事件');
window.dispatchEvent(new HashChangeEvent("hashchange"));
}
// 重新定义 history.pushState() 方法
Object.defineProperty(history, 'pushState', {value: myPushState});
// 保存原始的 replaceState() 方法的引用
var historyReplaceState = history.replaceState;
// 封装 replaceState() 方法
function myReplaceState(state, title, url) {
// 调用原生的 replaceState() 方法
historyReplaceState.call(history, state, title, url);
// 手动触发 hashchange 事件
console.log('由replaceState()手动触发事件');
window.dispatchEvent(new HashChangeEvent("hashchange"));
}
// 重新定义 history.replaceState() 方法
Object.defineProperty(history, 'replaceState', {value: myReplaceState});
// 监听URL地址变化
window.onhashchange = function(event) {
// 当location变化时,这个函数会被调用
console.log("Location changed:", window.location.href);
};