멘션 노드 타입

카테고리: 커스텀 • 뷰 연동 노트를 포함한 상세 구현 가이드

스키마 정의

멘션 노드 타입의 스키마 정의:

{
  mention: {
    inline: true,
    attrs: {
      id: { default: '' },
      label: { default: '' }
    },
  }
}

모델 표현

모델 표현 예제:

{
  type: 'mention',
  attrs: {
    id: 'user123',
    label: '@사용자명'
  }
}

HTML 직렬화

모델을 HTML로 변환:

function serializeMention(node) {
  return '<span data-type="mention" data-id="' + escapeHtml(node.attrs.id) + 
         '">' + escapeHtml(node.attrs.label) + '</span>';
}

HTML 역직렬화

HTML을 모델로 파싱:

function parseMention(domNode) {
  return {
    type: 'mention',
    attrs: {
      id: domNode.getAttribute('data-id') || '',
      label: domNode.textContent || ''
    }
  };
}

뷰 연동

뷰 연동 노트: 이 노드 타입을 뷰 레이어에서 구현할 때 contenteditable 동작, 선택 처리, 이벤트 관리에 특히 주의하세요.

뷰 연동 코드:

// 멘션 렌더링
const mention = document.createElement('span');
mention.setAttribute('data-type', 'mention');
mention.setAttribute('data-id', node.attrs.id);
mention.textContent = node.attrs.label;
mention.className = 'mention';
mention.contentEditable = 'false'; // 멘션은 일반적으로 직접 편집되지 않음

일반적인 문제

일반적인 함정: 이 노드 타입을 구현할 때 자주 발생하는 문제들입니다. 구현 전에 주의 깊게 검토하세요.

일반적인 문제 및 해결 방법:

// 문제: 멘션 자동완성
// 해결: 멘션 자동완성 구현
function handleMentionInput(e) {
  const query = e.target.value;
  if (query.startsWith('@')) {
    showMentionSuggestions(query.slice(1));
  }
}

// 문제: 멘션 삭제
// 해결: 멘션을 단위로 삭제 처리
function handleMentionDeletion(mention) {
  // 멘션 전체를 삭제, 일부만 삭제하지 않음
  mention.remove();
}

구현

완전한 구현 예제:

class MentionNode {
  constructor(attrs) {
    this.type = 'mention';
    this.attrs = {
      id: attrs?.id || '',
      label: attrs?.label || ''
    };
  }
  
  toDOM() {
    const mention = document.createElement('span');
    mention.setAttribute('data-type', 'mention');
    mention.setAttribute('data-id', this.attrs.id);
    mention.textContent = this.attrs.label;
    mention.className = 'mention';
    return mention;
  }
  
  static fromDOM(domNode) {
    return new MentionNode({
      id: domNode.getAttribute('data-id') || '',
      label: domNode.textContent || ''
    });
  }
}