範圍 & 選區 & 單元格

依任務跳轉到下方章節。本頁集中介紹基礎操作、進階範例、設定與疑難排解;完整 API 定義統一在 Reference 中維護。

範圍 Range

範圍指工作表中的一塊矩形區域,有起始行號、起始列號、長寬或者結束行號、結束列號來確定。

表格中的大部分操作都可以透過範圍 API 來操作,如設定值、獲取值、設定樣式、獲取樣式等。

範圍完整 Facade API 型別定義,請檢視 FRange Facade API

建立範圍

獲得一個範圍需要知道起始行號、起始列號、長寬。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 獲取 A1 單元格的範圍:const fRange = fWorksheet.getRange(0, 0)console.log(fRange, fRange.getA1Notation())// 獲取 A1:B2 的範圍:const fRange2 = fWorksheet.getRange(0, 0, 2, 2)console.log(fRange2, fRange2.getA1Notation())
TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 獲取名稱是 Sheet1 的工作表的 A1:B2 範圍const fRange1 = fWorksheet.getRange('Sheet1!A1:B2')console.log(fRange1, fRange1.getA1Notation())// 獲取單個單元格 A1const fRange2 = fWorksheet.getRange('A1')console.log(fRange2, fRange2.getA1Notation())// 獲取 A1:B2 範圍const fRange3 = fWorksheet.getRange('A1:B2')console.log(fRange3, fRange3.getA1Notation())// 獲取 A 列的範圍const fRange4 = fWorksheet.getRange('A:A')console.log(fRange4, fRange4.getA1Notation())// 獲取第 1 行的範圍const fRange5 = fWorksheet.getRange('1:1')console.log(fRange5, fRange5.getA1Notation())

獲取範圍資料

獲取範圍第一個單元格的值

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getValue()) // 範圍左上角單元格值console.log(fRange.getRawValue()) // 範圍左上角單元格原始值console.log(fRange.getDisplayValue()) // 範圍左上角單元格顯示值console.log(fRange.getCellData()) // 範圍左上角單元格 ICellData 物件const value = fRange.getValue(true)console.log(value)if (value !== null && typeof value === 'object') {  console.log(value.toPlainText())}

使用 getValue(true) 保留豐富文字物件。空儲存格傳回 null / undefined,一般儲存格傳回字串、數字或布林值;僅對豐富文字物件呼叫 toPlainText()。

獲取範圍的所有值

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getValues()) // 範圍所有單元格值console.log(fRange.getRawValues()) // 範圍所有單元格原始值console.log(fRange.getDisplayValues()) // 範圍所有單元格顯示值console.log(fRange.getCellDataGrid()) // 範圍所有單元格 ICellData 物件console.log(fRange.getValues(true))

獲取範圍的所有公式

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getFormula()) // 範圍左上角單元格公式console.log(fRange.getFormulas()) // 範圍所有單元格公式

設定範圍資料

設定單一值

傳入一個值或者單元格物件,將會覆蓋範圍內所有單元格,如果以 = 開頭,將被解釋為公式。

比如,設定 A1:B2 的值為 Hello, Univer:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange.setValue('Hello, Univer')

將 C1 的值設為 =A1+B1,讓結果與輸入儲存格分開:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('C1')fRange.setValue('=A1+B1')

設定 A1:B2 的值為單元格物件:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange.setValue({  v: 'Hello, Univer',  custom: {    key: 'value',  },})

如果只想設定範圍左上角的單元格值,可以使用 FRange.setValueForCell 方法:

TypeScript
fRange.setValueForCell('Hello, Univer')

透過陣列設定多個值

陣列的長度和寬度必須和範圍的長寬一致。

可以傳入單元格值也可以傳入單元格物件。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange.setValues([  ['A1', 'B1'],  ['A2', 'B2'],])fRange.setValues([  [{ v: 'A1' }, { v: 'B1' }],  [{ v: 'A2' }, { v: 'B2' }],])

透過物件設定多個值

