html知识点梳理

717 阅读8分钟

概述

本文对html中的重要内容做一下梳理,主要来源html spec,较为完整的介绍可以参考这篇

Event

js使用异步、事件驱动的编程模型。 一个完整的事件需包含

  • 一个事件对象,即Event
  • 一个事件目标对象,即EventTarget,一般是一个dom元素,也可以是window或其他,比如XMLHttpRequest
  • 一个事件监听器 eventHandler,是一个回调函数,当监听到事件
  • 事件分发动作

事件对象

浏览器中的各种事件都是基于Event class,比如MouseEvent。 除了这些内置的事件,还可以自定义事件,可以直接实例化Event,也可以实例化CustomEvent,后者可以添加自定义数据。

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) });

// create and dispatch the event
var event = new CustomEvent("cat", {
  detail: {
    hazcheeseburger: true
  }
});
obj.dispatchEvent(event);

事件目标对象

EventTarget是一个对象,可以绑定事件处理器和分发事件。

浏览器中的事件目标对象都是EventTarget及其字类,比如常见的Element, Document, and Window,另外还有XMLHttpRequest, AudioNode, AudioContext等。

事件监听器

事件监听器有三种使用方式

  • 设置事件处理器属性
el.onclick=(e)=>{}
  • html内联事件,内容是字符串
 onclick="console.log('Thank you');"
  • addEventListener()
三个参数,
第一个是事件类型,第二个是事件处理器函数
第三个是options或useCapture。当是布尔值时指定是否在捕获阶段处理,默认false.当是对象时包含属性
1.capture 布尔值,在捕获阶段处理
2.once 布尔值,是否只触发一次
3.passive 布尔值,如果为true,表明永远不会调用preventDefault(),从而不必等待主线程取消默认事件,直接生成对应帧,chrome等浏览器将文档级别的节点默认设为true
4.signal,是AbortSignal,其abort()方法调用时监听器移除,参考下一章

事件分发动作

一个事件可以是用户的一个行为触发的,比如鼠标单击,也可以是编程触发的,比如HTMLElement.click() ,类似的还有EventTarget.dispatchEvent()

其他细节

事件传播

事件传播包含三个阶段

  • capturing
  • target
  • bubble

注意“focus,” “blur,” and “scroll” 事件不会冒泡,除了整个文档以外的load事件会冒泡到document截至。

body元素直接添加事件处理器会处理window上的事件,因此冒泡时会在document之后。

事件取消

调用preventDefault()取消默认行为 用stopPropagation()停止传播

MutationObserver

提供了监测dom树变化的能力,当dom树变化会触发相关事件处理器

const targetNode = document.querySelector("#someElement");
const observerOptions = {
  childList: true,
  attributes: true,
  // Omit (or set to false) to observe only changes to the parent node
  subtree: true
}

const observer = new MutationObserver(callback);//创建一个观察者,其中包含事件处理器的回调
observer.observe(targetNode, observerOptions);//添加监测

Aborting ongoing activities

用来提供一个api来取消promise等请求,比如可以用在fetch或前面介绍的addEventListener()。

AbortController实例有一个属性,signal,和一个abort()实例方法,比如

var controller = new AbortController();
var signal = controller.signal;

var downloadBtn = document.querySelector('.download');
var abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
  controller.abort();
  console.log('Download aborted');
});

function fetchVideo() {
  ...
  fetch(url, {signal}).then(function(response) {
    ...
  }).catch(function(e) {
   reports.textContent = 'Download error: ' + e.message;
  })
}

Node及其子类

Node继承自EventTarget,并提供了一系列对node实例增删改查的api,即dom api。

node type

Node.nodeType属性是一个整数,来表示具体的node类型,包括

  • Node.ELEMENT_NODE (1) 元素
  • Node.ATTRIBUTE_NODE (2) 元素属性
  • Node.TEXT_NODE (3) 元素或属性中的文本
  • Node.CDATA_SECTION_NODE (4) such as .
  • Node.PROCESSING_INSTRUCTION_NODE (7) such as .
  • Node.COMMENT_NODE (8) 注释
  • Node.DOCUMENT_NODE (9) document节点
  • Node.DOCUMENT_TYPE_NODE (10) such as
  • Node.DOCUMENT_FRAGMENT_NODE (11) 片段

这些节点的类别我们会关注1和9。

Document

用来表示一个html页面,其中可以通过document.documentElement and document.body分别获取html元素和body元素

还可以用来访问文档级别的很多属性,比如document.domain。

Element

在html文档中的元素都是Element的子类,更准确地说,是HTMLElement的子类,比如每个div元素都是一个HTMLDivElement类的实例,其中可用的方法和属性除了自身的,还有继承自其他类的。

