Presentation API - 允许用户代理通过大型演示设备有效地显示 Web 内容
这是一个实验中的功能
此功能某些浏览器尚在开发中,请参考浏览器兼容性表格以得到在不同浏览器中适合使用的前缀。由于该功能对应的标准文档可能被重新修订,所以在未来版本的浏览器中该功能的语法和行为可能随之改变。
Presentation API(演示控制器 API)允许用户代理(例如 Web 浏览器)通过大型演示设备(例如投影仪和联网电视)有效地显示 Web 内容。支持的多媒体设备类型包括使用 HDMI、DVI 等有线连接的显示器,或使用 DLNA、Chromecast、AirPlay 或 Miracast 的无线显示器。
通常,网页使用 Presentation Controller API 来指定要在演示设备上呈现的 Web 内容并启动演示会话。使用 Presentation Receiver API,呈现的 Web 内容获取会话状态。通过为控制器页面和接收器页面提供基于消息的通道,Web 开发人员可以实现这两个页面之间的交互。
根据呈现设备提供的连接机制,任何控制器和接收器页面都可以由同一个用户代理呈现,也可以由不同的用户代理呈现。
- 对于 1-UA 模式设备,两个页面都由同一个用户代理加载。但是,接收方页面的渲染结果将通过支持的远程渲染协议发送到展示设备。
- 对于 2-UA 模式设备,接收器页面直接加载到演示设备上。控制用户代理通过支持的显示控制协议与显示设备通信,以控制显示会话并在两个页面之间传输消息。
接口
Presentation
在控制浏览上下文中,Presentation
接口提供了一种机制,以覆盖浏览器启动演示到外部屏幕的默认行为。在接收浏览上下文中,Presentation
接口提供了访问可用演示连接的方法。
PresentationRequest
启动或重新连接到由控制浏览上下文所做的演示。
PresentationAvailability
PresentationAvailability
对象表示可用的演示显示,并表示演示请求的显示可用性。
PresentationConnectionAvailableEvent
创建与对象关联的连接时,会在 PresentationRequest
上触发 PresentationConnectionAvailableEvent
。
PresentationConnection
每个演示连接由一个 PresentationConnection
对象表示。
PresentationConnectionCloseEvent
当演示连接进入 closed
状态时,会触发 PresentationConnectionCloseEvent
。
PresentationReceiver
PresentationReceiver
允许接收浏览上下文,来访问控制浏览上下文并与它们通信。
PresentationConnectionList
PresentationConnectionList
表示未终止的演示连接的集合。它也是新的可用演示连接事件的监视器。
实例
下面的实例代码突出显示了 Presentation API 主要功能的使用:controller.html
实现了控制器,而 presentation.html
实现了演示。这两个页面都来自域 http://example.org
(http://example.org/controller.html
和 http://example.org/presentation.html
)。这些示例假定控制页面一次管理一个演示文稿。有关更多详细信息,请参阅代码示例中的注释。
监控演示显示的可用性
<!-- controller.html -->
<button id="presentBtn" style="display: none;">Present</button>
<script>
// 如果至少有一个演示显示可用,则演示按钮可见
var presentBtn = document.getElementById("presentBtn");
// 也可以使用相对路径表示 URL,例如 “presentation.html”
var presUrls = ["http://example.com/presentation.html",
"http://example.net/alternate.html"];
// 根据显示可用性显示或隐藏当前按钮
var handleAvailabilityChange = function(available) {
presentBtn.style.display = available ? "inline" : "none";
};
// 一旦知道演示文稿显示的可用性,Promise 就会得到解析。
var request = new PresentationRequest(presUrls);
request.getAvailability().then(function(availability) {
// 只要可用性对象处于活动状态,控制 UA 就可以获得 `availability.value` 的最新值。
handleAvailabilityChange(availability.value);
availability.onchange = function() { handleAvailabilityChange(this.value); };
}).catch(function() {
// 平台不支持可用性监控,因此只有在调用 `request.start()` 后才会发现演示显示。为了简单起见,假装这些设备可用;或者,可以为按钮实现第三种状态。
handleAvailabilityChange(true);
});
</script>
开始新的演示
<!-- controller.html -->
<script>
presentBtn.onclick = function () {
// 开始新的演示。
request.start()
// 成功时,与演示的连接将被传递给 setConnection。
.then(setConnection);
// 否则,则是用户取消了选择对话框或没有找到任何屏幕。
};
</script>
重新连接到演示
<!-- controller.html -->
<button id="reconnectBtn" style="display: none;">重新连接</button>
<script>
var reconnect = function () {
// 如果存在,则从 localStorage 读取 presId
var presId = localStorage["presId"];
// 重新连接到演示时,pressId 是必需的。
if (!!presId) {
request.reconnect(presId)
// 成功时,演示文稿的新连接将传递给 setConnection。
.then(setConnection);
// 否则是未找到 presUrl 和 presId 的连接,或发生错误。
}
};
// 在控制器发生导航时,自动重新连接。
document.addEventListener("DOMContentLoaded", reconnect);
// 或者允许手动重新连接。
reconnectBtn.onclick = reconnect;
</script>
由控制 UA 发起的演示
<!-- controller.html -->
<!-- 设置 presentation.defaultRequest 允许页面指定在控制 UA 启动演示时要使用的 PresentationRequest。 -->
<script>
navigator.presentation.defaultRequest = new PresentationRequest(presUrls);
navigator.presentation.defaultRequest.onconnectionavailable = function(evt) {
setConnection(evt.connection);
};
</script>
监控连接状态并交换数据
<!-- controller.html -->
<button id="disconnectBtn" style="display: none;">断开</button>
<button id="stopBtn" style="display: none;">停止</button>
<button id="reconnectBtn" style="display: none;">重新连接</button>
<script>
let connection;
// 如果有连接的演示,则断开连接和停止按钮可见
const stopBtn = document.querySelector("#stopBtn");
const reconnectBtn = document.querySelector("#reconnectBtn");
const disconnectBtn = document.querySelector("#disconnectBtn");
stopBtn.onclick = _ => {
connection && connection.terminate();
};
disconnectBtn.onclick = _ => {
connection && connection.close();
};
function setConnection(newConnection) {
// 如果不尝试重新连接,则断开与现有演示的连接
if (connection && connection != newConnection && connection.state != 'closed') {
connection.onclosed = undefined;
connection.close();
}
// 设置新连接并保存演示 ID
connection = newConnection;
localStorage["presId"] = connection.id;
function showConnectedUI() {
// 允许用户断开或终止演示
stopBtn.style.display = "inline";
disconnectBtn.style.display = "inline";
reconnectBtn.style.display = "none";
}
function showDisconnectedUI() {
disconnectBtn.style.display = "none";
stopBtn.style.display = "none";
reconnectBtn.style.display = localStorage["presId"] ? "inline" : "none";
}
// 监控连接状态
connection.onconnect = _ => {
showConnectedUI();
// 注册消息处理程序
connection.onmessage = message => {
console.log(`收到消息:${message.data}`);
};
// 将初始消息发送到演示页面
connection.send("问好");
};
connection.onclose = _ => {
connection = null;
showDisconnectedUI();
};
connection.onterminate = _ => {
// localStorage 如果存在 presId,则将其删除
delete localStorage["presId"];
connection = null;
showDisconnectedUI();
};
};
</script>
监控可用连接并打个招呼
<!-- presentation.html -->
<script>
var addConnection = function(connection) {
this.onmessage = function (message) {
if (message.data === "问好")
this.send("你好");
};
};
navigator.presentation.receiver.connectionList.then(function (list) {
list.connections.map(function (connection) {
addConnection(connection);
});
list.onconnectionavailable = function (evt) {
addConnection(evt.connection);
};
});
</script>
使用消息传递本地化信息
<!-- controller.html -->
<script>
connection.send("{string: '你好,世界!', lang: 'zh-CN'}");
connection.send("{string: 'こんにちは、世界!', lang: 'ja'}");
connection.send("{string: '안녕하세요, 세계!', lang: 'ko'}");
connection.send("{string: 'Hello, world!', lang: 'en-US'}");
</script>
<!-- presentation.html -->
<script>
connection.onmessage = function (message) {
var messageObj = JSON.parse(message.data);
var spanElt = document.createElement("SPAN");
spanElt.lang = messageObj.lang;
spanElt.textContent = messageObj.string;
document.appendChild(spanElt);
};
</script>
规范
规范 |
---|
Presentation API |
桌面浏览器兼容性
特性 | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
基础支持 | 48 | ≤79 | 51 | 不支持 | 支持 | 未知 |
defaultRequest | 48 | ≤79 | 51 | 不支持 | 支持 | 未知 |
receiver | 48 | ≤79 | 51 | 不支持 | 支持 | 未知 |
移动浏览器兼容性
特性 | Android | Chrome for Android | Edge mobile | Firefox for Android | IE mobile | Opera Android | iOS Safari |
---|---|---|---|---|---|---|---|
基础支持 | 不支持 | 48 | 未知 | 51 | 未知 | 支持 | 未知 |
defaultRequest | 不支持 | 48 | 未知 | 51 | 未知 | 支持 | 未知 |
receiver | 不支持 | 48 | 未知 | 51 | 未知 | 支持 | 未知 |
相关链接
Presentation API polyfill 包含一个符合 W3C Second Screen 工作组标准化的 Presentation API 规范的 JavaScript polyfill。polyfill 主要用于探索如何在不同的表示机制之上实现 Presentation API。