我想在网页中动态地包括一个脚本标签,但我无法控制它的src,所以src="source.js"可能看起来像这样。

document.write('<script type="text/javascript">')
document.write('alert("hello world")')
document.write('</script>')
document.write('<p>goodbye world</p>')

一般来说

<script type="text/javascript" src="source.js"></script>

在头部工作很好,但有没有其他方法,我可以动态添加source.js使用innerHTML之类的东西?

我已经试过了


当前回答

差不多十年过去了,没有人愿意写Promise的版本,所以这里是我的版本(基于这个awnser):

function addScript(src) {
  return new Promise((resolve, reject) => {
    const s = document.createElement('script');

    s.setAttribute('src', src);
    s.addEventListener('load', resolve);
    s.addEventListener('error', reject);

    document.body.appendChild(s);
  });
}

使用

try {
  await addScript('https://api.stackexchange.com/js/2.0/all.js');
  // do something after it was loaded
} catch (e) {
  console.log(e);
}

其他回答

没有人提到它,但你也可以通过使用URL和Blob将实际的源代码插入到脚本标记中:

const jsCode = `
 // JS code in here. Maybe you extracted it from some HTML string.
`

const url = URL.createObjectURL(new Blob([jsCode]))
const script = document.createElement('script')
script.src = url
URL.revokeObjectURL(url) // dispose of it when done

至于jsCode,你可能已经从一些HTML中得到了它。

这里有一个更完整的例子,你如何处理HTML源代码中的任意数量的脚本:

main()

async function main() {
    const scriptTagOpen = /<script\b[^>]*>/g
    const scriptTagClose = /<\/script\b[^>]*>/g
    const scriptTagRegex = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g

    const response = await fetch('path/to/some.html')
    const html = await response.text()

    someElement.innerHTML = html

    // We need to get the script tags and manually add them to DOM
    // because otherwise innerHTML will not execute them.
    const codes =
        html
            .match(scriptTagRegex)
            ?.map(code => code.replace(scriptTagOpen, '').replace(scriptTagClose, ''))
            .map(code => URL.createObjectURL(new Blob([code]))) || []

    for (const code of codes) {
        const script = document.createElement('script')
        script.src = code
        someElement.append(script)
        URL.revokeObjectURL(code)
    }
}
var my_awesome_script = document.createElement('script');

my_awesome_script.setAttribute('src','http://example.com/site.js');

document.head.appendChild(my_awesome_script);

要做到这一点,唯一的方法是替换文档。使用您自己的函数编写,该函数将在页面底部附加元素。jQuery非常简单:

document.write = function(htmlToWrite) {
  $(htmlToWrite).appendTo('body');
}

如果你有html来文档。像问题样例那样写入块,你需要缓冲htmlToWrite段。也许是这样的:

document.write = (function() {
  var buffer = "";
  var timer;
  return function(htmlPieceToWrite) {
    buffer += htmlPieceToWrite;
    clearTimeout(timer);
    timer = setTimeout(function() {
      $(buffer).appendTo('body');
      buffer = "";
    }, 0)
  }
})()

一行代码(与上面的答案没有本质区别):

document.body.appendChild(document.createElement('script')).src = 'source.js';

我尝试递归地追加每个脚本

注意:如果你的脚本是一个接一个的,那么位置需要同步。

Major Dependency应该在数组的最后,以便初始脚本可以使用它

const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js'] let count = 0 const recursivelyAddScript = (script, cb) => { const el = document.createElement('script') el.src = script if(count < scripts.length) { count ++ el.onload = recursivelyAddScript(scripts[count]) document.body.appendChild(el) } else { console.log('All script loaded') return } } recursivelyAddScript(scripts[count])