Closed Hilshire closed 4 years ago
先说一下场景,使用iframe嵌入单页应用(hash模式),当iframe中的页面发生变化的时候,需要父页面的菜单跟着变化。因此,直观的需要知道子页面的url发生变化。
iframe
hash
由于是单页应用,onload显然是不好使的。一个很容易想到的方法是使用 onhashchange,这样就来到了我们这次问题的中心:如果你尝试一下,就会发现,vue的hash改变不是每次都会触发hashchange事件的——准确来说,通过push的更改的路由是不会触发hashchange的。vue-router 底层调用的是history.pushState和history.replaceState, 这2个api对url的更新不限于hash, 不会触发hashchange。
onload
onhashchange
vue
hashchange
push
vue-router
history.pushState
history.replaceState
如果是普通的vue项目,可以通过使用watch监听$route来解决这个问题。但是对于iframe我不是很想做出这样强侵入性的改动,更别说他还要我和父页面交互。
watch
$route
但是我们依然可以做一些事情: How to get notified about changes of the history via history.pushState?
(function(history){ var pushState = history.pushState; history.pushState = function(state) { if (typeof history.onpushstate == "function") { history.onpushstate({state: state}); } // ... whatever else you want to do // maybe call onhashchange e.handler return pushState.apply(history, arguments); }; })(window.history); window.onpopstate = history.onpushstate = function(e) { ... }
onpopstate的业务范围很狭窄,只处理游览器动作,或者history.back(), history.forward()。 经过处理之后,它就可以监听到push发生的变化。
onpopstate
history.back()
history.forward()
看到上面的代码好像问题已经解决了——且慢!这里有一个前提。我的系统 iframe 是跨域的,而iframe 一旦跨域,那么父页面就无法对子页面做什么,就只能看看而已了。
好在我 iframe 的页面主域名相同,可以简单的用 document.domain 解决
document.domain
其实这个问题是我的场景下需要嵌入的系统比较多,不然可以简单的用 postMessage 解决,根本不用纠结这么多。
postMessage
感谢!这个重写 history.pushState 的方法解决了我的问题
先说一下场景,使用
iframe
嵌入单页应用(hash
模式),当iframe
中的页面发生变化的时候,需要父页面的菜单跟着变化。因此,直观的需要知道子页面的url发生变化。由于是单页应用,
onload
显然是不好使的。一个很容易想到的方法是使用onhashchange
,这样就来到了我们这次问题的中心:如果你尝试一下,就会发现,vue
的hash
改变不是每次都会触发hashchange
事件的——准确来说,通过push
的更改的路由是不会触发hashchange
的。vue-router
底层调用的是history.pushState
和history.replaceState
, 这2个api对url的更新不限于hash, 不会触发hashchange
。如果是普通的
vue
项目,可以通过使用watch
监听$route
来解决这个问题。但是对于iframe
我不是很想做出这样强侵入性的改动,更别说他还要我和父页面交互。但是我们依然可以做一些事情: How to get notified about changes of the history via history.pushState?
onpopstate
的业务范围很狭窄,只处理游览器动作,或者history.back()
,history.forward()
。 经过处理之后,它就可以监听到push
发生的变化。看到上面的代码好像问题已经解决了——且慢!这里有一个前提。我的系统
iframe
是跨域的,而iframe
一旦跨域,那么父页面就无法对子页面做什么,就只能看看而已了。好在我
iframe
的页面主域名相同,可以简单的用document.domain
解决其实这个问题是我的场景下需要嵌入的系统比较多,不然可以简单的用
postMessage
解决,根本不用纠结这么多。