使用 Document.scripts 获取引入文件的 script 标签

2014-06-27 · 12 min read

有些时候,使用 javascript 控件的时,需要执行一些初始化设置,那么一般的做法是这样的:

<script src="path/to/your.js"></script>

<script type="text/javascript">
  your.init({
    id: 1,
  })
</script>

暴露一个初始化的方法,使用时自行调用执行初始化。一般来说这还是比较合理的,但是某些需求下就比较不科学了,例如实现类似知乎的“用户信息名片”这个功能:

我的想法是这样的:引入组件 js,立即在document 上注册mouseover事件委托,通过判断data-toggle 标记来判断是不是要显示名片:

<script type="text/javascript" src="path/to/card.js"></script>
<a href="#" data-toggle="card">测试用户</a>

引入 js 文件,给 html 元素打上标记,这样就能十分优雅的完成这个功能了。但是问题又来了,如果要全局配置一些信息呢(例如根据当前的栏目显示不同的信息)?难道再暴露一个初始化方法?可是感觉这样就不如原来那么优雅了。其实解决方法早就有了,seajs 就使用了:

引入 sea.js 时,可以把 sea.js 与其他文件打包在一起,可提前合并好,或利用 combo 服务动态合并。无论哪一种方式,为了让 sea.js 内部能快速获取到自身路径,推荐手动加上 id 属性,可以让 sea.js 直接获取到自身路径,而不需要通过其他机制去自动获取。这对性能和稳定性会有一定提升,推荐默认都加上。

seajs 的官方文档推荐在<script> 标签上加上 ID,说对性能有提升。其实不加也可以使用,那么它是怎么做到的呢?直接看代码:

var doc = document
var scripts = doc.scripts

// Recommend to add `seajsnode` id for the `sea.js` script element
var loaderScript = doc.getElementById('seajsnode') || scripts[scripts.length - 1]

上面是关键代码,关键在于使用了document.scripts 来取得script 对象。下面详细介绍下:

Document.scripts#

返回页面中的<script> 列表,结果的 HTML 对象,兼容所有浏览器。在不同 js 文件中(或者<script>  标签里),调用Document.scripts 取得的结果都是不一样的:

<script>
  console.log(document.scripts.length)
</script>
<script>
  console.log(document.scripts.length)
</script>
<script>
  console.log(document.scripts.length)
</script>

会分别输出 1,2,3。这样使用document.scripts[document.scripts.length - 1] 就可以取得当前 js 文件的<script> 标签了。

现在返回前面的问题,只要在和 seajs 一样,在引入 js 文件的 script 标签上配置栏目信息,执行 js 文件时获取到此信息,就可以免除初始化函数,继续保持“优雅”了:

<script src="path/to/card.js" data-category="music"></script>
<a href="#" data-toggle="card">测试用户</a>