線上狀態

顯示文件中的線上成員、協作者名稱與頭像,並啟用遠端游標和選取範圍。

Presence 讓使用者看見誰開啟了相同文件,以及其他人正在操作的位置。例如 Bob 選取 B3 儲存格時,Alice 會看到標有「Bob」的選取範圍。你也可以用頭像列或成員清單顯示目前協作者。

SDK 同步成員與游標資訊,並呈現支援的遠端游標。應用可提供協作者名稱及頭像,使用成員訂閱 API 建立頭像列、成員面板或線上人數。

開始之前

先完成快速開始及身分與授權。此時編輯器應能同步編輯,服務端透過 context.userID 識別登入使用者,且已設定讀取、JOIN 與編輯策略。

以下範例擴充既有 transport、endpoint 和 univer 設定。請保留前一篇的驗證與授權規則。

成員與游標同步

Alice 和 Bob 開啟相同試算表。Presence 有兩種更新:

操作成員清單Alice 在表格中看到的內容
Alice 開啟表格Alice自己的選取範圍
Bob 開啟相同表格Alice、BobBob 選取儲存格時的選取範圍
Bob 從 B3 移至 C5Alice、BobBob 的選取範圍移至 C5
Bob 關閉表格收到離開更新後只剩 AliceBob 的選取範圍消失

連線加入或離開時,成員清單才會改變。移動游標會改變編輯器中的選取範圍,不會新增或移除成員。編輯 C5 的值則另透過協同編輯流程同步文件內容。

Presence 的範圍是一份文件(Unit),描述目前連接至該文件的人;前一篇設定的存取清單描述所有有權開啟文件的人。Presence 是暫時資料:移動游標不建立變更集、不推進文件修訂版本,也不存入資料庫。

啟用快速開始中的協同外掛與對應編輯器 UI 後,SDK 會擷取並傳送本機游標、選取範圍更新,在其他成員的編輯器中呈現對應游標、選取範圍及名稱。

編輯器線上成員訂閱遠端游標與選取範圍 UI
Sheet支援儲存格與範圍選取
Doc支援文字游標與選取範圍
Slide支援指標位置與物件選取
Board支援指標位置與物件選取
Base支援不提供

1. 設定協作者名稱與頭像

在 Endpoint 的 connect Middleware 設定 context.member.name 和 context.member.avatar。應用決定如何取得資料:使用已驗證的 context.session.userID 查詢,或透過 customData 重用驗證時儲存的資料。

本例以 customData 避免第二次查詢。將欄位加入既有 Transport Middleware,並在啟動服務端前註冊 connect:

TypeScript
type AppUser = {  id: string;  name: string;  avatar?: string;};transport.use(async (context, next) => {  // Your authentication function; rejects unauthenticated requests.  const user: AppUser = await auth.requireUser(context.incomingMessage);  context.userID = user.id;  // An application-defined field to reuse the profile in connect.  context.customData.user = user;  await next();});endpoint.use("connect", async (context, next) => {  // Read the profile saved when the session ticket was issued.  const user = context.session.customData.user as AppUser;  // Without this assignment, the member name defaults to userID.  context.member.name = user.name;  // Use an empty string when there is no avatar URL.  context.member.avatar = user.avatar ?? "";  await next();});

SDK 將 session-ticket 請求的 customData 傳至 context.session.customData。多節點部署下,連線在其他節點上的傳送者只帶 userID 與 memberID,需要隨訊息傳遞的資料應放在 Presence payload 中。user 鍵與 AppUser 類型由應用決定,SDK 不解讀它們。其他協作者收到的是指定給 context.member 的資料。

connect 在每個新 WebSocket 連線(包括重新連線)加入文件前執行一次。應用中的個人資料變更不會自動更新已與既有連線共享的成員資料。

2. 顯示成員清單(選用)

應用需要頭像列或成員面板時,使用 subscribeCollaborators(unitID, callback) 訂閱開啟文件的成員。游標呈現不依賴此訂閱。

TypeScript
import { FUniver } from "@univerjs/core/facade";// Import once in the client entry point to enable collaboration Facade methods.import "@univerjs-pro/collaboration-client/facade";// Reuse an existing univerAPI if your editor setup already provides one.const univerAPI = FUniver.newAPI(univer);// unitID is the ID of the document open in the editor.const subscription = univerAPI.getCollaboration().subscribeCollaborators(unitID, (members) => {  // Each callback is a new list snapshot that the application can use to update its UI.  console.table(members);});

SDK 等待文件協同房間可用。每次回呼收到用戶端目前已知成員的 IMember[] 快照,加入後也包括自己。初始化時可能收到空清單。回呼提供成員資訊,不提供游標位置。

Alice 和 Bob 的成員資料欄位如下(ID 僅供示範):

userIDmemberIDnameavatar
alice83446a72-a1cc-4ed8-aedc-afd8907bbb18Alice""
bob7ee5a94e-c784-4e1e-b1a3-b9d34be8ec4eBob""

userID 識別應用中的使用者,memberID 由 SDK 指派,識別一個連線。Bob 開啟第二個分頁時,清單會增加一筆 userID: "bob" 相同、memberID 不同的記錄,此時是兩位使用者、三個連線。應用可依 userID 分組顯示頭像或線上人數,或依 memberID 顯示並計算連線。編輯器分別呈現每個連線的游標。

使用訂閱的檢視移除後,釋放訂閱:

TypeScript
subscription.dispose();

銷毀編輯器時,釋放應用建立的 univerAPI 與 Univer 執行個體。只關閉成員面板時,只需釋放該面板的訂閱。

範例:React 成員清單

將既有 univerAPI 和文件 ID 傳入此元件:

TSX
import type { FUniver } from "@univerjs/core/facade";import type { IMember } from "@univerjs/protocol";import "@univerjs-pro/collaboration-client/facade";import { useEffect, useState } from "react";export function OnlineMembers({ univerAPI, unitID }: { univerAPI: FUniver; unitID: string }) {  const [members, setMembers] = useState<IMember[]>([]);  useEffect(() => {    // Clear the previous document list while waiting for the new subscription.    setMembers([]);    const subscription = univerAPI.getCollaboration().subscribeCollaborators(unitID, setMembers);    // Unsubscribe when the document changes or the component unmounts.    return () => subscription.dispose();  }, [univerAPI, unitID]);  // Show each user once, even when they have multiple connections.  const users = [...new Map(members.map((member) => [member.userID, member])).values()];  return (    <ul>      {users.map((user) => (        <li key={user.userID}>          {user.avatar && <img src={user.avatar} alt="" width={24} height={24} />}          <span>{user.name}</span>        </li>      ))}    </ul>  );}

訂閱反映用戶端收到的最新房間成員狀態。偵測斷線需要時間,因此離開成員可能短暫保留。SDK 內建協同狀態 UI 提供目前用戶端的同步狀態、離線提示與重新連線操作。

使用兩位使用者驗證

  1. 在不同瀏覽器設定檔中分別以 Alice 和 Bob 登入,開啟同一文件。
  2. 確認成員清單中出現兩個名稱。
  3. 在 Sheet 中以 Bob 選取 B3,再選 C5。Alice 應看到帶 Bob 名稱的選取範圍移動,成員清單保持不變。
  4. 以 Bob 開啟另一個分頁。訂閱應增加另一個 memberID,React 清單仍只顯示一次 Bob。
  5. 關閉 Bob 的兩個分頁。收到離開更新後,Alice 的清單應只剩 Alice。

你覺得這篇文檔如何?

© 2026 DreamNum Co., Ltd.