Visual Viewport API

Visual Viewport API 提供了查询和监测屏幕可视区域的功能

该 API 通过 Window 接口的 visualViewport 属性暴露的 VisualViewport 实例使用

VisualViewport 概念

Viewport 有两个相对的概念 —— Layout Viewport 和 Visual Viewport,Layout Viewport 包含当前文档用户可见的内容,而 Visual Viewport 仅包含当前文档用户当前可见的内容。例如,屏幕键盘等功能仅影响 Visual Viewport,不影响 Layout Viewport;缩放页面时,Visual Viewport 发生变化,而 Layout Viewport 不变

获取 VisualViewport 信息

主要通过 VisualViewport 接口的属性获取 Visual Viewport 信息

VisualViewport 接口的 width 属性返回一个 number,表示 Visual Viewport 的宽度

VisualViewport 接口的 height 属性返回一个 number,表示 Visual Viewport 的高度

VisualViewport 接口的 offsetLeft 属性返回一个 number,表示 Visual Viewport 相对 Layout Viewport 左边缘的偏移量

VisualViewport 接口的 offsetTop 属性返回一个 number,表示 Visual Viewport 相对 Layout Viewport 上边缘的偏移量

VisualViewport 接口的 pageLeft 属性返回一个 number,表示 Visual Viewport 相对初始包含块的 x 坐标

VisualViewport 接口的 pageTop 属性返回一个 number,表示 Visual Viewport 相对初始包含块的 y 坐标

VisualViewport 接口的 resize 属性返回一个 number,表示 Visual Viewport 的缩放参数

监听 VisualViewport 变化

主要通过 VisualViewport 接口的事件监听 Visual Viewport 变化

VisualViewport 接口的 resize 事件在 Visual Viewport 尺寸发生改变时触发

VisualViewport 接口的 scroll 事件在 Visual Viewport 发生滚动时触发

示例

Width Height OffsetLeft OffsetTop PageLeft PageTop Scale
0 0 0 0 0 0 0

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Window {
readonly visualViewport: VisualViewport
}

interface VisualViewport extends EventTarget {
readonly offsetLeft: number
readonly offsetTop: number

readonly pageLeft: number
readonly pageTop: number

readonly width: number
readonly height: number

readonly scale: number

onresize: ((this: VisualViewport, ev: Event) => any) | null
onscroll: ((this: VisualViewport, ev: Event) => any) | null
onscrollend: ((this: VisualViewport, ev: Event) => any) | null
}

链接

Screen API

Screen API 主要支持获取当前设备屏幕的一些信息

该 API 通过 Window 接口的 screen 属性暴露的 Screen 实例使用

屏幕信息

Screen 接口的 height 属性返回一个 number,代表屏幕的高度

Screen 接口的 width 属性返回一个 number,代表屏幕的宽度

Screen 接口的 availHeight 属性返回一个 number,代表屏幕可用区域的高度

Screen 接口的 availWidth 属性返回一个 number,代表屏幕可用区域的宽度

Screen 接口的 colorDepth 属性返回一个 number,代表屏幕的颜色位深度

Screen 接口的 pixelDepth 属性返回一个 number,代表屏幕的像素位深度

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Window {
readonly screen: Screen
}

interface Screen {
readonly availHeight: number
readonly availWidth: number
readonly colorDepth: number
readonly height: number
readonly pixelDepth: number
readonly width: number
}

declare var Screen: {
prototype: Screen
}

链接

Permissions Policy

Permissions Policy 允许开发者定义在网页中控制功能的可用性,从而增加应用的安全性和隐私性

Permissions Policy 与 Content Security Policy 类似,但其专注于控制功能特性而非内容

需要注意的是 Permissions Policy 曾经被称为 Feature Policy,但其现在已重命名

指定 Permissions Policy

可以利用 Permissions-Policy 请求头来指定 Permissions Policy,或使用与之等价的 <meta> 标签

可以利用 <iframe> 标签的 allow 属性给内嵌网页指定 Permissions Policy

指定单个 Permissions Policy 时通常包含与之对应的一条指令与允许列表

检测 Permissions Policy

可以通过 Document 接口的 featurePolicy 属性或 HTMLIFrameElement 接口的 featurePolicy 属性暴露的 FeaturePolicy 实例检测 Permissions Policy 的状态

注意:标准已将 FeaturePolicy 接口重命名为 PermissionsPolicy 接口, featurePolicy 属性重命名为 permissionsPolicy 属性

FeaturePolicy 接口的 allowedFeatures() 方法获取当前用户代理在当前浏览上下文允许使用的所有特性

FeaturePolicy 接口的 allowsFeature() 方法检测指定特性在指定的域下是否可用

FeaturePolicy 接口的 features() 方法获取当前用户代理支持的所有特性

FeaturePolicy 接口的 allowedFeatures() 方法列举当前用户代理设置的特性策略中指定特性允许使用的域

Permissions Policy 与 Permissions API 的联系

