댓글

댓글 기능을 사용하면 문서에 댓글과 답글을 추가할 수 있어 팀원 간의 소통과 협업이 쉬워집니다.

플러그인 모드

설치

Shell
pnpm add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui

사용법

TypeScript
import { LocaleType, mergeLocales, Univer } from '@univerjs/core'import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment'import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui'import SheetsThreadCommentUIEnUS from '@univerjs/sheets-thread-comment-ui/locale/en-US'import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'import ThreadCommentUIEnUS from '@univerjs/thread-comment-ui/locale/en-US'import '@univerjs/sheets-thread-comment-ui/lib/index.css'import '@univerjs/thread-comment-ui/lib/index.css'import '@univerjs/sheets-thread-comment/facade'const univer = new Univer({  locale: LocaleType.EN_US,  locales: {    [LocaleType.EN_US]: mergeLocales(      ThreadCommentUIEnUS,       SheetsThreadCommentUIEnUS,     ),  },})univer.registerPlugin(UniverThreadCommentPlugin)univer.registerPlugin(UniverThreadCommentUIPlugin)univer.registerPlugin(UniverSheetsThreadCommentPlugin)univer.registerPlugin(UniverSheetsThreadCommentUIPlugin)

공동 편집 기능과 함께 사용하기

공동 편집 기능을 사용하는 경우 다음과 같이 구성하세요.

Shell
pnpm add @univerjs-pro/thread-comment-datasource
TypeScript
import { UniverThreadCommentDataSourcePlugin } from '@univerjs-pro/thread-comment-datasource'univer.registerPlugin(UniverThreadCommentDataSourcePlugin)

모바일 지원

먼저 모바일 에디터를 구성하세요. 이 페이지의 플러그인 모드 초기화 코드에서 아래 데스크톱 등록을 같은 패키지의 모바일 버전으로 바꾸고 문서를 열기 전에 완료하세요. 모델 플러그인, 스타일, 언어 파일과 Facade 가져오기는 유지하며 두 버전을 동시에 등록하지 마세요.

패키지데스크톱 등록모바일 등록
@univerjs/sheets-thread-comment-uiUniverSheetsThreadCommentUIPluginUniverSheetsThreadCommentMobileUIPlugin
@univerjs/thread-comment-uiUniverThreadCommentUIPluginUniverThreadCommentMobileUIPlugin

프리셋 모드

설치

Shell
pnpm add @univerjs/preset-sheets-thread-comment

사용법

TypeScript
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'import { UniverSheetsThreadCommentPreset } from '@univerjs/preset-sheets-thread-comment'import UniverPresetSheetsThreadCommentEnUS from '@univerjs/preset-sheets-thread-comment/locales/en-US'import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'import '@univerjs/preset-sheets-core/lib/index.css'import '@univerjs/preset-sheets-thread-comment/lib/index.css'const { univerAPI } = createUniver({  locale: LocaleType.EN_US,  locales: {    [LocaleType.EN_US]: mergeLocales(      UniverPresetSheetsCoreEnUS,      UniverPresetSheetsThreadCommentEnUS,     ),  },  presets: [    UniverSheetsCorePreset(),    UniverSheetsThreadCommentPreset(),   ],})

Facade API

전체 Facade API 타입 정의는 FacadeAPI에서 확인할 수 있습니다.

가져오기

플러그인 모드 참고 사항

플러그인 모드에서만 Facade 패키지를 직접 가져와야 합니다. 프리셋 모드에는 해당 Facade 패키지가 이미 포함되어 있으므로 추가로 가져올 필요가 없습니다.

TypeScript
import '@univerjs/sheets-thread-comment/facade'

셀 댓글 만들기

univerAPI.newTheadComment()를 사용하여 새 댓글 빌더를 만들 수 있습니다. 이 메서드는 FTheadCommentBuilder 인스턴스를 반환하며, 메서드를 체이닝하여 댓글의 여러 속성을 설정할 수 있습니다.

다음은 FTheadCommentBuilder의 일부 멤버 메서드입니다.

