并非所有内联JavaScript都通过AJAX执行

时间:2015-03-30 01:17:15

标签: javascript ajax

我正在通过AJAX加载文档的片段,并且我已经设法很好地加载了“外部”脚本,但是我无法执行<script>标记内的所有内联JavaScript。

以下是我正在尝试加载的文档片段/ HTML的示例:

    <textarea></textarea>
    <script src="tinyMCE.js" class="ajax-script"></script>
    <script class="ajax-script">
        alert("I'm inline");
        tinymce.init({
            selector: 'textarea',
        });
    </script>

以下是我用来加载此文档的JavaScript代码(在XHR status 200上):

    // * This response is HTML
    response = xhr.responseText;

    // * Set the innerHTML of the body to the response HTML
    document.body.innerHTML = response;

    // * Find all scripts with ajax-script class
    responseScripts = document.getElementsByClassName('ajax-script');

    // * Loop through all those scripts
    for (i = responseScripts.length; i--;) {

        // * Create a 'clone' script element
        cloneScript = document.createElement('script');

        // * If the response script has a src, add it to the clone
        if(responseScripts[0].src) {
            cloneScript.src = responseScripts[0].src;
        }

        // * If the response script has 'inline code', add it 
        if(responseScripts[0].innerHTML) {
            cloneScript.innerHTML = responseScripts[0].innerHTML;
        }

        // * Remove the original script
        responseScripts[0].parentNode.removeChild(responseScripts[0]);

        // * Append the clone script to the document
        document.body.appendChild(cloneScript);
    }

因此,在这个例子中,只有内联代码的alert("I'm inline");部分被执行,而其余部分则没有。没有控制台错误,没有什么,只是浏览器似乎忽略了tinymce.init()部分。

我不知道这是否与TinyMCE本身有关?但为什么会这样呢?我也试过评估代码,但没有运气。加载文档后,我可以复制tinymce.init()并将其粘贴到控制台中,文本编辑器实际显示(因为执行了tinymce.init())。

您是否有任何理由可以解释为什么只调用alert函数,而不是其他函数?你觉得这种加载脚本的方式有什么问题吗?

感谢。

3 个答案:

答案 0 :(得分:2)

尽管 David Water 的回复在Firefox中起到了作用,但它并不适用于Chrome。因此,通过遵循 jfriend 的建议,我将动态列表转换为数组,并确保脚本同步加载。这就是我的所作所为:

response = xhr.responseText;
document.body.innerHTML = response;
responseScripts = document.getElementsByClassName('ajax-script');
i = 0;
// * Convert DOM dynamic list into an array
function listToArray(list) {
  var array = [];
  for (var i = list.length >>> 0; i--;) { 
    array[i] = list[i];
  }
  return array;
}
function loadScripts() {
    if(responseScripts[i]) {
        cloneScript = document.createElement('script');
        if(responseScripts[i].src) {
            cloneScript.src = responseScripts[i].src;
        }
        if(responseScripts[i].innerHTML) {
            cloneScript.innerHTML = responseScripts[i].innerHTML;
        }
        responseScripts[i].parentNode.removeChild(responseScripts[i]);
        document.body.appendChild(cloneScript);
        if(cloneScript.src) {
            // * For external scripts, wait 'till they load
            cloneScript.onload = function () {
                loadScripts(i++);
            };
        } else {
            // * For inline scripts, just call the function again
            loadScripts(i++);
        }
    }
}
if(responseScripts.length > 0) {
    responseScripts = listToArray(responseScripts);
    // * Start loading the scripts
    loadScripts();
}

答案 1 :(得分:1)

这是你的答案中的一个清理版本的想法(来自我的评论)。以下是改进的部分清单:

  1. 将其变为一个函数,因此所有代码都是作用域的本地
  2. 声明与var
  3. 一起使用的所有变量
  4. 使用传入的代码重用参数
  5. 使其成为通用的
  6. 避免堆栈累积实际递归
  7. 将一些重复的引用放入局部变量
  8. 使用Array.slice技巧制作数组副本
  9. 由于脚本代码只能有src=.innerHTML(不是两者),因此将其设为if / else
  10. 将一些常用代码合并到一个地方
  11. .textContent切换到.innerHTML因为我们想要的只是文字
  12. 代码:

    function insertHtmlAndExecutescripts(elem, html, cls) {
        elem.innerHTML = html;
        // make actual array of all ajax-script tags
        var scripts = Array.prototype.slice.call(elem.getElementsByClassName(cls), 0);
        var i = 0;
    
        function loadScripts() {
            if (i < scripts.length) {
                var cloneScript = document.createElement('script');
                var tag = scripts[i++];
                if (tag.src) {
                    cloneScript.src = tag.src;
                    // * For external scripts, wait 'till they load
                    cloneScript.onload = function () {
                        loadScripts();
                    }
                    document.body.appendChild(cloneScript);
                } else if (tag.innerHTML) {
                    cloneScript.textContent = tag.textContent;
                    document.body.appendChild(cloneScript);
                    // avoid stack build-up of actual recursion
                    setTimeout(function() {
                        loadScripts();
                    }, 0);
                }
    
                // remove the original embedded script tag (this is likely not necessary)
                tag.parentNode.removeChild(tag);
            }
        }
        loadScripts();
    }
    

答案 2 :(得分:0)

尝试记录从responseScripts[0].innerHTML获取的内容,如果这是完整脚本,那么您只能eval结果。如果这只是第一行,那么你已经找到了问题所在。