script标签4种的四种用法,你知道几种?

这篇具有很好参考价值的文章主要介绍了script标签4种的四种用法,你知道几种?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文为HTML标准解读系列文章,其他文章详见这里。

在一个HTML页面中执行js脚本有很多方式,包括但不限于以下几种:

  • 使用script标签执行脚本;
  • 使用javascript:URL的导航;
  • 使用DOM上的事件监听机制;
  • 使用svg相关技术中的脚本能力;

在这些方式中,使用最多的无疑是第一种。script标签允许开发者给页面插入js脚本,而根据type属性的值,可以把script元素分成4种不同的类型:

类型 对应的type属性值 描述
js传统脚本(classic script) 没有声明type属性,或type属性值为空,或type属性值匹配任一JavaScript MIME类型(如text/javascript)。 以ECMAScript顶层Script语法规则进行解析的脚本。
js模块脚本(module script) “module” 以ECMAScript顶层Module语法规则进行解析的脚本。
Imports map “importmap” 控制页面内模块标识符(module specifier)的解析。
数据块 除了上述以外的其他值 浏览器不会被对其作处理,内部的文本可以作为数据在其他脚本中时候。

对于前面三种类型,可以使用HTMLScriptElement.supports(type)的方法来检测浏览器是否支持这些类型,对应的参数type分别是classicmoduleimportmap

js传统脚本

js传统脚本是我们使用最多的script类型。我们可以在标签内直接写js代码,也可以通过src属性引入一个外部的js文件。

基于历史原因,script标签内容的解析有一些奇怪的规则。比如,以下的script标签都无法按照预期运行:

<!-- 1: script标签把字符串内容</script>看成是闭合标签 -->
<script>
    const example = "script的闭合标签是</script>";
    console.log(example);
</script>

<!-- 2: script标签把<!--看成是注释的起始标签 -->
<script>
    if (x <!--y) { ... }
</script>

为了避免这些坑,标准建议把所有script标签里的字符串、正则表达式、注释内容里面的<!--<script</script都使用\x3C!--\x3Cscript\x3C/script转义,并且避免在js表达式中使用这类写法。所以,以上的问题可以这么修正:

<script>
    const example = "script的闭合标签是\x3C/script>";
    console.log(example);
</script>

<script>
    if (x < !--y) { ... }
</script>

js模块脚本

把代码拆解成不同的模块是程序员应对复杂度的一个重要手段。在js模块脚本获得浏览器原生支持之前,我们只能通过一些间接手段达成模块化的目标,如使用webpack这样的打包工具。

从es6开始,浏览器原生支持模块化。现在你可以使用type="module"声明js模块脚本。在以下的script标签中,app.js及其依赖都会被浏览器获取:

<script type="module" src="app.js"></script>

基于历史原因,js传统脚本的获取以及执行都会阻塞HTML解析。对于这种情况,你可以使用async属性促使浏览器异步获取脚本,又或者使用defer属性延迟到HTML解析完毕后才执行脚本。对于js模块脚本,默认是异步获取的,并且在HTML解析完成后才开始执行。你可以使用async属性让js模块脚本在完成获取后立即执行,如果这个时候HTML还未完成解析,解析就会被脚本的执行阻塞;defer属性对js模块脚本无影响。

async属性、defer属性与HTML解析过程在运行时上的关系,可以用下面一张图总结:

script标签4种的四种用法,你知道几种?

js模块脚本除了导入js模块,还可以导入css模块以及json模块,但需要使用assert语句声明其类型:

<script type="module">
    import json from 'example.json' assert {type: 'json'}
    import css from 'example.css' assert {type: 'css'}
    // ...
</script>

importmap

importmap是一个最近(2022年10月5日)才正式写入标准的脚本类型。

任何的模块系统,不管是AMD、commonJs还是es6模块,都有「模块标识符」的概念。模块标识符用于索引一个模块,你可以简单地理解为是模块的名字。很多时候,模块标识符就是代码所在位置的路径,比如下面的代码中,"/node_modules/moment/src/moment.js"就是这个文件对应的模块的模块标识符:

import moment form "/node_modules/moment/src/moment.js"

