Dice Roller 代码教程
在“骰子滚筒”示例应用中,向用户显示骰子,并显示一个用于滚动骰子的按钮。 滚动骰子时,Live Share SDK 使用 Fluid Framework 跨客户端同步数据,因此每个人都会看到相同的结果。 若要同步数据,请在 app.js 文件中执行以下步骤:
设置应用程序
首先,可以导入所需的模块。 此示例使用 Live Share SDK 中的 LiveState DDS 和 LiveShareClient 。 此示例支持 Teams 会议扩展性,因此必须包含 Microsoft teams JavaScript 客户端库 (TeamsJS) 。 最后,该示例设计为在本地和 Teams 会议中运行,因此需要包含更多 Fluid Framework 部分以 在本地测试示例。
应用程序使用一个架构创建 Fluid 容器,该架构定义一组可用于容器 的初始对象 。 该示例使用 LiveState 存储已滚动的当前骰子值。
Teams 会议应用需要多个视图,例如内容、配置和阶段。 可以创建一个 start()
函数来帮助识别视图。 此函数有助于呈现和执行任何必要的初始化。 该应用支持在 Web 浏览器中本地运行,也支持从 Teams 会议中运行。 函数 start()
查找 inTeams=true
查询参数以确定它是否在 Teams 中运行。
注意
在 Teams 中运行时,应用程序需要在调用 app.initialize()
任何其他 teams-js 方法之前调用。
除了 inTeams=true
查询参数,还可以使用 view=content|config|stage
查询参数来确定需要呈现的视图。
import { app, pages, LiveShareHost } from "@microsoft/teams-js";
import { LiveShareClient, TestLiveShareHost, LiveState } from "@microsoft/live-share";
const searchParams = new URL(window.location).searchParams;
const root = document.getElementById("content");
// Define container schema
const containerSchema = {
initialObjects: { diceState: LiveState },
};
// STARTUP LOGIC
async function start() {
// Check for page to display
let view = searchParams.get("view") || "stage";
// Check if we are running on stage.
if (!!searchParams.get("inTeams")) {
// Initialize teams app
await app.initialize();
}
// Load the requested view
switch (view) {
case "content":
renderSidePanel(root);
break;
case "config":
renderSettings(root);
break;
case "stage":
default:
const { container } = await joinContainer();
renderStage(container.initialObjects.diceState, root);
break;
}
}
start().catch((error) => console.error(error));
加入 Fluid 容器
并非所有应用视图都需要协作。 视图stage
始终需要协作功能,content
视图可能需要协作功能,并且config
视图永远不需要协作功能。 对于需要协作功能的视图,必须加入与当前会议关联的 Fluid 容器。
加入会议的容器非常简单,只需使用 LiveShareHost
Teams 客户端 SDK 中的实例初始化 LiveShareClient
,然后调用其 joinContainer()
方法即可。
在本地运行时,可以改为使用 TestLiveShareHost
实例进行初始化LiveShareClient
。
async function joinContainer() {
// Are we running in Teams? If so, use LiveShareHost, otherwise use TestLiveShareHost
const host = !!searchParams.get("inTeams")
? LiveShareHost.create()
: TestLiveShareHost.create();
// Create client
const client = new LiveShareClient(host);
// Join container
return await client.joinContainer(containerSchema, onContainerFirstCreated);
}
在本地测试时, TestLiveShareHost
更新浏览器 URL 以包含创建的测试容器的 ID。 将该链接复制到其他浏览器选项卡会导致 LiveShareClient
加入创建的测试容器。 如果应用程序 URL 的修改干扰了应用程序的操作,则可以使用传递给 LiveShareClient
的 setLocalTestContainerId 和 getLocalTestContainerId 选项自定义用于存储测试容器 ID 的策略。
编写阶段视图
许多 Teams 会议扩展性应用程序设计为将 React 用于其视图框架,但这不是必需的。 例如,此示例使用标准 HTML/DOM 方法来呈现视图。
从静态视图开始
使用不带任何 Fluid 功能的本地数据轻松创建视图,然后通过更改应用的某些关键部分来添加 Fluid。
函数 renderStage
将 stageTemplate
追加到传递的 HTML 元素,并在每次选择“ 滚动 ”按钮时使用随机骰子值创建一个工作骰子滚筒。 在接下来的几个步骤中将使用 diceState
。
const stageTemplate = document.createElement("template");
stageTemplate["innerHTML"] = `
<div class="wrapper">
<div class="dice"></div>
<button class="roll"> Roll </button>
</div>
`;
function renderStage(diceState, elem) {
elem.appendChild(stageTemplate.content.cloneNode(true));
const rollButton = elem.querySelector(".roll");
const dice = elem.querySelector(".dice");
const updateDice = () => {
// Get a random value between 1 and 6
const diceValue = Math.floor(Math.random() * 6) + 1;
// Unicode 0x2680-0x2685 are the sides of a die (⚀⚁⚂⚃⚄⚅).
dice.textContent = String.fromCodePoint(0x267f + value);
};
rollButton.onclick = () => updateDice();
updateDice(1);
}
将会议 Stageview 连接到 Live Share
修改 LiveState
若要开始在应用程序中使用 Live Share,首先要更改的是当用户选择 rollButton
时发生的情况。 按钮更新中存储为 state
值 diceState
的数字,而不是直接更新本地状态。 每当使用新的 state
调用 .set()
时,该值都会分发到所有客户端。 对 diceState
的任何更改都可能导致 stateChanged
发出事件,并且事件处理程序可以触发视图的更新。
此模式在 Fluid 和 Live Share 分布式数据结构中很常见,因为它使视图能够对本地和远程更改的行为方式相同。
rollButton.onclick = () =>
diceState.set(Math.floor(Math.random() * 6) + 1);
依赖 Fluid 数据
需要进行的下一个更改是更改 函数,updateDice
以便从每次调用时updateDice
检索LiveState
最新的骰子值。
const updateDice = () => {
const diceValue = diceState.state;
dice.textContent = String.fromCodePoint(0x267f + diceValue);
};
处理远程更改
从 diceState
返回的值只是时间快照。 若要在数据更改时保持最新状态,必须向 diceState
注册事件处理程序,以便每次发送事件时stateChanged
调用 updateDice
。
diceState.on("stateChanged", updateDice);
初始化 LiveState
在开始接收应用程序中的 Live Share 更改之前,必须先对LiveState
具有初始值的对象进行调用initialize()
。 此初始值不会覆盖其他用户发送的任何现有状态。
初始化 LiveState
后,每当进行更改时, stateChanged
前面注册的事件就会开始触发。 但是,若要更新初始值内的 UI,请调用 updateDice()
。
await diceState.initialize(1);
updateDice();
编写侧面板视图
当用户在会议中打开应用时,会在侧面板中向用户显示侧面板视图,该视图通过选项卡 contentUrl
加载 sidePanel
帧上下文。 侧面板视图的目标是允许用户在将应用共享到会议阶段之前选择应用的内容。 对于 Live Share SDK 应用,侧面板视图也可用作应用的配套体验。 从侧面板视图调用 joinContainer()
将连接到 Stageview 连接到的同一 Fluid 容器。 然后,可以使用此容器与 Stageview 通信。 确保与每个人的舞台视图和侧面板视图通信。
示例的侧面板视图提示用户选择要暂存的共享按钮。
const sidePanelTemplate = document.createElement("template");
sidePanelTemplate["innerHTML"] = `
<style>
.wrapper { text-align: center }
.title { font-size: large; font-weight: bolder; }
.text { font-size: medium; }
</style>
<div class="wrapper">
<p class="title">Lets get started</p>
<p class="text">Press the share to stage button to share Dice Roller to the meeting stage.</p>
</div>
`;
function renderSidePanel(elem) {
elem.appendChild(sidePanelTemplate.content.cloneNode(true));
}
编写设置视图
在应用清单中加载configurationUrl
的设置视图在用户首次将你的应用添加到 Teams 会议时会显示给用户。 此视图允许开发人员根据用户输入配置固定到会议的选项卡的 contentUrl
。 即使无需用户输入即可设置 , contentUrl
也需要此页。
注意
选项卡settings
上下文中不支持 Live Share joinContainer()
的 。
示例的设置视图提示用户选择保存按钮。
const settingsTemplate = document.createElement("template");
settingsTemplate["innerHTML"] = `
<style>
.wrapper { text-align: center }
.title { font-size: large; font-weight: bolder; }
.text { font-size: medium; }
</style>
<div class="wrapper">
<p class="title">Welcome to Dice Roller!</p>
<p class="text">Press the save button to continue.</p>
</div>
`;
function renderSettings(elem) {
elem.appendChild(settingsTemplate.content.cloneNode(true));
// Save the configurable tab
pages.config.registerOnSaveHandler((saveEvent) => {
pages.config.setConfig({
websiteUrl: window.location.origin,
contentUrl: window.location.origin + "?inTeams=1&view=content",
entityId: "DiceRollerFluidLiveShare",
suggestedDisplayName: "DiceRollerFluidLiveShare",
});
saveEvent.notifySuccess();
});
// Enable the Save button in config dialog
pages.config.setValidityState(true);
}
在本地测试
可以使用 npm run start
在本地测试应用。 有关详细信息,请参阅 快速入门指南。
在 Teams 中测试
开始使用 npm run start
在本地运行应用后,可以在 Teams 上测试应用。 若要在不部署的情况下测试应用,请下载并使用 ngrok
隧道服务。
创建 ngrok 隧道以允许 Teams 访问你的应用
下载 ngrok。
使用 ngrok 创建具有端口 8080 的隧道。 运行以下命令:
ngrok http 8080 --host-header=localhost
将打开一个新的 ngrok 终端,其中包含一个新 URL,例如
https:...ngrok.io
。 新 URL 是指向应用的隧道,需要在应用manifest.json
中更新。
创建要上传到 Teams 的应用包
转到计算机上
live-share-sdk\samples\javascript\01.dice-roller
的 Dice Roller 示例文件夹。 还可以从 GitHub 上的 Dice Roller 示例中查看 manifest.json 。打开 manifest.json 并更新配置 URL。
将
https://<<BASE_URI_DOMAIN>>
替换为 ngrok 中的 http 终结点。可以更新以下字段:
- 将
developer.name
设置为你的姓名。 - 使用网站更新
developer.websiteUrl
。 - 使用隐私策略更新
developer.privacyUrl
。 - 使用使用条款更新
developer.termsOfUseUrl
。
- 将
压缩清单文件夹的内容以创建
manifest.zip
。 确保manifest.zip
仅包含manifest.json
源文件、color
图标和outline
图标。- 在 Windows 上,选择
.\manifest
目录中的所有文件并对其进行压缩。
注意
- 不要压缩包含的文件夹。
- 为 zip 文件提供描述性名称。 例如,
DiceRollerLiveShare
。
有关清单的详细信息,请访问 Teams 清单文档
- 在 Windows 上,选择
将自定义应用上传到会议
打开 Teams。
在 Teams 中从日历安排会议。 确保邀请至少一名与会者参加会议。
加入会议。
在顶部的会议窗口中,选择“+ 应用”>“管理应用”。
在“管理应用”窗格中,选择“上传自定义应用”。
- 如果看不到“上传自定义应用”选项,请按照 说明 在租户中启用自定义应用。
从计算机中选择并上传
manifest.zip
文件。选择“添加”以将示例应用添加到会议中。
选择“+ 应用”,在“查找应用”搜索框中键入 "Dice Roller"。
选择应用以在会议中激活它。
选择“保存”。
Dice Roller 应用将添加到 Teams 会议面板。
在侧面板中,选择要暂存的共享图标。 Teams 开始与会议阶段的用户进行实时同步。
你现在应该会在会议阶段看到骰子投掷。
受邀加入会议的用户可以在加入会议时在台上查看你的应用。
部署
准备好部署代码后,可以使用 Teams 工具包 或 Teams 开发人员门户 来预配和上传应用的 zip 文件。
注意
在上传或分发应用之前,需要将预配的 appId 添加到 manifest.json
。
代码示例
示例名称 | Description | JavaScript |
---|---|---|
投掷骰子 | 启用所有连接的客户端以投掷骰子并查看结果。 | View |