則物件的一級索引代表行號,二級索引代表列號,與範圍的長寬無需一致。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange.setValues({  0: {    0: 'A1',    1: 'B1',  },  1: {    0: 'A2',    1: 'B2',  },})

清理範圍資料

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorkSheet = fWorkbook.getActiveSheet()const fRange = fWorkSheet.getRange('A1:D10')// 清除範圍的內容和格式資訊。fRange.clear()

獲取範圍樣式

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getCellStyleData()) // 範圍左上角單元格樣式資料console.log(fRange.getCellStyle()) // 範圍左上角單元格樣式console.log(fRange.getCellStyles()) // 範圍所有單元格樣式

設定範圍樣式

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange  .setValues([    [1, 2],    [3, 4],  ])  .setFontWeight('bold')  .setFontLine('underline')  .setFontFamily('Arial')  .setFontSize(24)  .setFontColor('red')

清理範圍樣式

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')fRange.setFontWeight(null).setFontLine(null).setFontFamily(null).setFontSize(null).setFontColor(null)

選區 Selection

Univer 表格支援多選區,所以選區是一個範圍陣列,可以透過範圍 API 來操作選區資料。

我們還提供 API 來獲取當前選區、設定選區和監聽選區變化。

選區完整 Facade API 型別定義,請檢視 FSelection Facade API

獲取啟用選區的範圍

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 啟用新的選區const fRange = fWorksheet.getRange('A1:B2')fRange.activate()// 獲取啟用選區的範圍const fSelection = fWorksheet.getSelection()console.log(fSelection)const activeRange = fSelection.getActiveRange()console.log(activeRange.getA1Notation()) // A1:B2

設定選區

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 透過 FRange 設定選區 A1:B2const fRange = fWorksheet.getRange('A1:B2')fRange.activate()// 透過 FWorksheet 設定選區 C1:D2fWorksheet.setActiveSelection(fWorksheet.getRange('C1:D2'))

獲取當前啟用的單元格

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 啟用選區 A10:B11const fRange = fWorksheet.getRange('A10:B11')fRange.activate()// 獲取當前啟用的單元格let fSelection = fWorksheet.getSelection()const { actualRow, actualColumn } = fSelection.getCurrentCell()console.log(fWorksheet.getRange(actualRow, actualColumn).getA1Notation()) // A10// 更新新的啟用單元格 B11fSelection = fSelection.updatePrimaryCell(fWorksheet.getRange('B11'))const { actualRow: newRow, actualColumn: newColumn } = fSelection.getCurrentCell()console.log(fWorksheet.getRange(newRow, newColumn).getA1Notation()) // B11

禁用/啟用/隱藏/顯示選區

禁用後,選區將不會響應。設定選區不可見,與禁用選區不同,選區仍然有效,只是看不到它們。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()// 禁用選區fWorkbook.disableSelection()// 啟用選區fWorkbook.enableSelection()// 隱藏選區fWorkbook.transparentSelection()// 顯示選區fWorkbook.showSelection()

監聽選區變化

TypeScript
univerAPI.addEvent(univerAPI.Event.SelectionChanged, (params) => {  const { worksheet, workbook, selections } = params  console.log(params)})

單元格 Cell

單元格資料以二維 Map 的形式儲存在工作表中,一二級索引分別代表行號和列號。

以下是一個典型的單元格物件:

TypeScript
const data = {  v: 'Hello, Univer',  s: 'styleId',  t: CellValueType.STRING,}

詳細的欄位說明請參考 單元格資訊。

注意事項

  1. 對單元格的操作可以看作對行高 1 、列寬 1 的範圍進行操作,操作範圍請閱讀 範圍-range。
  2. 外掛還會將拓展的單元格屬性儲存在 Workbook 的 resources 屬性中,詳細請閱讀 外掛自訂模型。

範圍進階操作

插入單元格

FRange.insertCells 方法可以在此範圍內插入空單元格。工作表中沿指定維度的現有資料將移離插入的範圍。