Permissions Policy 允许开发者设置权限的策略,而 Permissions API 允许用户授予权限

Permissions Policy 指令

Directive name Directive description
accelerometer Accelerometer
ambient-light-sensor AmbientLightSensor
autoplay HTMLMediaElement.play() <audio> & <video> autoplay
battery Battery Status API - Navigator.getBattery()
camera video input devices MediaDevices.getUserMedia()
display-capture MediaDevices.getDisplayMedia()
document-domain set document.domain
encrypted-media Encrypted Media Extensions API - Navigator.requestMediaKeySystemAccess()
execution-while-not-rendered script execution of renderer status
execution-while-out-of-viewport script execution of viewport status
fullscreen Element.requestFullscreen()
gamepad Gamepad API - Navigator.getGamepads() Window:gamepadconnected Window:gamepaddisconnected
geolocation Geolocation API - Geolocation.getCurrentPosition() Geolocation.watchPosition()
gyroscope Gyroscope
hid WebHID API
identity-credentials-get FedCM API
idle-detection Idle Detection API
local-fonts Local Font Access API - Window.queryLocalFonts()
magnetometer Magnetometer
microphone audio input devices MediaDevices.getUserMedia()
midi Web MIDI API - Navigator.requestMIDIAccess()
otp-credentials WebOTP API
payment Payment Request API - PaymentRequest
picture-in-picture Picture In Picture API
publickey-credentials-create Web Authentication API
publickey-credentials-get Web Authentication API
screen-wake-lock Screen Wake Lock API
serial Web Serial API
speaker-selection Audio Output Devices API
storage-access Storage Access API
usb WebUSB API
web-share Web Share API - Navigator.share()
window-management Window Management API
xr-spatial-tracking WebXR Device API

Permissions Policy 允许列表

  • * 允许在顶层浏览上下文及其嵌入浏览上下文中使用
  • () 禁止在顶层浏览上下文及其嵌入浏览上下文中使用,在 <iframe> 标签的 allow 属性的值为 none
  • self 允许在顶层浏览上下文及其同源的嵌入浏览上下文中使用,禁止在嵌入的跨域的嵌入浏览上下文中使用
  • src 仅限在 <iframe> 标签的 allow 属性中使用,允许在当前嵌入浏览上下文中使用
  • <origin> 允许在指定源的浏览上下文中使用
1
2
3
4
5
6
7
8
9
*
()
(self)
(src)
("https://a.example.com")
("https://a.example.com" "https://b.example.com")
(self "https://a.example.com" "https://b.example.com")
(src "https://a.example.com" "https://b.example.com")
("https://*.example.com")

Permissions-Policy 响应头语法

基本语法

1
Permissions-Policy: <directive>=<allowlist>

示例