메서드설명
setContent댓글 내용을 설정합니다
setPersonId댓글 작성자의 ID를 설정합니다
setDateTime댓글의 날짜와 시간을 설정합니다
setId댓글 ID를 설정합니다
setThreadId댓글 스레드 ID를 설정합니다
TypeScript
// Create a new commentconst richText = univerAPI.newRichText().insertText('hello univer')const commentBuilder = univerAPI.newTheadComment()  .setContent(richText)console.log(commentBuilder.content.toPlainText())// Add the comment to cell A1const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const cell = fWorksheet.getRange('A1')const result = await cell.addCommentAsync(commentBuilder)

셀 댓글 가져오기

다음 메서드를 사용하여 댓글을 가져올 수 있습니다. 각 메서드는 FThreadComment 인스턴스를 반환하며, 이를 통해 댓글을 업데이트하거나 삭제 또는 해결할 수 있습니다.

  • FWorkbook.getComments(): 통합 문서의 모든 댓글을 가져옵니다
  • FfWorksheet.getComments(): 워크시트의 모든 댓글을 가져옵니다
  • FRange.getComment(): 범위의 왼쪽 위 셀에 있는 댓글을 가져옵니다
  • FRange.getComments(): 범위의 모든 댓글을 가져옵니다

다음은 FThreadComment의 일부 멤버 메서드입니다.

메서드설명
getIsRoot댓글이 루트 댓글인지 확인합니다
getCommentData댓글 데이터를 가져옵니다
getReplies댓글의 답글 목록을 가져옵니다
getRange댓글의 범위를 가져옵니다
getRichText댓글의 리치 텍스트 내용을 가져옵니다
deleteAsync댓글과 답글을 삭제합니다
updateAsync댓글 내용을 업데이트합니다
resolveAsync댓글을 해결합니다
replyAsync댓글에 답글을 작성합니다
TypeScript
// Get all comments in the workbookconst fWorkbook = univerAPI.getActiveWorkbook()fWorkbook.getComments()// Get all comments in the active worksheetconst fWorksheet = fWorkbook.getActiveSheet()fWorksheet.getComments()const fRange = fWorksheet.getRange('A1:B2')// Get the comment of cell A1fRange.getComment()// Get all comments in the range A1:B2fRange.getComments()

셀 댓글 지우기

  • FWorkbook.clearComments(): 통합 문서의 모든 댓글을 지웁니다
  • FWorksheet.clearComments(): 워크시트의 모든 댓글을 지웁니다
  • FRange.clearCommentAsync(): 범위의 왼쪽 위 셀에 있는 댓글을 지웁니다
  • FRange.clearCommentsAsync(): 범위의 모든 댓글을 지웁니다
TypeScript
// Clear all comments in the workbookconst fWorkbook = univerAPI.getActiveWorkbook()await fWorkbook.clearComments()// Clear all comments in the active worksheetconst fWorksheet = fWorkbook.getActiveSheet()await fWorksheet.clearComments()const fRange = fWorksheet.getRange('A1:B2')// Clear the comment of cell A1await fRange.clearCommentAsync()// Clear all comments in the range A1:B2await fRange.clearCommentsAsync()

