ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ContentEditable에서 커서(Caret) 활용하기(3) - 자바스크립트
    백수의 개발/웹 2020. 3. 4. 20:32

    ContentEditable에서 커서(Caret) 활용하기(3) - 자바스크립트

    [ ContentEditable에서 커서(Caret) 활용하기(2) - 자바스크립트 ]에서 Caret을 설정하고, 드래그의 형태로 만드는 것 까지 진행해봤다.

    그러나 드래그의 형태로 해보면 알겠지만, 뒤에서 앞으로 드래그를 했을때와, 앞에서 뒤로 드래그를 했을 때는 엄연히 다를 것이다.

    이번 글을 통해 이에 대해 알아보고 ContContentEditable에서 커서(Caret) 활용하기를 마무리 하겠다.

     

    드래그 한 Caret의 위치

    내가 키보드나 마우스로 Caret을 조정하였다면 큰 문제는 없을 것이다. 그런데 앞에서 한 것 처럼 Caret을 인위적으로 바꿨다면 나의 기준은 어디이고, 기준은 어떻게 바꿔야 할까?

    아래와 같이 드래그가 되도록 Caret을 설정하였을 때 Shift + 를 하면 어느방향으로 갈까?

    아무런 설정 없이 Caret을 설정했다면, "아"로 부터 드래그가 움직일 것이다.

    그렇다면 "다"로 부터 드래그가 움직이도록 기준을 바꾸는건 어떻게 해야할까?

     

    이를 제대로 알기 위해서는 Selection에 대해 알아야한다. [ ContentEditable에서 커서(Caret) 활용하기(1) - 자바스크립트 ]에서도 Selection에 대해 작성하였지만, 크게 다루지 않았다. 여기서도 간단하게 알아보고 각각의 역할을 알아보자.

    Selection{
    	anchorNode: node,
    	anchorOffset: number,
    	baseNode: node,
    	baseOffset: number,
    	extentNode: node,
    	extentOffset: number,
    	focusNode: node,
    	focusOffset: number,
    	isCollapsed: boolean,
    	rangeCount: number,
    	type: string
    }

    그려진 caret의 형태만 봤을 때 anchor이 앞(시작점), focus가 뒤(끝지점)이라고 보면된다. 그래서 anchor가 focus보다 뒤에 있을 수 없다.

    이와 비슷하게 base와 extent가 있는데 anchor/focus와 유사하지만 조금 다르다.

    caret이 그려진다고 생각했을 때 base가 출발점, extent가 도착점으로 방향이 있다고 생각하면 된다.

     

    그렇다면 우리는 어떻게 base와 extent를 설정할 수 있을지 알아보자.

    [ ContentEditable에서 커서(Caret) 활용하기(2) - 자바스크립트 ]에서 caret을 설정한 것에서 base와 extent만 바꿔주면 된다.

    아래의 코드를 통해 확인해보자. 위에 보여준 이미지를 바탕으로 "다"의 위치에서 caret이 움직을 수 있도록 수정해보자.

    <div contenteditable='true'>
    	<span>가나다</span><span>라마바사</span><span>아자차</span>
    <div>
    const spanList = document.querySelectorAll("span");
    
    // 각 span으로 부터 text node 가져오기
    const startContainer = spanList[0].childNodes[0];
    const startOffset = 2;
    const endContainer = spanList[2].childNodes[0];
    const endOffset = 1;
    
    // Range 설정
    const newRange = document.createRange();
    newRange.setStart(startContainer, startOffset);
    newRange.setEnd(endContainer, endOffset);
    
    // Selection에 전달
    const selection = document.getSelection();
    selection.removeAllRanges();
    selection.addRange(newRange);
    
    // Base와 Extent 교체
    selection.setBaseAndExtent(selection.extentNode, selection.extentOffset, selection.baseNode, selection.baseOffset);

    마지막에 있는 setBaseAndExtent를 통해 간단히 바꿔주어 아래 이미지 처럼 동작하게 할 수 있다.

    테스트

    간단히 테스트를 진행해보자.

    setInterval(() => {
      const spanList = document.querySelectorAll("span");
    
      // 각 span으로 부터 text node 가져오기
      const startContainer = spanList[0].childNodes[0];
      const startOffset = 2;
      const endContainer = spanList[2].childNodes[0];
      const endOffset = 1;
    
      // Range 설정
      const newRange = document.createRange();
      newRange.setStart(startContainer, startOffset);
      newRange.setEnd(endContainer, endOffset);
    
      // Selection에 전달
      const selection = document.getSelection();
      selection.removeAllRanges();
      selection.addRange(newRange);
    
      // Base와 Extent 교체
      // 있을 때와 없을 때의 차이를 확인해보자.
      selection.setBaseAndExtent(selection.extentNode, selection.extentOffset, selection.baseNode, selection.baseOffset);
    }, 3000)

    이런식으로 간단히 interval을 통해 3초마다 caret이 설정 된 후 Shift + ← or 를 해보면 잘 작동하는지 확인할 수 있을 것이다.

    댓글

Designed by Tistory.