協同整合

將 Univer 編輯器接入協同服務,讓使用者編輯同一份文件。

協同功能將瀏覽器編輯器連接到共用文件服務。例如,兩位使用者開啟同一份試算表,一個瀏覽器中的修改會出現在另一個瀏覽器。

先依伺服器整合準備後端,再按照下方內容設定編輯器與文件載入。請對照 協同快速開始成對的 Server 與 Web 程式碼。

100%

接入現有編輯器

保留現有 Web SDK 編輯器,依快速開始的瀏覽器設定加入協同外掛,設定文件載入、修改提交與 WebSocket 位址。保持瀏覽器與伺服器套件版本相容。

範例中的固定使用者與預設權限只用於示範。實際應用程式的請求應包含登入憑證,讓後端驗證身分與文件存取權。授權相關設定請參閱授權設定。

建立並開啟同一份文件

建立與開啟是兩個不同操作:

  1. 使用者建立文件時,後端儲存文件並回傳 ID。
  2. 瀏覽器載入此 ID;重新開啟或與其他使用者分享時,都重用相同 ID。

API 中的 unitId 就是這個文件 ID。不要每次造訪都建立新的本機空白文件。

先設定目前使用者,再載入文件。目前使用者決定協同編輯的身分與本機離線快取的歸屬,設定方式請參閱身分與授權。

例如,註冊 Sheets 與協同外掛後,可載入伺服器試算表:

TypeScript
import { UserManagerService } from '@univerjs/core'import '@univerjs-pro/collaboration-client/facade'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })const workbook = await univerAPI.getCollaboration().loadSheetAsync('your-document-id')if (!workbook) throw new Error('Document could not be loaded')

各產品的載入方式請參閱 Sheets、Docs、Slides、Boards、Bases與 PDFs 指南。請確認產品與目標後端版本的支援情況。

驗證同步、儲存與權限

在兩個獨立瀏覽器工作階段中開啟相同文件,例如一般視窗與無痕視窗。在一個視窗編輯,確認另一個收到變更,再驗證重新整理、重新連線與重啟伺服器後的內容。

使用編輯者、檢視者與未授權使用者測試。唯讀 UI 設定控制頁面互動,伺服器仍須拒絕未授權的讀取與修改。

若可載入但不同步,請檢查 WebSocket 連線。若重啟後內容遺失,請檢查後端儲存。相關設定請參閱伺服器整合。

加入檔案交換、留言或歷史記錄

若要共同編輯匯入的檔案,請使用轉換後的資料建立協同文件,詳見檔案交換整合。留言與歷史記錄各自需要外掛、服務與權限,請參考 Office 擴充模組。

歷史面板設定請參閱 Sheets、Docs、Slides、Boards、Bases。PDFs 目前的能力範圍請參閱 PDFs 歷史記錄。

同步狀態與重送

匯入協同 Facade 後註冊監聽。CollaborationStatusChanged 會報告註冊監聽時已在協同的文件的目前狀態,此後只報告變更,不連續重複相同狀態。hasWritePending(unitId) 包含等待傳送、等待確認和離線快取的修改;省略 ID 時檢查目前聚焦文件。WebSocket 已連線不代表修改已儲存。

TypeScript
import '@univerjs-pro/collaboration-client/facade'const collaboration = univerAPI.getCollaboration()const statusSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationStatusChanged, (event) => {  console.info(event.unitId, event.status, collaboration.hasWritePending(event.unitId))})const resendSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationChangesetResend, (event) => {  console.info(event.unitId, event.reason, event.attempt, event.unsyncedMutationCount, event.nextDelayMs)})

CollaborationChangesetResend 僅在重送時觸發,首次提交不觸發。原因包括 ack_timeout、should_retry 和 reconnect;attempt、elapsedMs、unsyncedMutationCount、nextDelayMs 可用來顯示儲存與重試狀態。移除編輯器時釋放事件訂閱。

合併傳送延遲與確認逾時是兩個設定。用戶端外掛預設使用 sendChangesetTimeout: 2000、changesetAckTimeout: 20000、maxChangesetAckTimeout: 120000,單位均為毫秒。提交請求也使用確認逾時;未收到確認時以指數退避重送,間隔不超過最大值。後兩項相同時使用固定間隔。

TypeScript
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import { BrowserCollaborationSocketService } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientPlugin, {  socketService: BrowserCollaborationSocketService,  sendChangesetTimeout: 200,  changesetAckTimeout: 20_000,  maxChangesetAckTimeout: 120_000,})

將這些選項合併到現有用戶端註冊中,保留 socket 與介面位址設定。Sheets 和 Docs 協同預設使用 200 ms 的合併傳送延遲,未提供確認逾時選項;自訂逾時請使用外掛模式。

由應用程式處理衝突

文件進入衝突後,CollaborationConflict 在嘗試清理離線快取後觸發一次,請在載入文件前監聽。reason 為 transform_failed、apply_failed、changeset_rejected、permission_rejected 或 remote_revert;可用時由 message 和 revert 提供更多資訊。

TypeScript
import type { IEventParamConfig } from '@univerjs/core/facade'import '@univerjs-pro/collaboration-client/facade'const conflicts = new Map<string, IEventParamConfig['CollaborationConflict']>()const conflictSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationConflict, (event) => {  conflicts.set(event.unitId, event)})

上述範例保留事件供應用程式復原介面使用。Map 僅存在於記憶體:重新整理前應儲存或匯出 localChanges。必須在事件中保留資料,後續讀取無法復原已清理的快取。awaitingChangeset 可能已套用至伺服器,不應直接重新提交。

cacheCleared: false 表示重新整理會重播舊快取,請先解決清理問題。清理快取不代表未同步修改已儲存;permission_rejected 還需解決權限問題,重新整理不會授予權限。

預設 UI 依衝突原因顯示通知,快取清理成功後提供重新整理操作,失敗時提供重試。若由應用程式接管復原流程,在現有初始化設定 enableDefaultConflictUI: false,並自行處理事件:

TypeScript
import { UniverCollaborationClientUIPlugin } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientUIPlugin, { enableDefaultConflictUI: false })

將協同預設放入現有 createUniver({ presets: [...] }),與編輯器預設組合,保留介面位址與歷史設定。詳見事件參數和用戶端設定。

你覺得這篇文檔如何?

© 2026 DreamNum Co., Ltd.