在importmap之前,es6模块的模块标识符只支持像上面这样的实际路径,而importMap可以实现对模块标识符的重新映射。比如下面的例子,把"/node_modules/moment/src/moment.js"映射到"moment"上;于是,该页面中所有的js模块脚本,都可以统一使用import XXX from "moment"引入这个模块:

<script type="importmap">
    {
        "imports": {
          "moment": "/node_modules/moment/src/moment.js"
        }
      }
</script>
<script type="module">
    import moment from "moment"
    // ...
</script>

每一个页面最多只能有一个importmap。importmap需要使用一个内联的json表示,这个json支持两个顶层的键:

  • imports:作用于全局的映射,如上面所示。

  • scopes:作用于局部映射。常用于在页面内使用同一模块的不同版本,比如以下这个例子:

    <script type="importmap">
        {
            "scopes": {
              "/a/" : {
                "moment": "/node_modules/moment/src/moment.js"
              },
              "/b/" : {
                "moment": "https://cdn.example.com/moment/src/moment.js"
              }
            }
          }
    </script>
    

    当使用import "moment"的时候,不同位置下的脚本会有不同的情况:

    • 位于/a/下的脚本,会引入"/node_modules/moment/src/moment.js"
    • 位于/b/下的脚本,会引入"https://cdn.example.com/moment/src/moment.js"
    • 位于/c/下的脚本,会报错。

importmap还支持多种类型的模块标识符:

  • 裸标识符(Bare specifiers),不带有斜杠/的标识符,如上面的moment。

  • 以斜杠结尾的标识符:可用于映射一类的路径。

    <script type="importmap">
        {
            "imports": {
              "moment/": "/node_modules/moment/src/"
            }
        }
    </script>
    <script type="module">
        import localeData from "moment/locale/zh-cn.js"
      	// ...
    </script>
    
  • URL类标识符:包括绝对路径和相对路径。

    {
      "imports": {
        "https://cdn.example.com/vue/dist/vue.runtime.esm.js": "/node_modules/vue/dist/vue.runtime.esm.js",
        "/js/app.mjs": "/js/app-8e0d62a03.mjs",
        "../helpers/": "https://cdn.example/helpers/"
      }
    }
    

在现实中,three.js很早就在使用importmap了,不过是配合着垫片(shim)使用的。

数据块

当script标签的type属性不匹配js传统脚本、js模块脚本、importmap任一类型的时候,浏览器会直接忽略这个标签。这种标签在实际开发中经常被用来当作数据块使用。

比如,你可以使用数据块存放一张游戏地图,这个数据块可以用于运行游戏的时候生成地图,也可以用在站内检索,提供特定的能力。

<script src="game-engine.js"></script>
<script type="text/x-game-map">
........U.........e
o............A....e
.....A.....AAA....e
.A..AAA...AAAAA...e
</script>

我们也可以看一些现实中的例子:

  • systemjs:systemjs使得开发者可以在老式浏览器上使用es6模块的语法。它使用type="systemjs-module"以及type="systemjs-importmap"的script标签分别模拟js模块脚本和importmap,这种script标签本质上就是一个数据块,浏览器并不会对这些script标签作任何处理,这些标签会留给systemjs内部进行处理,从而模拟加载模块的过程:

    <script src="system.js"></script>
    <script type="systemjs-importmap">
    {
      "imports": {
        "lodash": "https://unpkg.com/lodash@4.17.10/lodash.js"
      }
    }
    </script>
    <script type="systemjs-module" src="/js/main.js"></script>
    
  • three.js:threejs是一个3D库。在它的示例中,常常使用数据块来存放3D渲染模型的数据,如type="x-shader/x-vertex"type="x-shader/x-fragment"的script标签。

    <script id="procedural-vert" type="x-shader/x-vertex">
    	varying vec2 vUv;
    
    	void main() {
    		vUv = uv;
    		gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    	}
    </script>
    

值得一提的是,标准建议:在使用数据块的时候,最好使用符合格式的MIME类型,避免标准在未来增加新的类型的时候发生冲突:文章来源地址https://www.toymoban.com/news/detail-449320.html

"text/html" // 符合格式
"text/html;" // 不符合格式
"text/html;charset=uft-8" // 符合格式

