通用 API
在 Univer 中,根據文件類型的不同,所能調用的 Facade API 也有所不同。本章將介紹在所有類型文件中都適用的通用 Facade API。
導入
import { FUniver } from '@univerjs/core/facade'const univerAPI = FUniver.newAPI(univer)概念
命令
Univer 中大多數的操作都會註冊到命令系統,並通過命令系統來觸發。這種統一的操作方式使得 Univer 可以很容易的實現撤銷、重做、協同等功能。
命令系統
Univer 為使用者提供了統一的命令系統,通過命令系統使用者可以實現各種自訂化的功能。
每一個命令對應了一個唯一的 ID。如果你正在尋找某個特定的命令 ID,可以參考 如何查找命令 ID。
監聽命令
Univer 設計了兩種監聽命令的方式,分別是在命令執行前和命令執行後:
Event.BeforeCommandExecute:在命令執行前執行自訂邏輯。Event.CommandExecuted:在命令執行後執行自訂邏輯。
監聽命令執行前
命令執行前,將 Event.BeforeCommandExecute 傳給 FUniver.addEvent 來註冊預處理監聽器。
當命令執行前,預處理監聽器內邏輯會被執行。
const univerAPI = FUniver.newAPI(univer)univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, ({ id, type, params }) => { // 在命令執行前執行自訂邏輯})如需阻止命令執行,在監聽器中將 event.cancel 設為 true。
const univerAPI = FUniver.newAPI(univer)univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, (event) => { event.cancel = true})監聽命令執行後
命令執行後,將 Event.CommandExecuted 傳給 FUniver.addEvent 來註冊後處理監聽器。
當命令執行後,後處理監聽器內邏輯會被執行。
const univerAPI = FUniver.newAPI(univer)univerAPI.addEvent(univerAPI.Event.CommandExecuted, ({ id, type, params }) => { // 在命令執行後執行自訂邏輯})取消監聽
註冊命令監聽器的方法會返回一個 IDisposable 物件,調用 IDisposable.dispose 可以銷毀該監聽器。
建議你及時銷毀不再使用的監聽器,有助於提高程式的穩定性。
const univerAPI = FUniver.newAPI(univer)// 註冊監聽器const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, () => { // 在命令執行前執行自訂邏輯})// 示例:1 秒後取消監聽setTimeout(() => { // 取消監聽 disposable.dispose()}, 1000)執行命令
如果你知道命令 ID 和所需傳遞的參數,也可以通過 FUniver.executeCommand 方法來執行命令。
例如,我們可以通過 sheet.command.set-range-values 命令來設定儲存格 A1 的值:
const univerAPI = FUniver.newAPI(univer)// 執行命令univerAPI.executeCommand('sheet.command.set-range-values', { value: { v: 'Hello, Univer!' }, range: { startRow: 0, startColumn: 0, endRow: 0, endColumn: 0 },})事件系統
Univer 提供了一個完整的事件系統,允許你監聽和響應電子試算表中的各種變化。事件可以分為多個類別,包括剪貼板操作、選區變化、儲存格互動、表格修改等。
事件類別
完整事件列表請參考:/reference/facade/events#%E5%B1%9E%E6%80%A7
-
剪貼板事件
BeforeClipboardChange: 在剪貼板內容改變前觸發,可以通過設定params.cancel = true來阻止改變BeforeClipboardPaste: 在貼上內容前觸發,可以通過設定params.cancel = true來阻止貼上ClipboardChanged: 在剪貼板內容改變後觸發,可以獲取新的剪貼板內容ClipboardPasted: 在內容貼上後觸發,可以獲取貼上的內容
-
選區事件
SelectionChanged: 在選區改變時觸發,提供新的選區範圍資訊SelectionMoveStart: 在選區開始移動時觸發,可用於實現自訂選區效果SelectionMoveEnd: 在選區結束移動時觸發,提供最終的選區範圍SelectionMoving: 在選區移動過程中觸發,可用於即時更新 UIDragOver: 在拖動經過儲存格時觸發Drop: 在放置選區內容時觸發
-
儲存格事件
CellClicked: 在儲存格被點擊時觸發,提供儲存格的位置和內容資訊CellHover: 在滑鼠懸停在儲存格上時觸發,可用於顯示提示資訊CellPointerDown: 在儲存格上按下指標時觸發,用於開始拖動或選擇操作CellPointerUp: 在儲存格上釋放指標時觸發,用於完成操作CellPointerMove: 在指標在儲存格上移動時觸發
-
表格事件
SheetValueChanged: 在表格值改變時觸發,提供變更的範圍和新值SheetZoomChanged: 在縮放級別改變時觸發,可獲取新的縮放比例SheetSkeletonChanged: 在表格結構改變時觸發,如行列的插入刪除BeforeSheetEditStart: 在儲存格開始編輯前觸發,可用於控制是否允許編輯SheetEditStarted: 在儲存格開始編輯時觸發,可用於自訂編輯器行為BeforeSheetEditEnd: 在儲存格結束編輯前觸發,可用於驗證編輯內容SheetEditEnded: 在儲存格結束編輯時觸發,提供編輯後的值SheetEditChanging: 在儲存格編輯過程中觸發,可用於即時驗證或格式化Scroll: 在表格滾動時觸發,提供滾動位置信息CrosshairHighlightColorChanged: 在十字光標高亮顏色改變時觸發CrosshairHighlightEnabledChanged: 在啟用或禁用十字光標高亮時觸發
-
表頭事件
RowHeaderClick: 在行表頭被點擊時觸發RowHeaderHover: 在滑鼠懸停在行表頭時觸發ColumnHeaderClick: 在列表頭被點擊時觸發ColumnHeaderHover: 在滑鼠懸停在列表頭時觸發
-
資料驗證事件
BeforeSheetDataValidationAdd: 在新增資料驗證規則前觸發SheetDataValidationChanged: 在資料驗證規則改變時觸發SheetDataValidatorStatusChanged: 在資料驗證狀態改變時觸發
-
評論事件
BeforeCommentAdd: 在新增評論前觸發CommentAdded: 在評論新增後觸發BeforeCommentUpdate: 在更新評論前觸發CommentUpdated: 在評論更新後觸發BeforeCommentDeleted: 在刪除評論前觸發CommentDeleted: 在評論刪除後觸發
-
資料處理事件
SheetBeforeRangeSort: 在範圍排序前觸發SheetRangeSorted: 在範圍排序後觸發SheetBeforeRangeFilter: 在範圍篩選前觸發SheetRangeFiltered: 在範圍篩選後觸發BeforePivotTableAdd: 在新增資料透視表前觸發PivotTableAdded: 在資料透視表新增後觸發
使用事件
你可以使用 univerAPI 的 addEvent 方法來監聽事件。以下是基本模式:
univerAPI.addEvent(univerAPI.Event.事件名稱, (params) => { // 處理事件參數})示例:監聽儲存格點擊
univerAPI.addEvent(univerAPI.Event.CellClicked, (params) => { const { worksheet, workbook, row, column } = params console.log(`儲存格被點擊,行:${row},列:${column}`)})示例:監控剪貼板操作
univerAPI.addEvent(univerAPI.Event.BeforeClipboardPaste, (params) => { const { text, html } = params // 如果要取消貼上操作 params.cancel = true})示例:追蹤選區變化
univerAPI.addEvent(univerAPI.Event.SelectionChanged, (params) => { const { worksheet, workbook, selections } = params console.log('選區已改變:', selections)})取消事件監聽
事件監聽器會返回一個 IDisposable 物件,可以用它來在不再需要時移除監聽器:
const disposable = univerAPI.addEvent(univerAPI.Event.SheetValueChanged, (params) => { // 處理值變化})// 之後,當你想要移除監聽器時:disposable.dispose()最佳實踐
- 當不再需要時,務必銷毀事件監聽器以防止記憶體洩漏
- 根據具體用例選擇合適的事件 - 優先使用特定事件而不是通用事件
- 保持事件處理程序輕量化以維持效能
- 當需要阻止預設行為時,考慮使用
BeforeClipboardChange等「前置」事件
撤銷和重做
撤銷
await univerAPI.undo()重做
await univerAPI.redo()系統剪貼板
使用 FUniver.copy() 和 FUniver.paste() 方法可以讀取和寫入系統剪貼板。
複製與貼上依賴瀏覽器原生 API ,當環境條件或者權限不滿足時複製與貼上功能將無法工作。
示例: Sheet 區域的複製與貼上
// 防止在控制台中執行複製貼上程式碼時因失去焦點而失敗,// 此示例監聽儲存格點擊事件並執行複製貼上程式碼。univerAPI.addEvent(univerAPI.Event.CellClicked, async (params) => { const fWorkbook = univerAPI.getActiveWorkbook() const fWorksheet = fWorkbook.getActiveSheet() // 將範圍 A1:B2 複製到剪貼板 const fRange = fWorksheet.getRange('A1:B2') fRange.activate().setValues([ [1, 2], [3, 4], ]) await univerAPI.copy() // 將複製的內容貼到範圍 C1:D2 const fRange2 = fWorksheet.getRange('C1') fRange2.activate() await univerAPI.paste() // 檢查貼上的內容 console.log(fWorksheet.getRange('C1:D2').getValues()) // [[1, 2], [3, 4]]})你也可以使用命令系統實現調用剪貼板功能:
import { CopyCommand, PasteCommand } from '@univerjs/ui'// 複製univerAPI.executeCommand(CopyCommand.id)// 貼上univerAPI.executeCommand(PasteCommand.id)UI
請參考以下文件來擴展 Univer 的 UI:
WebSocket
Facade API 提供了一個便捷的 API createSocket 來建立 WebSocket,傳入一個 URL 即可。
然後可以監聽 open、message、close、error 事件,以及主動發送消息 send 方法和主動關閉 close 方法。
使用 Presets 安裝,可以直接使用 univerAPI.createSocket(url)。
使用手動組合安裝,需要安裝 @univerjs/network 依賴包,並註冊 UniverNetworkPlugin 插件。
// ... 省略其他插件引入import { UniverNetworkPlugin } from '@univerjs/network'// ... 省略其他 facade 引入import '@univerjs/network/facade'// ... 省略其他插件註冊univer.registerPlugin(UniverNetworkPlugin)以下是一個簡單的示例:
// URL 換成你自己 WebSocket 服務的地址const ws = univerAPI.createSocket('ws://47.100.177.253:8449/ws')ws.open$.subscribe(() => { console.log('websocket opened') ws.send('hello')})ws.message$.subscribe((message) => { console.log('websocket message', message) const content = JSON.parse(message.data).content if (!content.includes('command')) { return } const commandInfo = JSON.parse(content) const { command, options } = commandInfo const { id, params } = command // 接收到協同數據,本地落盤 univerAPI.executeCommand(id, params, options)})ws.close$.subscribe(() => { console.log('websocket closed')})ws.error$.subscribe((error) => { console.log('websocket error', error)})univerAPI.addEvent(univerAPI.Event.CommandExecuted, ({ id, type, params, options }) => { // 僅同步本地 mutation if ( type !== univerAPI.Enum.CommandType.MUTATION || options?.fromCollab || options?.onlyLocal || id === 'doc.mutation.rich-text-editing' ) { return } const commandInfo = JSON.stringify({ command: { id, type, params }, options: { fromCollab: true } }) ws.send(commandInfo)})注意:啟動 Univer 的時候要確保有 unitID,不指定 unitID 的話無法協同。
註冊公式
使用 Facade API,可以方便快速地在當前 Univer 實例中註冊自訂公式。
如下案例所示,使用 registerFunction 將一個 CUSTOMSUM 公式所需的演算法、名稱、描述一次性註冊到公式插件,執行之後就可以使用公式了。在任一空白儲存格輸入 =CUSTOMSUM 可以看到提示。
// 註冊公式支援 lambda 函數const formulaEngine = univerAPI.getFormula()formulaEngine.registerFunction( 'CUSTOMSUM', (...variants) => { let sum = 0 const last = variants[variants.length - 1] if (last.isLambda && last.isLambda()) { variants.pop() const variantsList = variants.map((variant) => (Array.isArray(variant) ? variant[0][0] : variant)) sum += last.executeCustom(...variantsList).getValue() } for (const variant of variants) { sum += Number(variant) || 0 } return sum }, '求參數的和',)// Use the function in a cellconst fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const cellA1 = fWorksheet.getRange('A1')cellA1.setValue(1)const cellA2 = fWorksheet.getRange('A2')cellA2.setValue(2)const cellA3 = fWorksheet.getRange('A3')cellA3.setValue({ f: '=CUSTOMSUM(A1,A2,LAMBDA(x,y,x*y))' })// A3 will display: 5formulaEngine.calculationEnd((functionsExecutedState) => { if (functionsExecutedState === 3) { console.log(cellA3.getValue()) // 5 }})如果需要卸載所註冊的公式,可以調用 dispose 方法。
const functionDisposable = formulaEngine.registerFunction( // calculate )// 卸載所註冊的公式functionDisposable.dispose()如果想要提供更完善的國際化內容和描述,還可以配置 locales 和 description 欄位。如下所示。
formulaEngine.registerFunction( 'CUSTOMSUM', (...variants) => { let sum = 0 const last = variants[variants.length - 1] if (last.isLambda && last.isLambda()) { variants.pop() const variantsList = variants.map((variant) => (Array.isArray(variant) ? variant[0][0] : variant)) sum += last.executeCustom(...variantsList).getValue() } for (const variant of variants) { sum += Number(variant) || 0 } return sum }, { description: { functionName: 'CUSTOMSUM', description: 'formulaCustom.CUSTOMSUM.description', abstract: 'formulaCustom.CUSTOMSUM.abstract', functionParameter: [ { name: 'formulaCustom.CUSTOMSUM.functionParameter.number1.name', detail: 'formulaCustom.CUSTOMSUM.functionParameter.number1.detail', example: 'A1:A20', require: 1, repeat: 0, }, { name: 'formulaCustom.CUSTOMSUM.functionParameter.number2.name', detail: 'formulaCustom.CUSTOMSUM.functionParameter.number2.detail', example: 'B2:B10', require: 0, repeat: 1, }, ], }, locales: { zhCN: { formulaCustom: { CUSTOMSUM: { description: '將單個值、儲存格引用或是範圍相加,或者將三者的組合相加。', abstract: '求參數的和', functionParameter: { number1: { name: '數值1', detail: '要相加的第一個數字。 該數字可以是 4 之類的數字,B6 之類的儲存格引用或 B2:B8 之類的儲存格範圍。', }, number2: { name: '數值2', detail: '這是要相加的第二個數字。 可以按照這種方式最多指定 255 個數字。', }, }, }, }, }, enUS: { formulaCustom: { CUSTOMSUM: { description: `You can add individual values, cell references or ranges or a mix of all three.`, abstract: `Adds its arguments`, functionParameter: { number1: { name: 'number1', detail: 'The first number you want to add. The number can be like 4, a cell reference like B6, or a cell range like B2:B8.', }, number2: { name: 'number2', detail: 'This is the second number you want to add. You can specify up to 255 numbers in this way.', }, }, }, }, }, }, },)說明
func編寫計算公式的具體演算法和名稱映射。入參為使用公式時使用者輸入的內容,可能為數字、字串、布林值,或者一個陣列。description設定自訂公式的描述。locales下可以設定多種語言,命名規則參考 LocaleType。可以在functionList下添加多個公式的翻譯。詳細的欄位說明請參考 如何在 Formula Engine 中添加公式 的部分。
如果想重用公式系統提供的演算法,增強公式演算法的能力,可以通過插件配置的方式註冊自訂公式,詳細教程請參考 自訂公式。
列舉類型 API
Facade API 提供了一些常用的列舉類型,可以在開發過程中使用。例如:
console.log(univerAPI.Enum)console.log(univerAPI.Enum.UniverInstanceType.UNIVER_SHEET)console.log(univerAPI.Enum.LifecycleStages.Rendered)工具方法 API
Facade API 提供了一些常用的工具方法,可以在開發過程中使用。例如:
console.log(univerAPI.Util)console.log(univerAPI.Util.tools.chatAtABC(10))console.log(univerAPI.Util.tools.ABCatNum('K'))你覺得這篇文檔如何?