繁体   English   中英

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

[英]Not all inline JavaScript gets executed via 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功能,而不是其他? 你觉得这种加载脚本的方式有什么问题吗?

谢谢。

尽管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. 将它变成一个函数,所以所有代码都是作用域的
  2. 声明了与var使用的所有变量
  3. 使其传递给代码重用的参数
  4. 避免堆栈实际递归的累积
  5. 将一些重复引用放入局部变量中
  6. 使用Array.slice技巧进行数组复制
  7. 由于脚本标记只能有src=.innerHTML (不是两者),因此将其转换为if / else
  8. 将一些常见代码合并到一个地方
  9. .innerHTML切换到.textContent ,因为我们想要的只是文本

码:

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();
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM