Axure文件可以通过官方的文件导出成一个资源包,部署到服务器即可在web页面浏览。在web页面浏览的时候是以index.html文件为入口文件,iframe内嵌了一个子页面,通过hash参数来控制子页面的具体显示。
需求分析
- 需要将这个Axure的页面内嵌至另外一个项目的页面中
- 需要实现分页预览
内嵌页面选择通过iframe来实现,导致目前的页面层级结构比较复杂,一共有三个层级,嵌套了两层iframe框架,目前的难点是如何在外层监听Axure内部页面的变化。
--- 主站点
--- iframe Axure站点的入口页面
--- iframe Axure站点内嵌的子页面
方案思考
目前问题是如何捕捉到页面的变化,通过阅读Axure包体的源码,发现在以下目录有一个messagecenter.js文件,对目录的变化做了消息监听。
_messageCenter.dispatchMessageRecursively = function(message, data) {
console.log("dispatched to " + window.location.toString());
// dispatch to the top center first
_messageCenter.dispatchMessage(message, data);
$('iframe').each(function(index, frame) {
//try,catch to handle permissions error in FF when loading pages from another domain
try {
if (frame.contentWindow.$axure && frame.contentWindow.$axure.messageCenter) {
frame.contentWindow.$axure.messageCenter.dispatchMessageRecursively(message, data);
}
}catch(e) {}
});
};
于是我们找到了可以去捕获消息的来源,因为涉及到页面跨域,所以采用了PostMessage作为子页面向外层页面传输信息的工具,于是有以下两种方案
- 1,上传Axure包体的时候,使用修改过的messagecenter.js覆盖掉这个文件
- 2,上传Axure包体的时候,注入patch文件
考虑到以后可能还有其他需求或者bug修复,直接修改messagecenter.js会导致已经发布的项目需要重新上传,采取patch的方式更新,以后的修改可以同步到之前的项目,于是选择了第二种方案。
代码实现
// patch.js
;(function(){
// [202087 patch]
var oldConsole = console.log;
var lastSendHref = null
console.log = function(str){
var regStr = str.match(/dispatched\s+to\s+(.+)/);
var href = regStr && regStr[1]
if(lastSendHref !== href && /index.html/.test(href)){
top.postMessage({
href: href,
title: document.title
}, '*');
lastSendHref = href;
}
oldConsole(str);
}
})();
再上传Axure包体的时候只需要给index.html注入一个部署在CDN的patch脚本,通过复写console.log的方案,监听messagecenter.js内的打印消息,捕捉到消息之后通过PostMessage发送给外层。不直接去修改messagecenter.js原本的函数是为了遵循开发的原则,修改最小化。
外层的监听函数
window.addEventListener('message', function(event){
let { title = '', href = '' } = event.data || {};
// 接受到来自于iframe内嵌的网页修改
if(!/index\.html/.test(href)) return;
let childHash = href.split('index.html#')[1]
if(!childHash) return;
let nowHash = window.location.hash;
if(nowHash){
// 可能子目录切换,保持 id 之前的参数不变
nowHash = nowHash.split('&id')[0]
}
window.location.hash = nowHash + '&' + childHash
}, false)
这样就实现了外层监听Axure页面的页面变化