TypeScript
// 假設當前工作表是空工作表const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const values = [  [1, 2, 3, 4],  [2, 3, 4, 5],  [3, 4, 5, 6],  [4, 5, 6, 7],  [5, 6, 7, 8],]// A1:D5 範圍設定值如下:// 1 | 2 | 3 | 4// 2 | 3 | 4 | 5// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8const fRange = fWorksheet.getRange('A1:D5')fRange.setValues(values)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]// 沿著列維度在範圍 A1:B2 中插入空單元格,範圍 A1:D5 將變為://   |   | 1 | 2//   |   | 2 | 3// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8const fRange2 = fWorksheet.getRange('A1:B2')fRange2.insertCells(univerAPI.Enum.Dimension.COLUMNS)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[null, null, 1, 2], [null, null, 2, 3], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]// 再次設定範圍 A1:D5 的值,範圍 A1:D5 將變為:// 1 | 2 | 3 | 4// 2 | 3 | 4 | 5// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8fRange.setValues(values)// 沿著行維度在範圍 A1:B2 中插入空單元格,範圍 A1:D5 將變為://   |   | 3 | 4//   |   | 4 | 5// 1 | 2 | 5 | 6// 2 | 3 | 6 | 7// 3 | 4 | 7 | 8const fRange3 = fWorksheet.getRange('A1:B2')fRange3.insertCells(univerAPI.Enum.Dimension.ROWS)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[null, null, 3, 4], [null, null, 4, 5], [1, 2, 5, 6], [2, 3, 6, 7], [3, 4, 7, 8]]

刪除單元格

FRange.deleteCells 方法可以在範圍內刪除單元格。工作表中沿指定維度的現有資料將向已刪除的範圍移動。

TypeScript
// 假設當前工作表是空工作表const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const values = [  [1, 2, 3, 4],  [2, 3, 4, 5],  [3, 4, 5, 6],  [4, 5, 6, 7],  [5, 6, 7, 8],]// A1:D5 範圍設定值如下:// 1 | 2 | 3 | 4// 2 | 3 | 4 | 5// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8const fRange = fWorksheet.getRange('A1:D5')fRange.setValues(values)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]// 沿著列維度刪除範圍 A1:B2,範圍 A1:D5 將變為:// 3 | 4 |   |// 4 | 5 |   |// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8const fRange2 = fWorksheet.getRange('A1:B2')fRange2.deleteCells(univerAPI.Enum.Dimension.COLUMNS)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[3, 4, null, null], [4, 5, null, null], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]// 再次設定範圍 A1:D5 的值,範圍 A1:D5 將變為:// 1 | 2 | 3 | 4// 2 | 3 | 4 | 5// 3 | 4 | 5 | 6// 4 | 5 | 6 | 7// 5 | 6 | 7 | 8fRange.setValues(values)// 沿著行維度刪除範圍 A1:B2,範圍 A1:D5 將變為:// 3 | 4 | 3 | 4// 4 | 5 | 4 | 5// 5 | 6 | 5 | 6//   |   | 6 | 7//   |   | 7 | 8const fRange3 = fWorksheet.getRange('A1:B2')fRange3.deleteCells(univerAPI.Enum.Dimension.ROWS)console.log(fWorksheet.getRange('A1:D5').getValues()) // [[3, 4, 3, 4], [4, 5, 4, 5], [5, 6, 5, 6], [null, null, 6, 7], [null, null, 7, 8]]

合併單元格

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// 合併 B1:B2const fRange = fWorksheet.getRange('B1:B2')fRange.merge()console.log(fRange.isMerged()) // true// A1:B2 是否合併const fRange2 = fWorksheet.getRange('A1:B2')console.log(fRange2.isMerged()) // falseconsole.log(fRange2.isPartOfMerge()) // true// 取消合併fRange2.breakApart()// 水平合併:fRange2.mergeAcross();// 垂直合併:fRange2.mergeVertically();// 獲取表格中所有合併單元格範圍:fWorksheet.getMergedRanges();

高亮範圍