在html中,多数类的实例化需要用提供的工厂函数

document.createElement(tagName[, options])

也有部分元素可以直接new调用,比如

new Image()
//等效于
document.createElement('img')

除了浏览器提供的元素,我们还可以封装自己的元素,即Web Components

元素分类

元素是按照content model分类的,content model定义了元素可以包含什么内容。

html4将元素分为两大类

  • inline inline元素只能包含文本和其他inline元素,在渲染时不需要另取一行,比如span
  • block-level,block-level元素可以包含其他block-level元素或inline-element,渲染时需要另起一行,比如div。

另外还有些元素可以作为两种中的任意一种,当作为inline元素时,比如button元素在另一个inline元素内部时,就不能再包含block-level。

因为这些概念容易和css中display属性相关的内容弄混,于是在html5被重新分类。

新版的分类包括七种

  • Metadata content 用来描述文档信息,包括
  • Flow content body的大部分子元素都是
  • Sectioning content
  • Heading content
  • Phrasing content
  • Embedded content 用来嵌套别的内容
  • Interactive content 用于交互

这一块我们只关注一下script标签的defer和async属性对于普通script和model的影响。

image.png

另外还关注一下crossorigin属性,用来向window.error中传递较少的错误信息。

Web application APIs

web页面一般运行在浏览器中,浏览器中除了根据ecma规范实现的js引擎,还提供了其他api,比如输入输出。

有多种方式可以使js在文档的上下文执行,包括但不限于:

  • script元素的处理
  • 使用javascript: URLs导航
  • Event handlers,比如通过设置元素属性
  • svg的script功能

realm

ecma介绍了realm概念,表示script运行的全局环境,每个realm都有一个全局对象(作为[[GlobalObject]]),全局对象和它的属性上挂载者规范定义的东西。

Event loops

为了协调事件、用户交互、scripts、渲染、网络请求等,用户代理一定要使用本节介绍的event loop

event loop不对应于每个线程,比如多个event loop可以对应于一个线程。

一个event loop有一个或多个task queues,即一系列tasks,注意这里task queue并不是queue,而是sets。

tasks封装的算法对应于以下works

  • Event
  • parsing html parser解析
  • callback 回调
  • Using a resource 当一个算法fetch一个资源,一旦资源可用就会被task处理
  • Reacting to DOM manipulation 响应dom操作,比如插入元素

微任务包括 不同宿主统一的

  • promise

html

  • queueMicrotask
queueMicrotask(callback)可以将一个回调加入微任务队列,一旦调用栈为空就会调用,类似于setTimeout(f, 0)

当然不要添加太多到微任务队列,可以考虑使用 requestAnimationFrame() or requestIdleCallback()
  • MutationObserver

node

  • process.nextTick

当一个task完成把控制权交给用户代理进行下一次task前(如果是当前task生成的微任务也会等当前任务执行完再处理),会检查microtasks queue,微任务也会产生微任务添加到微任务队列,直到微任务为空,在这里要先执行完当前的微任务,再去执行新产生的微任务,然后进行必要的渲染,再进行下一次任务。

执行渲染之前会调用requestAnimationCallback,如果这帧还有剩余时间就会执行requestIdleCallback,否则跳过,执行真正渲染。

image 这节后半部分参考这里

通信

MessageEvent表示一个消息事件,在各种web通信方式中使用。

Server-sent events

Server-sent events可以用来使服务器随时向web页面推送数据。 使用步骤可以分为

  • 实例化EventSource,指定接收事件的url
  • 添加事件监听 = 服务端发送text/event-stream类型的事件流

具体实现参考sse.js

Web sockets

Web sockets可以用来服务端和客户端相互发送信息

当前规范只规定了客户端的用法,即创建一个WebSocket实例,然后调用对应方法向服务器发送事件,并监听事件,服务端可以搭配ws

或者直接使用连客户端也封装了的socket.io

Cross-document messaging

这个是指的跨文档通信,比如文档和iframe,或者和一个window.open打开的文档。

这种方式可以实现跨域,案例可参考这里

Channel messaging

Channel messaging是前一种的升级版,通信双方在第一次通信验证安全性后可以建立一个管道。

Broadcasting to other browsing contexts

是一种广播形式的通信,实现了一对多。

不能跨域

Web workers

web worker提供了main线程以外的其他线程,可以用来处理ui以外的计算(和ui相关的一些浏览器api无法访问)。worker线程和main线程使用Cross-document messaging方法通信。

普通的worker,即Worker的实例,只能被实例化它的脚本使用,这被称为dicated worker。
另外还提供了SharedWorker,可以被同源的多个脚本使用.