• Javascript动态执行问题浅析


    现在web2.0/ajax大行其道,我们会经常碰到这种应用case:前端浏览器通过ajax发请求到后端,后端生成html代码返回,前端接收后将html代码插入一个div容器内。这个应用很普遍,一般情况下也不会有什么问题,特别是返回的是单纯的数据的情况下。但如果返回的html代码包含javascript函数或是css style定义,哪可能就会出现问题了。特别是在IE浏览器下(由此看出,IE浏览器真是垃圾!!真是WEB程序开发者的噩梦啊。),Javascript动态执行的问题很突出。相对来说,Firefox支持的较好。 

    下面是一段示例代码: 
    __cb_render : function( containerId, htmlContent ) 

        var oDiv = document.getElementById( containerId ); 
        while( oDiv.childNodes.length > 0 ) 
        { 
            oDiv.removeChild( oDiv.firstChild ); 
        } 

        try 
        { 
            var container = document.createElement( "div" ); 
            container.innerHTML = htmlContent; 
            oDiv.appendChild( container ); 
        } 
        catch ( error ) 
        { 
            // ignore exception 
        } 


    这段代码很简单,将soap返回的html代码插入到页面的一个Div容器里。在firefox里执行,okay,一切都没问题。html代码里的Javascript也能正确得以执行。但在IE浏览器里,很抱歉,一堆问题就来了。 

    首先,如果返回的html代码以<script开头,哪IE浏览器会直接忽略这些Javascript片断(很奇怪吧,你可以试试。)。而且,中间的Javascript代码根本得不到正确执行,还有就是采用<script src="test.js"/>这种方式引入Javascript函数,也无法成功。 

    所以,对IE浏览器,我们就需要采取一些特殊的解决方案。有一种解决方案,是强行在每个script tag中添加一个属性<script defer="true"......。Defer属性是指浏览器先load完所有html代码,然后去执行相应的Javascript函数。这种解决方案,一般情况下也能得到正确的结果。但笔者并不推荐,尽量少用defer属性。 

    以下是另一可行的解决方案,也经过了多种主流浏览器的测试。 
    __cb_render : function( containerId, htmlContent ) 

        var oDiv = document.getElementById( containerId ); 
        while( oDiv.childNodes.length > 0 ) 
        { 
            oDiv.removeChild( oDiv.firstChild ); 
        } 

        if( BrowserUtility.isIE( ) ) 
        { 
           // 在html代码开头添加一段空白代码,主要是为了解决script放在开头而被IE忽略的问题 
            htmlContent = '<span style="display: none">&nbsp;</span>' + htmlContent; 
           // 去掉html代码中script tag的defer属性,防止函数被执行两次 
            htmlContent = htmlContent .replace(/<script(.*)defer([^\s|^>]*)([^>]*)>/gi,'<script$1$3>'); 
        }

        try 
        { 
            // 先将新的节点append到DOM中 
            var container = document.createElement( "div" ); 
           container.innerHTML = htmlContent; 
           oDiv.appendChild( container ); 
        } 
        catch ( error ) 
        { 
            // ignore exception 
        } 

        var scripts = container.getElementsByTagName( "script" ); 
        for( var i = 0; i < scripts.length; i++ ) 
        { 
            if( scripts[i].src ) 
            {
                // 添加script src到head中 
                  if( BrowserUtility.isIE( ) ) 
                { 
                    var scriptObj = document.createElement( "script" ); 
                    scriptObj.setAttribute( "type", "text/javascript" ); 
                    scriptObj.setAttribute( "src", scripts[i].src ); 

                    var head = document.getElementsByTagName( "head" )[0]; 
                    if( head ) 
                        head.appendChild( scriptObj ); 
                }
            } 
            else if ( scripts[i].innerHTML ) 
            {     
                 //  IE支持该方法去动态执行javascript代码 
                 if ( window.execScript ) 
                   window.execScript( scripts[i].innerHTML ); 
            } 
        } 

        // 如果是safari或是KHTML浏览器,需要将html代码中包含的css style代码显示的append到head中。 
        if ( BrowserUtility.isSafari() || BrowserUtility.isKHTML() ) 
        { 
            var styles = container.getElementsByTagName("style"); 
            for ( var i = 0; i < styles.length; i++ ) 
            { 
                var styleContent = styles[i].innerHTML; 
                if ( styleContent ) 
                { 
                    var element = document.createElement("style"); 
                    element.type = "text/css"; 
                    if ( element.styleSheet ) 
                    { 
                        element.styleSheet.cssText = styleContent; 
                    } 
                    else 
                    { 
                        element.appendChild( document.createTextNode( styleContent ) ); 
                    } 

                    var head = document.getElementsByTagName( "head" )[0];
                    if( head ) 
                    { 
                        head.appendChild( element ); 
                    }        
                } 
            } 
        } 


    以上代码中,还有一点要注意的,就是一定先要将container节点append到DOM中,也就是一定要先落地。不然,在javascript执行顺序上会有些问题的。 

    好了,就到这吧。搞WEB开发,真是很烦啊!!!
  • 相关阅读:
    30网络通信之多线程
    U盘自动拷贝
    多态原理探究
    应用安全
    应用安全
    编码表/转义字符/进制转换
    代码审计
    文件上传
    渗透测试-Web安全-SSRF
    中间人攻击
  • 原文地址:https://www.cnblogs.com/zzh/p/1345884.html
Copyright © 2020-2023  润新知