1
2
3
Permissions-Policy: geolocation=()
Permissions-Policy: geolocation=(self "https://a.example.com" "https://b.example.com")
Permissions-Policy: picture-in-picture=(), geolocation=(self https://example.com), camera=*;

另外值得注意的是,该响应头无法被编程式修改

<iframe> 标签 allow 属性语法

一般建议在 Permissions-Policy 响应头中指定相对宽泛的 Permissions Policy,并在对应内嵌浏览上下文中通过 <iframe> 标签 allow 属性指定更加严格的 Permissions Policy

基本语法

1
<iframe src="<origin>" allow="<directive> <allowlist>"></iframe>

示例

1
2
3
<iframe src="https://example.com" allow="geolocation 'none'"></iframe>
<iframe src="https://example.com" allow="geolocation 'self' https://a.example.com https://b.example.com"></iframe>
<iframe src="https://example.com" allow="geolocation 'self' https://a.example.com https://b.example.com; fullscreen 'none'"></iframe>

链接

Popover API

Popover API 提供了标准化的显示弹出窗口的形式

Popover API 可以通过 HTML 控制或通过 JavaScript 控制

设置弹出元素

向 HTML 元素指定 popover 属性,以将元素指定为可弹出的,值需要为 automanual 或空字符串之一

auto 代表仅允许显示单个弹出窗口,允许自动关闭弹出窗口

manual 代表允许显示多个弹出窗口,允许手动关闭弹出窗口

1
<div id="popover" popover="auto"></div>

同样可以通过 HTMLElement 接口的 popover 属性指定

1
popoverElement.popover = 'auto';

设置弹出元素的控制元素

控制元素必须为 <button> 元素或 <input type="button" /> 元素

向 HTML 元素指定 popovertarget 属性以设置控制元素控制的弹出元素,值是弹出元素的 id

向 HTML 元素指定 popovertargetaction 属性以设置控制元素的控制行为,值为 hide show toggle 之一

1
<button popovertarget="popover" popovertargetaction="toggle">popover</button>

同样可以通过 HTMLElement 接口的 popoverTargetElement 属性指定控制元素控制的弹出元素,值需要接受一个 HTMLElement

同样可以通过 HTMLElement 接口的 popoverTargetAction 属性指定控制元素的控制行为

1
2
targetElement.popoverTargetElement = popoverElement;
targetElement.popoverTargetAction = 'toggle';

控制弹出元素

调用 HTMLElement 接口的 showPopover() 方法显示弹出窗口

调用 HTMLElement 接口的 hidePopover() 方法隐藏弹出窗口

showPopover() 方法与 hidePopover() 方法在已处于相应状态时会抛出 InvalidStateError 异常

调用 HTMLElement 接口的 togglePopover() 方法切换弹出窗口

togglePopover() 方法允许接受一个 force 参数,以指定期望的行为,但不会抛出异常;并且会返回执行的结果

1
2
3
popoverElement.showPopover();
popoverElement.hidePopover();
popoverElement.togglePopover();

弹出元素事件

beforetoggle 事件在元素的弹出状态改变前触发

toggle 事件在元素的弹出状态改变后触发

两事件均返回一个 ToggleEvent 事件,事件的 newState 属性和 oldState 属性返回 closedopen 之一

弹出元素 CSS 相关

可以利用 :popover-open 伪类选择器选中处于 popover 显示状态的元素

可以利用 ::backdrop 伪元素选择器选中 top-layer 背后的内容并进行特殊的定制

示例

popover window

链接

Device Memory API

Device Memory API 允许获取运行内存容量的大小

JS 使用

通过 Navigator 接口或 WorkerNavigator 接口的 deviceMemory 只读属性使用

返回的值是一个 number 值,0.25 0.5 1 2 4 8

HTTP 使用

服务器在 Accept-CH 响应头中指定 Device-Memory 值,或通过 HTML <meta> 标签的 http-equiv 属性指定

1
Accept-CH: Device-Memory

之后用户代理会通过 Device-Memory 请求头携带对应的信息,具体值同 deviceMemory 属性,如:

1
Device-Memory: 1

类型

1
2
3
4
5
6
7
interface NavigatorDeviceMemory {
readonly deviceMemory: number
}

interface Navigator extends NavigatorDeviceMemory {}

interface WorkerNavigator extends NavigatorDeviceMemory {}

链接

History API

History API 提供了管理浏览会话历史记录的方式

通过 window.history 暴露的 History 接口实例使用

浏览会话历史记录前进后退

History 接口的 back() 方法使浏览会话历史记录后退一条

History 接口的 forward() 方法使浏览会话历史记录前进一条

1
2
history.back()
history.forward()

浏览会话历史记录指定跳转

History 接口的 go() 方法使浏览会话历史记录前进或后退指定数量的记录

传递正数则前进,传递负数则后退

特别的,传递 1 等价于调用 history.forward(),传递 -1 等价于调用 history.back(),传递 0 或不传递参数等价于调用 location.reload()

1
2
3
4
history.go(-1)
history.go(1)
history.go(0)
history.go()

浏览会话历史记录信息

History 接口的 length 只读属性指定当前浏览会话历史记录的数量

1
history.length

History 接口的 scrollRestoration 属性读取或设置浏览会话历史记录默认的导航恢复滚动行为

auto 代表会存储滚动位置,恢复后会自动滚动到存储的位置

manual 代表不会存储滚动位置,恢复后不会自动滚动到存储的位置

1
history.scrollRestoration

浏览会话历史记录数据

History 接口的 state 只读属性反映当前浏览会话历史记录对应的数据,初始为 null 直至调用 pushState() 方法或 replaceState() 方法修改

History 接口的 pushState() 方法向浏览会话历史记录中添加一条历史记录,并更新数据与 URL

History 接口的 replaceState() 方法在浏览会话历史记录中替换当前历史记录,并更新数据与 URL

两方法接收一个 state 参数,可以为任意可序列化的对象或 null,代表与对应的浏览会话历史记录相关的数据

两方法接收一个 unused 参数,因历史原因保留但不再使用,建议传递一个空字符串

两方法接收一个可选的 url 参数,代表与对应的浏览会话历史记录的 URL,受同源策略限制

监听浏览会话历史记录变化

Window 接口的 popstate 事件在浏览会话历史记录变化时触发,返回一个 PopStateEvent 事件

可通过 PopStateEvent 事件的 state 参数读取对应浏览会话历史记录的数据

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface History {
readonly length: number
scrollRestoration: ScrollRestoration
readonly state: any
back(): void
forward(): void
go(delta?: number): void
pushState(data: any, unused: string, url?: string | URL | null): void
replaceState(data: any, unused: string, url?: string | URL | null): void
}

declare var History: {
prototype: History
}

type ScrollRestoration = "auto" | "manual"

链接

Location API

Location API 提供获取和管理当前网页的 URL 的方法

通过 document.locationwindow.location 暴露的 Location 接口实例使用

Location 属性

Location 接口的 ancestorOrigins 只读属性返回一个 DOMStringList,倒序返回所有祖先浏览上下文的源

Location 接口的 hash 属性返回一个 string,代表当前文档 URL 的片段标识符,包含 # 符号

Location 接口的 host 属性返回一个 string,代表当前文档 URL 的主机(包含主机名及端口)

Location 接口的 hostname 属性返回一个 string,代表当前文档 URL 的主机名

Location 接口的 href 属性返回一个 string,代表当前文档 URL 本身

Location 接口的 origin 只读属性返回一个 string,代表当前文档 URL 的源

Location 接口的 pathname 属性返回一个 string,代表当前文档 URL 的路径

Location 接口的 port 属性返回一个 string,代表当前文档 URL 的端口

Location 接口的 protocol 属性返回一个 string,代表当前文档 URL 的协议,包含 : 符号

Location 接口的 search 属性返回一个 string,代表当前文档 URL 的搜索参数,包含 ? 符号

1
2
3
4
5
6
7
8
9
10
11
12
/**
* assume current document's URL is https://example.org:8080/foo/bar?q=baz#bang
*/
location.hash // #bang
location.host // example.org:8080
location.hostname // example.org
location.href // https://example.org:8080/foo/bar?q=baz#bang
location.origin // https://example.org:8080
location.pathname // /foo/bar
location.port // ?q=baz
location.protocol // 8080
location.search // https:

Location 方法

Location 接口的 assign() 方法使用给定 URL 加载新文档(不会替换当前文档对应的历史记录)

方法可能抛出 SecurityError 异常,若调用该方法的域与原域不同源时发生

方法可能抛出 SyntaxError 异常,若尝试解析 URL 参数失败

Location 接口的 reload() 方法用于重新加载当前文档

方法可能抛出 SecurityError 异常,若调用该方法的域与原域不同源时发生

Location 接口的 replace() 方法用于使用给定 URL 重新加载当前文档(会替换当前文档对应的历史记录)

方法可能抛出 SyntaxError 异常,若尝试解析 URL 参数失败

Location 接口的 toString() 方法用于获取当前文档 URL 本身,效果同 href 属性

示例

Hash Host Hostname Href Origin Pathname Port Protocol Search

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface Location {
readonly ancestorOrigins: DOMStringList
hash: string
host: string
hostname: string
href: string;
toString(): string
readonly origin: string
pathname: string
port: string
protocol: string
search: string
assign(url: string | URL): void
reload(): void
replace(url: string | URL): void
}

declare var Location: {
prototype: Location
}

interface Document {
get location(): Location
set location(href: string | Location)
}

interface Window {
get location(): Location
set location(href: string | Location)
}

链接

Navigation API

Navigation API 提供了启动、拦截和管理浏览器导航行为的能力,同时允许检查应用的历史条目

该 API 是对 History API 和 Location 的扩展和补充

该 API 旨在提供 SPA (Single-Page Applications) 应用所需的功能

该 API 通过 Window 接口的 navigation 指定属性访问全局的 Navigation 实例使用

导航历史记录获取

Navigation 接口的 entries() 方法返回所有导航历史记录

方法返回一个 NavigationHistoryEntry 数组

1
2
3
function getNavigateEntries() {
return window.navigation.entries()
}

Navigation 接口的 currentEntry 只读属性返回一个 NavigationHistoryEntry,返回当前的导航历史记录

导航历史记录操作

Navigation 接口的 navigate() 方法用于导航至指定 URL,并更新导航历史记录

方法接受一个字符串参数,代表导航目标的 URL

方法接受一个可选的配置项:参数 info 允许传递自定义的任何类型的数据,该参数可通过触发的 navigate 事件后通过返回的 NavigateEvent 事件的 info 参数传递;参数 state 允许传递自定义的任何可结构化克隆类型的数据,该参数可通过与之相应的 NavigationHistoryEntry 实例的 getState() 方法获取;参数 history 允许传递 auto (默认 push,特定情况下 replacepush (新增一条 NavigationHistoryEntry 记录) replace (替代当前 NavigationHistoryEntry 记录) 字符串中之一,默认值 auto

两方法均返回一个对象,对象的 committed 参数在可见 URL 改变,同时新的 NavigationHistoryEntry 实例创建时完成,对象的 finished 参数在所有 intercept() 方法完成时完成(等价于 NavigationTransition 接口的 finished 属性完成,同时 navigatesuccess 事件触发),两参数均返回 Promise 的 NavigationHistoryEntry 实例

方法可能抛出 SyntaxError 异常,如 URL 解析失败

方法可能抛出 NotSupportedError 异常,如 history 选项设定为 push 且当前显示 about:blank 页面或 URL 协议为 javascript

方法可能抛出 DataCloneError 异常,如 state 选项数据无法被结构化克隆

方法可能抛出 InvalidStateError 异常,如当前文档未处于活跃状态或当前文档处于卸载中状态或当前记录处于第一条或最后一条

方法可能抛出 AbortError 异常,若当前导航被终止

1
2
3
4
5
6
async function handleNavigate() {
await window.navigation.navigate('/newPage', {
info: { newInfo: 'newInfo' },
state: { newState: 'newState' },
}).finished
}

Navigation 接口的 reload() 方法用于重新加载当前 URL

方法接受一个可选的配置项:参数 info 允许传递自定义的任何类型的数据,该参数可通过触发的 navigate 事件后通过返回的 NavigateEvent 事件的 info 参数传递;参数 state 允许传递自定义的任何可结构化克隆类型的数据,该参数可通过与之相应的 NavigationHistoryEntry 实例的 getState() 方法获取

两方法均返回一个对象,对象的 committed 参数在可见 URL 改变,同时新的 NavigationHistoryEntry 实例创建时完成,对象的 finished 参数在所有 intercept() 方法完成时完成(等价于 NavigationTransition 接口的 finished 属性完成,同时 navigatesuccess 事件触发),两参数均返回 Promise 的 NavigationHistoryEntry 实例

方法可能抛出 DataCloneError 异常,如 state 选项数据无法被结构化克隆

方法可能抛出 InvalidStateError 异常,如当前文档未处于活跃状态或当前文档处于卸载中状态或当前记录处于第一条或最后一条

1
2
3
4
5
async function handleReload() {
await window.navigation.reload({
state: { ...navigation.currentEntry.getState(), newState: 'newState' },
}).finished
}

Navigation 接口的 updateCurrentEntry() 方法用于更新当前导航历史记录的 state 数据,同时避免执行重新加载和导航操作

方法可能抛出 DataCloneError 异常,如 state 选项数据无法被结构化克隆

方法可能抛出 InvalidStateError 异常,如 Navigation.currentEntrynull,即当前页面为 about:blank

1
2
3
4
5
function updateCurrentState() {
window.navigation.updateCurrentEntry({
state: { newState: 'newState' },
})
}

导航历史记录前进或后退

Navigation 接口的 canGoBack 只读属性返回一个 boolean,表示当前是否可以进行导航后退,例如当前记录为导航历史记录中第一条

Navigation 接口的 canGoForward 只读属性返回一个 boolean,表示当前是否可以进行导航前进,例如当前记录为导航历史记录中最后一条

Navigation 接口的 back() 方法在导航历史记录向后导航一条记录

Navigation 接口的 forward() 方法在导航历史记录向前导航一条记录

两方法均接受一个可选的配置项,配置项唯一参数 info 允许传递自定义的任何类型的数据,该参数通过触发的 navigate 事件后通过返回的 NavigateEvent 事件的 info 参数传递

两方法均返回一个对象,对象的 committed 参数在可见 URL 改变,同时新的 NavigationHistoryEntry 实例创建时完成,对象的 finished 参数在所有 intercept() 方法完成时完成(等价于 NavigationTransition 接口的 finished 属性完成,同时 navigatesuccess 事件触发),两参数均返回 Promise 的 NavigationHistoryEntry 实例

两方法均在导航目标超出范围时抛出 InvalidStateError 异常,如当前文档未处于活跃状态或当前文档处于卸载中状态或当前记录处于第一条或最后一条

1
2
3
4
5
6
7
8
9
10
11
async function goBack() {
if (window.navigation.canGoBack) {
await window.navigation.back().finished
}
}

async function goForward() {
if (window.navigation.canGoForward) {
await window.navigation.forward().finished
}
}

导航历史记录指定跳转

Navigation 接口的 traverseTo() 方法在导航历史记录中导航至指定历史记录

方法接受一个字符串参数,代表指定历史记录的唯一标识,与 NavigationHistoryEntry 实例的 key 参数类似

方法接受一个可选的配置项,配置项唯一参数 info 允许传递自定义的任何类型的数据,该参数通过触发的 navigate 事件后通过返回的 NavigateEvent 事件的 info 参数传递

方法在导航目标超出范围时抛出 InvalidStateError 异常,如当前文档未处于活跃状态或 key 参数对应的记录不存在

1
2
3
function initBackToHomeButton() {
BackToHomeButton.onclick = window.navigation.traverseTo(window.navigation.currentEntry.key)
}

导航历史记录跳转监听

Navigation 接口的 currententrychange 事件在当前导航记录内容变化时触发,返回一个 NavigationCurrentEntryChangeEvent 事件

可能原因包括,相同文档内导航 forward() back() traverseTo();替换当前记录 navigate() 方法并设置 history 参数为 replace;更新当前记录数据 updateCurrentEntry() 等等

NavigationCurrentEntryChangeEvent 事件继承自 Event 事件,反映了 currententrychange 事件触发时返回的事件实例

NavigationCurrentEntryChangeEvent 事件的 from 只读属性返回一个 NavigationHistoryEntry,代表来源的导航历史记录

NavigationCurrentEntryChangeEvent 事件的 navigationType 只读属性返回一个 string,值为 push (至新纪录) replace (替换当前记录) reload (重新加载当前记录) traverse (至已有记录) 之一;若因为调用 Navigation 接口的 updateCurrentEntry() 方法导致的,返回 null

1
2
3
4
5
6
7
8
window.navigation.addEventListener("currententrychange", () => {
const data = window.navigation.currentEntry.getState()
// to do something with the data

window.navigation.currentEntry.addEventListener("dispose", () => {
// do something when disposing
})
})

Navigation 接口的 navigate 事件在任一导航类型事件发生时触发,返回一个 NavigateEvent 事件

NavigateEvent 事件继承自 Event 事件,反映了 navigate 事件触发时返回的事件实例

NavigateEvent 事件的 destination 只读属性返回一个 NavigationDestination 实例,反映导航的目标

NavigationDestination 接口类似于 NavigationHistoryEntry 接口,除其不支持 dispose 事件外类似

NavigateEvent 事件的 navigationType 只读属性返回一个 string,值为 push(至新纪录) replace(替换当前记录) reload(重新加载当前记录) traverse(至已有记录)之一,代表导航的类型

NavigateEvent 事件的 canIntercept 只读属性返回一个 boolean,表示导航是否可被拦截并重写 URL(通常跨域导航无法被拦截)

NavigateEvent 事件的 userInitiated 只读属性返回一个 boolean,表示导航是否因用户行为而发生的

NavigateEvent 事件的 hashChange 只读属性返回一个 boolean,表示导航是否是一个片段导航,即仅 URL 的 hash 部分发生改变

NavigateEvent 事件的 signal 只读属性返回一个 AbortSignal,其会在导航取消时终止(一个使用场合是传递给导航内的 fetch 函数以安全地取消请求)

NavigateEvent 事件的 formData 只读属性返回一个 FormData,若导航因为提交表单发生;否则返回 null

NavigateEvent 事件的 downloadRequest 只读属性返回一个 string,代表请求下载的文件名,若请求因为点击 download 的链接导致;否则返回 null

NavigateEvent 事件的 info 只读属性返回在导航操作中传递的 info 参数;若为传递则返回 undefined

NavigateEvent 事件的 hasUAVisualTransition 只读属性返回一个 boolean,表示用户代理是否进行了可视化的导航过渡进程

NavigateEvent 事件的 intercept() 方法允许拦截导航并控制导航的行为

NavigateEvent 事件的 scroll() 方法允许主动触发导航滚动行为

Navigation 接口的 navigateerror 事件在导航操作失败时触发,返回一个 Event 事件

Navigation 接口的 navigatesuccess 事件在导航操作成功完成时触发,返回一个 Event 事件

此时刻 intercept() 方法中传递的所有 Promise 均完成且 NavigationTransition.finished 同样完成

1
2
3
4
5
6
7
8
9
window.navigation.addEventListener("navigatesuccess", () => {
loadingIndicator.hidden = true
})

window.navigation.addEventListener("navigateerror", (event) => {
loadingIndicator.hidden = true

showMessage(`Failed to load page: ${event.message}`)
})

导航历史记录信息

NavigationHistoryEntry 接口表示单条导航历史记录

NavigationHistoryEntry 接口的 id 只读属性返回一个 string,代表当前导航历史记录的 id,该值是一个唯一的由用户代理生成的值

NavigationHistoryEntry 接口的 index 只读属性返回一个 number,代表当前导航历史记录在导航历史记录列表中的下标,若不在时返回 -1

NavigationHistoryEntry 接口的 key 只读属性返回一个 string,代表当前导航历史记录在导航历史记录列表中的位置的 key,该值是一个唯一的由用户代理生成的值,可以用于 Navigation 接口的 traverseTo() 方法

NavigationHistoryEntry 接口的 sameDocument 只读属性返回一个 boolean,代表当前的当前导航历史记录对应的 document 对象是否与 document 对象相同

NavigationHistoryEntry 接口的 url 只读属性返回一个 string,代表当前导航历史记录的绝对 URL,若受 Referer Policy 限制可能返回 null

NavigationHistoryEntry 接口的 getState() 方法返回与当前导航历史记录绑定的 state 数据的拷贝,若不存在则返回 undefined

NavigationHistoryEntry 接口的 dispose 事件在当前导航历史记录被移除时触发,返回一个 Event 事件

导航历史记录进程

NavigationTransition 接口代表正在进行中的导航(即尚未触发 navigatesuccessnavigateerror 事件的导航),通过 Navigation 接口的 transition 属性访问

NavigationTransition 接口的 navigationType 只读属性返回一个 string,值为 push(至新纪录) replace(替换当前记录) reload(重新加载当前记录) traverse(至已有记录)之一,代表导航的类型

NavigationTransition 接口的 from 只读属性返回一个 NavigationHistoryEntry,代表来源的导航历史记录

NavigationTransition 接口的 finished 只读属性返回一个 Promise,在 navigatesuccessnavigateerror 事件触发同时兑现或拒绝

1
2
3
4
5
6
7
async function handleTransition() {
if (navigation.transition != null) {
showLoadingSpinner();
await navigation.transition.finished;
hideLoadingSpinner();
}
}

导航历史记录拦截

NavigateEvent 事件的 intercept() 方法允许拦截导航并控制导航的行为

方法允许接收一个配置项:

选项 handler 指定拦截器的处理回调方法,回调方法允许返回一个 Promise

选项 focusReset 指定导航的聚焦行为,值可以为 after-transition(默认值)或 manual

选项 scroll 指定导航的滚动行为,值可以为 after-transition(默认值)或 manual

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
window.navigation.addEventListener("navigate", (event) => {
if (shouldNotIntercept(navigateEvent)) {
return;
}
const url = new URL(event.destination.url);

if (url.pathname.startsWith("/articles/")) {
event.intercept({
async handler() {
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);

event.scroll();

const secondaryContent = await getSecondaryContent(url.pathname);
addSecondaryContent(secondaryContent);
},
});
}
});

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
interface Window {
readonly navigation: Navigation
}

interface Navigation extends EventTarget {
entries(): NavigationHistoryEntry[]
readonly currentEntry?: NavigationHistoryEntry
updateCurrentEntry(options: NavigationUpdateCurrentEntryOptions): void
readonly transition?: NavigationTransition

navigate(url: string, options?: NavigationNavigateOptions): NavigationResult
reload(options?: NavigationReloadOptions): NavigationResult

readonly canGoBack: boolean
readonly canGoForward: boolean

back(options?: NavigationOptions): NavigationResult
forward(options?: NavigationOptions): NavigationResult
traverseTo(key: string, options?: NavigationOptions): NavigationResult

oncurrententrychange: ((this: Navigation, ev: NavigationCurrentEntryChangeEvent) => any) | null
onnavigate: ((this: Navigation, ev: NavigateEvent) => any) | null
onnavigateerror: ((this: Navigation, ev: Event) => any) | null
onnavigatesuccess: ((this: Navigation, ev: Event) => any) | null
}

declare var Navigation: {
prototype: Navigation
}

interface NavigationUpdateCurrentEntryOptions {
state: any
}

interface NavigationOptions {
info?: any
}

interface NavigationNavigateOptions extends NavigationOptions {
state?: any
history?: NavigationHistoryBehavior
}

interface NavigationReloadOptions extends NavigationOptions {
state?: any
}

interface NavigationResult {
committed: Promise<NavigationHistoryEntry>
finished: Promise<NavigationHistoryEntry>
}

enum NavigationHistoryBehavior {
"auto",
"push",
"replace",
}

enum NavigationType {
"push",
"replace",
"reload",
"traverse",
}

interface NavigationHistoryEntry extends EventTarget {
readonly url: string | null
readonly key: string
readonly id: string
readonly index: number
readonly sameDocument: boolean

getState(): any

ondispose: ((this: NavigationHistoryEntry, ev: Event) => any) | null
}

declare var NavigationHistoryEntry: {
prototype: NavigationHistoryEntry
}

interface NavigationTransition {
readonly navigationType: NavigationType
readonly from: NavigationHistoryEntry
readonly finished: Promise<undefined>
}

declare var NavigationTransition: {
prototype: NavigationTransition
}

interface NavigationCurrentEntryChangeEvent extends Event {
readonly navigationType: NavigationType | null
readonly from: NavigationHistoryEntry
}

declare var NavigationCurrentEntryChangeEvent: {
new(type: string, eventInitDict: NavigationCurrentEntryChangeEventInit): NavigationCurrentEntryChangeEvent
prototype: NavigationCurrentEntryChangeEvent
}

interface NavigationCurrentEntryChangeEventInit extends EventInit {
navigationType?: NavigationType
from: NavigationHistoryEntry
}

interface NavigateEvent extends Event {
readonly navigationType: NavigationType
readonly destination: NavigationDestination
readonly canIntercept: boolean
readonly userInitiated: boolean
readonly hashChange: boolean
readonly signal: AbortSignal
readonly formData?: FormData
readonly downloadRequest?: string
readonly info: any
readonly hasUAVisualTransition: boolean

intercept(options?: NavigationInterceptOptions): void
scroll(): void
}

declare var NavigateEvent: {
new(type: string, eventInitDict: NavigateEventInit): NavigateEvent
prototype: NavigateEvent
}

interface NavigateEventInit extends EventInit {
navigationType?: NavigationType
destination: NavigationDestination
canIntercept?: boolean
userInitiated?: boolean
hashChange?: boolean
signal: AbortSignal
formData?: FormData
downloadRequest?: string
info: any
hasUAVisualTransition?: boolean
}

interface NavigationInterceptOptions {
handler?: NavigationInterceptHandler
focusReset?: NavigationFocusReset
scroll?: NavigationScrollBehavior
}

enum NavigationFocusReset {
"after-transition",
"manual",
}

enum NavigationScrollBehavior {
"after-transition",
"manual",
}

type NavigationInterceptHandler = () => Promise<undefined>

interface NavigationDestination {
readonly url: string
readonly key: string
readonly id: string
readonly index: number
readonly sameDocument: boolean

getState(): any
}

declare var NavigationDestination: {
prototype: NavigationDestination
}

链接

Pointer Events

Pointer Events 定义指针相关的一系列事件

旨在为 Mouse Events 和 Touch Events 在不同平台上提供统一的行为

指针事件列表

事件名称 事件类型 事件目标 事件是否冒泡 事件是否可取消 事件描述
pointerenter PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针移入元素及其子元素
pointerleave PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针移出元素及其子元素
pointerdown PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 元素上按下指针
pointermove PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针在元素内移动
pointerup PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 元素上释放指针
pointerover PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针移入元素及其子元素
pointerout PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针移出元素及其子元素
pointercancel PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针操作被取消
pointerrawupdate PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 指针操作不触发 pointerdown 与 pointerup 事件
gotpointercapture PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 进入指针捕获模式
lostpointercapture PointerEvent Window,Document,HTMLElement,SVGElement,MathMLElement 离开指针捕获模式

其中 pointerrawupdate 事件仅限严格模式使用

指针事件

PointerEvent 接口表示一个指针事件

指针捕获

Element 接口的 setPointerCapture() 方法用于给指定的指针ID设置一个指针捕获

Element 接口的 releasePointerCapture() 方法用于给指定的指针ID释放一个指针捕获

Element 接口的 hasPointerCapture() 方法用于检测当前元素是否处于指定的指针ID下的指针捕获状态,返回一个 boolean

以上三个方法均接受一个 number 参数,代表指针 ID

触摸点数量

Navigator 接口的 maxTouchPoints 只读属性返回 number,代表设备能够同时支持的触摸点的最大数量

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Element {
hasPointerCapture(pointerId: number): boolean
releasePointerCapture(pointerId: number): void
setPointerCapture(pointerId: number): void
}

interface GlobalEventHandlers {
ongotpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onlostpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointercancel: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerdown: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerenter: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerleave: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointermove: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerout: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerover: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerrawupdate: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
onpointerup: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null
}

interface Navigator {
readonly maxTouchPoints: number
}

链接

Touch Events

Touch Events 定义与用户触摸交互的事件

触摸事件列表

事件名称 事件类型 事件目标 事件是否冒泡 事件是否可取消 事件描述
touchstart TouchEvent Window,Document,HTMLElement,SVGElement,MathMLElement 视情况而定 触摸点放置到触摸面上
touchmove TouchEvent Window,Document,HTMLElement,SVGElement,MathMLElement 视情况而定 触摸点在触摸面上移动
touchend TouchEvent Window,Document,HTMLElement,SVGElement,MathMLElement 视情况而定 触摸点从触摸板上移除
touchcancel TouchEvent Window,Document,HTMLElement,SVGElement,MathMLElement 触摸行为被特定于实现被中断

触摸事件

TouchEvent 接口表示一个触摸事件

TouchList 接口表示一组触摸点

Touch 接口表示单个触摸点

类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
interface GlobalEventHandlers {
ontouchcancel?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined
ontouchend?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined
ontouchmove?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined
ontouchstart?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined
}

interface Touch {
readonly clientX: number
readonly clientY: number
readonly force: number
readonly identifier: number
readonly pageX: number
readonly pageY: number
readonly radiusX: number
readonly radiusY: number
readonly rotationAngle: number
readonly screenX: number
readonly screenY: number
readonly target: EventTarget
}

declare var Touch: {
prototype: Touch
new(touchInitDict: TouchInit): Touch
}

interface TouchInit {
altitudeAngle?: number
azimuthAngle?: number
clientX?: number
clientY?: number
force?: number
identifier: number
pageX?: number
pageY?: number
radiusX?: number
radiusY?: number
rotationAngle?: number
screenX?: number
screenY?: number
target: EventTarget
touchType?: TouchType
}

interface TouchEvent extends UIEvent {
readonly altKey: boolean
readonly changedTouches: TouchList
readonly ctrlKey: boolean
readonly metaKey: boolean
readonly shiftKey: boolean
readonly targetTouches: TouchList
readonly touches: TouchList
}

declare var TouchEvent: {
prototype: TouchEvent
new(type: string, eventInitDict?: TouchEventInit): TouchEvent
}

interface TouchEventInit extends EventModifierInit {
changedTouches?: Touch[]
targetTouches?: Touch[]
touches?: Touch[]
}

interface TouchList {
readonly length: number
item(index: number): Touch | null
[index: number]: Touch
}

declare var TouchList: {
prototype: TouchList
}

type TouchType = 'direct' | 'stylus'

链接


:D 一言句子获取中...