zoukankan      html  css  js  c++  java
  • 前台跨域调用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早点去死掉啊。

  • 相关阅读:
    股票数据可视化
    试下代码高亮
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第3节:Spark架构设计(2)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第3节:Spark架构设计(1)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第2节:Spark架构设计(2)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第2节:Spark架构设计(1)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第1节:为什么Spark是大数据必然的现在和未来?(2)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第1节:为什么Spark是大数据必然的现在和未来?(1)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第2章动手实战Scala第3小节:动手实战Scala函数式编程(2)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第2章动手实战Scala第3小节:动手实战Scala函数式编程(1)
  • 原文地址:https://www.cnblogs.com/willin/p/2991986.html
Copyright © 2011-2022 走看看