FRange.highlight 方法可以使用指定樣式和主單元格高亮範圍。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Highlight the range C3:E5 with default styleconst fRange = fWorksheet.getRange('C3:E5')fRange.highlight()// Highlight the range C7:E9 with custom style and primary cell D8const fRange2 = fWorksheet.getRange('C7:E9')const primaryCell = fWorksheet.getRange('D8').getRange()const disposable = fRange2.highlight(  {    stroke: 'red',    fill: 'yellow',  },  {    ...primaryCell,    actualRow: primaryCell.startRow,    actualColumn: primaryCell.startColumn,  },)// Remove the range C7:E9 highlight after 5 secondssetTimeout(() => {  disposable.dispose()}, 5000)

資料分列

FRange.splitTextToColumns 方法可以將單元格中的文字按指定分隔符分列。

預設分隔符示例:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// A1:A3 包含以下值://  A      |//  1,2,3  |//  4,,5,6 |const fRange = fWorksheet.getRange('A1:A3')fRange.setValues([['A'], ['1,2,3'], ['4,,5,6']])// 呼叫 splitTextToColumns(true) 後,範圍值將變為://  A |   |//  1 | 2 | 3//  4 | 5 | 6fRange.splitTextToColumns(true)// 呼叫 splitTextToColumns(false) 後,範圍值將變為://  A |   |   |//  1 | 2 | 3 |//  4 |   | 5 | 6fRange.splitTextToColumns(false)

指定分隔符示例:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// A1:A3 包含以下值://     A   |//  1;;2;3 |//  1;,2;3 |const fRange = fWorksheet.getRange('A1:A3')fRange.setValues([['A'], ['1;;2;3'], ['1;,2;3']])// 呼叫 splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Semicolon|univerAPI.Enum.SplitDelimiterType.Comma) 後,範圍值將變為://  A |   |   |//  1 |   | 2 | 3//  1 |   | 2 | 3fRange.splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Semicolon | univerAPI.Enum.SplitDelimiterType.Comma)// 呼叫 splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Semicolon|univerAPI.Enum.SplitDelimiterType.Comma) 後,範圍值將變為://  A |   |//  1 | 2 | 3//  1 | 2 | 3fRange.splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Semicolon | univerAPI.Enum.SplitDelimiterType.Comma)

自訂分隔符示例:

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// A1:A3 包含以下值://     A   |//  1#2#3  |//  4##5#6 |const fRange = fWorksheet.getRange('A1:A3')fRange.setValues([['A'], ['1#2#3'], ['4##5#6']])// 呼叫 splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Custom, '#') 後,範圍值將變為://  A |   |   |//  1 | 2 | 3 |//  4 |   | 5 | 6fRange.splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Custom, '#')// 呼叫 splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Custom, '#') 後,範圍值將變為://  A |   |//  1 | 2 | 3//  4 | 5 | 6fRange.splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Custom, '#')

獲取座標

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getCellRect()) // width、heigh、left、right、top、bottom、x、y

同時獲取範圍的合併資訊和座標

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')console.log(fRange.getCell())

工作表邊界的鍵盤導覽

allowArrowKeyWrapOnSheetBoundary 用來控制方向鍵到達工作表邊界後是否可換到另一列或欄。預設值為 true,設為 false 時停留在邊界;不影響選取範圍內 Enter/Tab 的循環移動。預設模式下放在 sheets 中,外掛模式下直接傳給 UniverSheetsUIPlugin。

TypeScript
univer.registerPlugin(UniverSheetsUIPlugin, {  allowArrowKeyWrapOnSheetBoundary: false,})

儲存格事件與編輯

以下範例依指標、繪製、編輯與剪貼簿互動組織。完整事件與參數型別見事件 Reference。外掛模式下訂閱前需匯入 @univerjs/sheets-ui/facade,Sheets Core 預設已包含此擴充。所屬元件或頁面卸載時應清理訂閱。

使用示例

所有事件都可以透過 addEvent 方法進行監聽。基本格式如下:

