HTML
February 17, 2023
Web components #
custom element #
名字里必须要有 hyphen -
- Autonomous custom elements – “all-new” elements, extending the abstract HTMLElement class.
class MyElement extends HTMLElement {
constructor() {
super();
// element created
}
connectedCallback() {
// browser calls this method when the element is added to the document
// (can be called many times if an element is repeatedly added/removed)
}
disconnectedCallback() {
// browser calls this method when the element is removed from the document
// (can be called many times if an element is repeatedly added/removed)
}
static get observedAttributes() {
return [/* array of attribute names to monitor for changes */];
}
attributeChangedCallback(name, oldValue, newValue) {
// called when one of attributes listed above is modified
}
adoptedCallback() {
// called when the element is moved to a new document
// (happens in document.adoptNode, very rarely used)
}
// there can be other element methods and properties
}
// let the browser know that <my-element> is served by our new class
customElements.define("my-element", MyElement);
// document.createElement('my-element')
- Customized built-in elements – extending built-in elements, like a customized button, based on HTMLButtonElement etc
class MyButton extends HTMLButtonElement { /*...*/ }
customElements.define('my-button', MyElement, {extends: 'button'});
/* <button is="my-button"> */
Shadow dom #
用于创建组件级的 Dom,有自己的 id 空间,不会被外部的 querySelector 访问到
A DOM element can have two types of DOM subtrees
- Light tree – a regular DOM subtree, made of HTML children. All subtrees that we’ve seen in previous chapters were “light”.
- Shadow tree – a hidden DOM subtree, not reflected in HTML, hidden from prying eyes.
<script>
customElements.define('show-hello', class extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `<p>
Hello, ${this.getAttribute('name')}
</p>`;
}
});
</script>
<show-hello name="John"></show-hello>
Shadow Dom 有自己的样式,不会被外部 dom 的样式影响到
<template /> #
用于封装 dom 片段
内部可编写任何语法正确的 html 片段
浏览器会校验其内部的 html 语法,但允许使用任何顶级 html 标签
当被插入到 document 中,其内部的标签会开始解析并执行
<template id="tmpl">
<style> p { font-weight: bold; } </style>
<p id="message"></p>
</template>
<div id="elem">Click me</div>
<script>
elem.onclick = function() {
elem.attachShadow({mode: 'open'});
elem.shadowRoot.append(tmpl.content.cloneNode(true)); // (*)
elem.shadowRoot.getElementById('message').innerHTML = "Hello from the shadows!";
};
</script>
Dom api #
- document.querySelectorAll(selectors)
动画 #
MessageChannel #
用于通信场景,例如 两个 iframe, 主文档和其中嵌入的 iframe, 两个文档通过 SharedWorker 通信, 两个 Worker
Message channels 可以提供一个安全通道,允许开发者在不同的浏览上下文中传递数据
实例属性 #
-
MessageChannel.port1
返回 channel 的端口1
-
MessageChannel.port2
返回 channel 的端口2
示例 #
主文档:
const input = document.getElementById("message-input");
const output = document.getElementById("message-output");
const button = document.querySelector("button");
const iframe = document.querySelector("iframe");
const channel = new MessageChannel();
const port1 = channel.port1;
// Wait for the iframe to load
iframe.addEventListener("load", onLoad);
function onLoad() {
// Listen for button clicks
button.addEventListener("click", onClick);
// Listen for messages on port1
port1.onmessage = onMessage;
// Transfer port2 to the iframe
// The contentWindow property returns the Window object of an HTMLIFrameElement.
/* 参数1: The message being sent. For this initial port transferring this message could be an empty string but in this example it is set to 'init'.
参数2: The origin the message is to be sent to. * means "any origin".
参数3: An object, the ownership of which is transferred to the receiving browsing context. In this case, we are transferring MessageChannel.port2 to the IFrame, so it can be used to communicate with the main page. */
iframe.contentWindow.postMessage("init", "*", [channel.port2]);
}
// Post a message on port1 when the button is clicked
function onClick(e) {
e.preventDefault();
port1.postMessage(input.value);
}
// Handle messages received on port1
function onMessage(e) {
output.innerHTML = e.data;
input.value = "";
}
iframe:
const list = document.querySelector("ul");
let port2;
// Listen for the initial port transfer message
window.addEventListener("message", initPort);
// Setup the transferred port
function initPort(e) {
port2 = e.ports[0];
port2.onmessage = onMessage;
}
// Handle messages received on port2
function onMessage(e) {
const listItem = document.createElement("li");
listItem.textContent = e.data;
list.appendChild(listItem);
port2.postMessage(`Message received by IFrame: "${e.data}"`);
}
事件 #
- DOMContentLoaded
Performance #
-
performance.now()
返回 DOMHighResTimeStamp, 单位毫秒(milliseconds)
represents the time elapsed since the time origin.
If the current Document is the first one loaded in the Window, the time origin is the time at which the browser context was created
const t0 = performance.now(); // 239313.40000000596 doSomething(); const t1 = performance.now(); // 256432.29999998212 console.log(`Call to doSomething took ${t1 - t0} milliseconds.`);