댓글 답글 목록 가져오기

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Get all comments in the worksheetconst comments = fWorksheet.getComments()comments.forEach((comment) => {  // If the comment is a root comment, get its replies  if (comment.getIsRoot()) {    const replies = comment.getReplies()    replies.forEach((reply) => {      console.log(reply.getCommentData())    })  }})

댓글 업데이트/삭제/해결/답글 작성

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Create a new comment and add it to cell A1const richText = univerAPI.newRichText().insertText('hello univer')const commentBuilder = univerAPI.newTheadComment()  .setContent(richText)  .setId('mock-comment-id')const cell = fWorksheet.getRange('A1')await cell.addCommentAsync(commentBuilder)// Update the comment and reply after 3 secondssetTimeout(async () => {  // Get the comment by ID and update its content  const comment = fWorksheet.getCommentById('mock-comment-id')  const newRichText = univerAPI.newRichText().insertText('Hello Univer AI')  await comment.updateAsync(newRichText)  // Create a new reply comment and set its content  const replyText = univerAPI.newRichText().insertText('Hello Univer AI! GO! GO! GO!')  const reply = univerAPI.newTheadComment().setContent(replyText)  await comment.replyAsync(reply)}, 3000)// Resolve the comment and delete it after 6 secondssetTimeout(async () => {  const comment = fWorksheet.getCommentById('mock-comment-id')  await comment.resolveAsync()  await comment.deleteAsync()}, 6000)

이벤트 리스너

전체 이벤트 타입 정의는 Events에서 확인할 수 있습니다.

댓글 모듈은 댓글 추가, 업데이트, 삭제 및 해결 상태 변경을 수신할 수 있는 일련의 이벤트를 제공합니다. 모든 이벤트는 univerAPI.addEvent()를 사용하여 수신할 수 있습니다.

댓글 추가 이벤트

univerAPI.Event.CommentAdded: 댓글이 추가된 후 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentAdded, (params) => {  const { comment, workbook, worksheet, row, col } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentAdd: 댓글이 추가되기 전에 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentAdd, (params) => {  const { comment, workbook, worksheet, row, col } = params  // Cancel the comment addition operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

댓글 업데이트 이벤트

univerAPI.Event.CommentUpdated: 댓글이 업데이트된 후 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentUpdated, (params) => {  const { comment, workbook, worksheet, row, col } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentUpdate: 댓글이 업데이트되기 전에 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentUpdate, (params) => {  const { comment, workbook, worksheet, row, col, newContent } = params  // Cancel the comment update operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

댓글 삭제 이벤트

univerAPI.Event.CommentDeleted: 댓글이 삭제된 후 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentDeleted, (params) => {  const { commentId, workbook, worksheet } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentDelete: 댓글이 삭제되기 전에 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentDelete, (params) => {  const { comment, workbook, worksheet, row, col } = params  // Cancel the comment deletion operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

댓글 해결 상태 이벤트

univerAPI.Event.CommentResolved: 댓글의 해결 상태가 변경된 후 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentResolved, (params) => {  const { comment, row, col, resolved, workbook, worksheet } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentResolve: 댓글의 해결 상태가 변경되기 전에 트리거됩니다

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentResolve, (params) => {  const { comment, row, col, resolved, workbook, worksheet } = params  // Cancel the comment resolution operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

모든 이벤트에는 다음과 같은 공통 매개변수가 포함됩니다.

  • workbook: 현재 통합 문서 인스턴스
  • worksheet: 현재 워크시트 인스턴스
  • row: 댓글의 행 인덱스
  • col: 댓글의 열 인덱스
  • comment: 댓글 객체(삭제 이벤트에는 commentId만 포함됨)

특수 매개변수는 다음과 같습니다.

  • BeforeCommentUpdate 이벤트에는 newContent가 포함됩니다: 새 댓글 내용(RichTextValue 타입)
  • CommentResolved 및 BeforeCommentResolve 이벤트에는 resolved가 포함됩니다: 댓글 해결 상태

접두사가 Before인 모든 이벤트 콜백 함수는 params.cancel = true를 반환하여 해당 작업을 막을 수 있습니다.

공통 댓글 작업

공통 댓글 Facade와 제품 Facade를 모두 가져오세요. 제품 메서드는 안정적인 앵커를 만들고 공통 API는 답글, 수정, 해결 및 삭제를 처리합니다. getComments()는 로컬 상태를 읽습니다. listCommentsAsync()는 설정된 데이터 소스를 통해 알려진 스레드를 동기화하며 서버의 모든 스레드를 검색하지 않습니다.

TypeScript
import '@univerjs/thread-comment/facade'const [thread] = univerAPI.getComments({ resolved: false })if (thread) {  await univerAPI.replyCommentAsync({    unitId: thread.unitId,    subUnitId: thread.subUnitId,    threadId: thread.threadId,    content: 'Reviewed.',  })}

공유 토론

Server SDK로 Comment Service와 Endpoint를 통합하고 협업 및 라이선스를 설정한 뒤 @univerjs-pro/thread-comment-datasource의 UniverThreadCommentDataSourcePlugin을 등록하세요. 내장 데이터 소스는 /universer-api/comment/unit/{unitId}/...와 /universer-api/user/list를 사용하므로 앱에서 해당 경로를 제공해야 합니다. 서버는 문서 편집 권한과 별도로 댓글 읽기 및 쓰기 권한을 확인해야 합니다.

이 가이드는 어떠셨나요?

© 2026 DreamNum Co., Ltd.