TypeScript
import '@univerjs/sheets-ui/facade'const subscription = univerAPI.addEvent(univerAPI.Event.CellClicked, ({ row, column }) => {  console.log(row, column)})// Call subscription.dispose() when the owning component or page is removed.

單元格 PointerMove 事件

CellPointerMove 事件在滑鼠移動到單元格上時觸發。透過此事件可以獲取當前滑鼠指向的單元格資訊。

TypeScript
univerAPI.addEvent(univerAPI.Event.CellPointerMove, (params) => {  // 獲取事件參數  const { worksheet, workbook, row, column } = params  console.log('當前單元格位置:', worksheet.getRange(row, column).getA1Notation())})

單元格 PointerDown 事件

CellPointerDown 事件在滑鼠按下時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.CellPointerDown, (params) => {  const { worksheet, workbook, row, column } = params  console.log('滑鼠按下的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格 PointerUp 事件

CellPointerUp 事件在滑鼠釋放時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.CellPointerUp, (params) => {  const { worksheet, workbook, row, column } = params  console.log('滑鼠釋放的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格 Hover 事件

CellHover 事件在滑鼠懸停在單元格上時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.CellHover, (params) => {  const { worksheet, workbook, row, column } = params  console.log('懸停的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格 DragOver 事件

DragOver 事件在拖動元素經過單元格時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.DragOver, (params) => {  const { worksheet, workbook, row, column } = params  console.log('拖動經過的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格 Drop 事件

Drop 事件在拖動元素放置到單元格時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.Drop, (params) => {  const { worksheet, workbook, row, column } = params  console.log('放置的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格 Click 事件

CellClicked 事件在點選單元格時觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.CellClicked, (params) => {  const { worksheet, workbook, row, column } = params  console.log('點選的單元格:', worksheet.getRange(row, column).getA1Notation())})

單元格渲染事件

registerCellCustomRender 用於註冊單元格自訂渲染器。

案例 1:固定位置渲染,新增行不會影響渲染位置

TypeScript
// 固定位置渲染univerAPI.registerCellCustomRender([  {    drawWith: (ctx, info, skeleton, spreadsheets) => {      const { row, col } = info      // 在指定位置(1,1)渲染勾選標記      if (row === 1 && col === 1) {        const { primaryWithCoord } = info        const { startX, startY } = primaryWithCoord        ctx.fillText('✅', startX, startY + 10)      }    },  },])// 重新整理畫布以應用渲染univerAPI.getActiveWorkbook().getActiveSheet().refreshCanvas()

案例 2:按標記渲染,標記位置會隨著行列變化而變化

TypeScript
// 設定標記univerAPI  .getActiveWorkbook()  .getActiveSheet()  .getRange('B2')  .setValue({ custom: { key: 'needCheck' } })// 按標記渲染univerAPI.registerCellCustomRender([  {    drawWith: (ctx, info, skeleton, spreadsheets) => {      const { row, col, data } = info      // 在標記的位置渲染勾選標記      if (data?.custom?.key === 'needCheck') {        const { primaryWithCoord } = info        const { startX, startY } = primaryWithCoord        ctx.fillText('✅', startX, startY + 10)      }    },  },])// 重新整理畫布以應用渲染univerAPI.getActiveWorkbook().getActiveSheet().refreshCanvas()

單元格編輯事件

開始編輯

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()fWorkbook.startEditing()

結束編輯

TypeScript
// 傳入 true 表示提交編輯,false 表示取消編輯// 這是一個非同步函式,需要使用 awaitconst fWorkbook = univerAPI.getActiveWorkbook()await fWorkbook.endEditingAsync(true)

開始編輯事件

BeforeSheetEditStart 事件在單元格開始編輯前觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.BeforeSheetEditStart, (params) => {  const { worksheet, workbook, row, column, eventType, keycode } = params  console.log('單元格編輯前:', params)  // 如果想阻止進入編輯狀態  params.cancel = true})

SheetEditStarted 事件在單元格開始編輯時觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.SheetEditStarted, (params) => {  const { worksheet, workbook, row, column, eventType, keycode } = params  console.log(params)})// 移除事件監聽器,使用 `disposable.dispose()`

結束編輯事件

BeforeSheetEditEnd 事件在單元格結束編輯前觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeSheetEditEnd, (params) => {  const { worksheet, workbook, row, column, value, eventType, keycode, isConfirm } = params  console.log(params)  // 取消單元格編輯結束操作  params.cancel = true})// 移除事件監聽器,使用 `disposable.dispose()`

SheetEditEnded 事件在單元格結束編輯後觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.SheetEditEnded, (params) => {  const { worksheet, workbook, row, column, eventType, keycode, isConfirm } = params  console.log('單元格編輯後:', params)})

剪貼簿事件

BeforeClipboardChange

BeforeClipboardChange 事件在剪貼簿內容改變之前觸發。你可以使用此事件在內容改變之前監控或修改剪貼簿內容。

TypeScript
univerAPI.addEvent(univerAPI.Event.BeforeClipboardChange, (params) => {  const { text, html } = params  console.log('剪貼簿內容:', text, html)  // 如果想取消剪貼簿內容的改變  // params.cancel = true;})

BeforeClipboardPaste

BeforeClipboardPaste 事件在內容貼上之前觸發。你可以使用此事件在貼上之前監控或修改內容。

TypeScript
univerAPI.addEvent(univerAPI.Event.BeforeClipboardPaste, (params) => {  const { text, html } = params  console.log('待貼上內容:', text, html)  // 如果想取消貼上操作  // params.cancel = true;})

ClipboardChanged

ClipboardChanged 事件在剪貼簿內容改變之後觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.ClipboardChanged, (params) => {  const { text, html } = params  console.log('新的剪貼簿內容:', text, html)})

ClipboardPasted

ClipboardPasted 事件在內容貼上完成後觸發。

TypeScript
univerAPI.addEvent(univerAPI.Event.ClipboardPasted, (params) => {  const { text, html } = params  console.log('已貼上的內容:', text, html)})

儲存格編輯疑難排解

如何實時獲取單元格編輯器內的資料?

訂閱 SheetEditChanging,可在儲存格編輯過程中讀取目前的富文字值。此時內容仍在編輯器內,編輯結束後才會提交到工作表。

TypeScript
import '@univerjs/sheets-ui/facade'const subscription = univerAPI.addEvent(univerAPI.Event.SheetEditChanging, ({ value }) => {  console.log(value.toPlainText())})// Call subscription.dispose() when the owning component or page is removed.

單元格編輯器聚焦時,點選外部按鈕觸發事件,獲取的 snapshot 未包含當前單元格資料

單元格資料會在編輯器失焦(即編輯狀態結束)時同步到 snapshot。因此,在嘗試獲取 snapshot 資料前,應確保單元格已經失去焦點。可以透過如下方式主動結束編輯:

TypeScript
import '@univerjs/sheets-ui/facade'async function saveWorkbook() {  const fWorkbook = univerAPI.getActiveWorkbook()  if (!fWorkbook) return  await fWorkbook.endEditingAsync(true)  const snapshot = fWorkbook.save()  console.log(snapshot)}$btn.addEventListener('click', () => {  saveWorkbook().catch(console.error)})

參考:https://github.com/dream-num/univer/issues/1314

使用 Facade API 建立 Workbook 後,立即呼叫其它 API 不生效的情況

部分 API 依賴於介面渲染完成後才能正常工作。如果在 Workbook 建立後立即呼叫相關 API,可能因尚未完成渲染而失效。建議在生命週期的 Rendered 或 Steady 階段再進行相關操作:

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.LifeCycleChanged, ({ stage }) => {  if (stage === univerAPI.Enum.LifecycleStages.Steady) {    // 程式碼...  }})// 需要移除事件監聽時,可呼叫 disposable.dispose()

參考:生命週期

你覺得這篇文檔如何?

© 2026 DreamNum Co., Ltd.