前台跨域调用js函数.

最近遇到一个问题,页面上嵌入的一个表单需要调用页面上的一个函数,因为表单是由表单系统提供的,所以他们不在一个域名下。

稍微查找了一下,这种一般是用 iframe 大法,因为虽然说是跨域,但其实浏览器的内部实现里还是有部分属性可以调用到的,其中window.parent , window.top,window.frames 之类 ,而如果这些window对象的 domain 如果是相同的,你就可以调用其中的方法了,所以根据这个思想,我写了一个比较通用的页面来实现。

不过可能有些童鞋不清楚这个 iframe大法具体怎么用,这里简要介绍一下。

假设一个场景,你的页面是d1/main.htm, 上面嵌入了一个第三方地图,比如就叫 d2/map.htm吧,main 上面有一个输入框,你输入了一个地方,map就会自动跳转到那个位置,这里使用的是 d2/map.htm 上的 move('place'); 这个js方法。

如果你试图通过获取 iframeMap.contentWindow.move(''),浏览器会告诉你,跨域了,无法调用。 这时候怎么办呢,首先,让d2提供一个 d2/func.htm, 内容如下   

<script>

window.parent.move(param(place)); // 这里的 window.parent 是有问题的,不要吐槽了,举个例子而已 ^_^

</script>

然后在 main.htm 上弄一个隐藏的 iframeFunc ,然后 function move() { iframeFunc.src = 'd2/func.htm?place=place'; },  这样,iframeFunc 载入的时候就会调用d2/map.htm 上的  move 方法了,iframe大法完成。

所以,这个通用页面只是处理一下这里的 window.parent 这个问题。

首先,func.htm 里面的 window.parent 是跨域的父页面。 而实际要调用的函数就不知道在哪个页面上了,所以虽然说是通用,其实还是无法考虑到全面,这里只查找window.parent.parent... 和 window.parent.frames... 这些.

上源码:

<script type="text/javascript">  
// 参数说明
// page 要调用函数的页面地址 a.html 
// func 要调用的函数名称
// params 经过编码的字符串,调用函数的参数,多参数请自行修改

var url = window.location.href; 
var paraString = url.substring(url.indexOf("?")+1,url.length).split("&"); 
var paraObj = {};
for (i=0; j=paraString[i]; i++){ 
    paraObj[j.substring(0,j.indexOf("=")).toLowerCase()] = j.substring(j.indexOf("=")+1,j.length); 
} 

if (paraObj['func'] && paraObj['page']) {

    function func_run(win, flag, url, params, defRun) {
        try {
            var hasRun = false;
            if (flag) {
                hasRun = win.func_flag && flag == win.func_flag;  
            } 
            if (url && !hasRun) {
                hasRun = win.location.pathname.indexOf(url) > -1;
            } 
    
            if (hasRun) {
                var jsStr = 'parent.' + paraObj['func'] + '("' + params + '");';
                eval(jsStr);
            }
            
            return hasRun;
        } catch (e) {
            return false;
        }
    }
    
    var parentTemp = window.parent;
    var targetPage = paraObj['page'];
    var hasRun = false;
    var params = paraObj['params'];
    var last = null;
    
    while (parentTemp) {
        if (hasRun) break;
        if (last != parentTemp)
            last = parentTemp;
        else 
            break;
        
        try {
            hasRun = parentTemp.location.pathname.indexOf(targetPage) > -1; 
            if (hasRun) {
                var js = 'parentTemp.' + paraObj['func'] + ((params) ? '(' + params + ');' : '();');
                eval(js);
                break;
            }
        } catch (e) {
        }
            
        if (!hasRun) {
            for (var i = 0; i < parentTemp.frames.length; ++i) {
                try {
                    var temp = parentTemp.frames[i].contentWindow;
                    hasRun = temp.location.pathname.indexOf(targetPage) > -1;
                    if (hasRun) {
                        var js = 'parentTemp.' + paraObj['func'] + ((params) ? '(' + params + ');' : '();');
                        eval(js);
                        break;
                    }
                } catch (e) {
                }
            }
        }
        parentTemp = parentTemp.parent;
    }
}

</script>  

其实本来是可以进行进一步的扩展的,首先是添加一个参数, flag ,而不是用页面的地址,在页面上预定义一个变量,如

window.func_flag = ‘1’; 而调用 c.html 的时候加上 func_flag=1, 这样只会对func_flag=1的页面进行调用。

另外params多参数。

还有run=once/all 这样,对 flag 和 page 之类的是只调用一次,还是对所有的页面调用,想了一下午,脑袋都炸了,不写那么多了。

OVER.

 

后续:

后来在实验中发现,表单页面不让添加iframe,所以上面的方法就悲剧掉了。所以使用了 postMessage大法。

在调用的时候

var msg = {};

msg.event = 'newPage';

msg.url = 'http://www.cnblogs.com/willin';

var msgJson = '({"event":"'+msg.event+'","url":,"'+msg.url+'"})'

parent.parent.postMessage(msg, '*'); // 这个后面的 ‘*’ 是指传入的页面地址。如 cnblogs.com,这样,如果parent.parent 不是 cnblogs.com 就不会触发。

在cnblogs.com 这个页面上加入

if (window.addEventListener)

window.addEventListener('message', function(event){

var data = eval(event.data);

if (data.event == 'newPage') { 

window.addTab(data.url);

}

}, false);

 在现代浏览器上都是可行的,据说IE7及一下不行,唉,还好XP下还是能用IE8的。 真希望IE6和7早点去死掉啊。

 

posted @ 2013-03-31 18:31  张鲸落  阅读(826)  评论(0编辑  收藏  举报