到了这里,关于script标签4种的四种用法,你知道几种?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • cv::Mat的四种复制操作和cv::Mat作为函数形参的四种形式

    1、通过讲解cv::Mat类的深拷贝和浅拷贝来说明cv::Mat的四种复制操作 2、当cv::Mat作为函数形参时: cv::Mat temp 、 const cv::Mat temp 、 cv::Mat temp 、 const cv::Mat temp 这四种形参有什么区别?函数内部对Mat类形参数据的改变是否会影响到外面的Mat类实参数据? OpenCV2,数据结构Mat主要包含

    2024年02月10日
    浏览(61)
  • JAVA 的四种访问权限

    在Java编程中,访问权限是非常重要的概念,因为它可以保证代码的安全性和封装性。访问权限有四种,分别是public、protected、default和private。 private :如果一个类的方法或者变量被 private 修饰,那么这个类的方法或者变量只能在该类本身中被访问,在类外以及其他类中都不能

    2024年02月09日
    浏览(48)
  • View 的四种 OnClick 方式

    嗨喽,大家好!今天呢,我跟大家聊一聊Android 的View 的点击事件onClick 。额,有点拗口(^_^) 。 看过我的文章的人可能会好奇,你怎么写Android的文章了啊?说起这啊,就是我的血泪史了,此处省略一万字.................... 废话不多说,让我们代码走起,风里来,雨里去,唯有代

    2023年04月15日
    浏览(42)
  • java的四种访问权限

    1、public: 所修饰的类、变量、方法,在内外包均具有访问权限,Public (公有) 访问权限较为宽松的一种,不仅可以被跨类访问,而且可以跨包访问。 2、protected: 这种权限是为继承而设计的,protected所修饰的成员,对所有子类是可访问的,但只对同包的类是可访问的,对外

    2024年02月15日
    浏览(40)
  • Hive的四种排序方法

    hive排序方法,hive的排序方式 hive有四种排序方法: ORDER BY 、SORT BY 、DISTRIBUTE BY 、CLUSTER BY 0. 测试数据准备 uuid dept salary 1001 研发部 16000 1002 市场部 17000 1003 销售部 11000 1004 研发部 15000 1005 销售部 12000 1006 研发部 21000 1007 产品部 16000 1008 研发部 18000 1009 市场部 17000 1010 产品部 16

    2024年02月02日
    浏览(42)
  • 数据的四种基本存储方法

    数据的存储结构可用以下四种基本存储方法得到: ( 1 )顺序存储方法     该方法把逻辑上相邻的结点存储在物理位置上相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。     由此得到的存储表示称为顺序存储结构  (Sequential Storage Structure),通常借

    2024年02月15日
    浏览(44)
  • docker中的四种网络模式

    Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接

    2024年02月04日
    浏览(55)
  • 创建多线程的四种方式

    ① 创建一个类继承 Thread 类,重写 run() 方法 ② 调用 start() 方法启动线程 例: ① 创建类实现 Runnable 接口,重写 run() 方法 ② 以实现类作为构造器参数,创建一个线程( Thread )对象 ③ 调用 start() 方法启动线程 例 注意:实现Runnable接口方式中,调用的不是Thread类的run()方法

    2024年02月10日
    浏览(45)
  • 06-PS中的四种蒙版

    Photoshop中的蒙版就是遮罩的意思,主要作用就是将其所在的图层,把不同的明暗度转化成相应的透明度。黑色为完全透明,灰色为半透明,白色为完全不透明。添加蒙版有便于灵活修改,不影响图层原貌。PS蒙版有四类:图层蒙版、剪切蒙版、矢量蒙版、快速蒙版。 遮住此图

    2024年02月02日
    浏览(39)
  • CSS中的四种定位方式

    在CSS中定位有以下4种: 静态定位 - static 相对定位 - relative 绝对定位 - absolute 固定定位 - fixed 静态定位是css中的默认定位方式,也就是没有定位。在此定位方式中设置:top,bottom,left,right,z-index 这些属性都是无效的。 相对位置前的位置: 相对位置后的位置: 可以看到该

    2024年02月08日
    浏览(85)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包