Range 넌 뭘까?(핥아보기)

김범기·2025년 12월 17일

서론

회사 업무중 페이지 만들고 있었것을 모달안에 고대로 집어 넣어야하는 상황이 생겼다.
이런....
어쩌겠나 우겨넣어봐야지.

카테고리페이지- 제품 관련 모달 - 내가 만들어놓은 페이지 - 페이지안의 여러가지 뭐 불러오는 모듈들

뭐 이런식의 구조로 되어있었다.하니까 일단 얼추 생겨먹은건 흠 봐줄만 하군 하게 생겨먹었는데,
아오 모달에 들어가서 내가 필요한 작업이 실행이 안되었다.

몇 시간을 끙끙 댔는데 문제는 의외로 단순했다.ㅋㅋㅋㅋㅋ

내가 모달을 만들때 innerHTML을 만들어서,

마 느그 다 이 div안에 들으가는기다 알겠제?

이러고 있었다. 이러니 js가 들어가있는 script는 모달안에 들어가지도 못했으니, 작동이 안되는게 당연하지 아옼ㅋㅋㅋㅋㅋㅋ 보고도 뭐가 문젠지 모르고 있었닼ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

도와주던 선임께서 알려줘서 깨ㅋ달ㅋ음ㅋ

이벤트 위임해서 하는 방법도 있는데, 그건 부모가 너무 더러워지니까 내가 선호하는 방식이 아니다. 게다가 내가 몇개를 넣을 줄 알고 그걸 해;;;;

그래서 찾던 중 range! 오 그 찬란한 이름 range를 사용해봤다.
그러니 잘된다 이야호

본론

https://developer.mozilla.org/ko/docs/Web/API/Range
에 들어가서 Range를 보자

Range 객체는 주어진 document 내의 텍스트 노드들의 부분들(parts)과 document의 단편화에 포함된 노드들을 나타내고 있다.

Range 오브젝트는 Document 객체에 포함되어 있는 createRange 메소드를 사용하여 생성할 수 있다. 또한 selection 객체에 포함되어 있는 getRangeAt 메소드를 사용하여 추출할 수 있다.

Range() 생성자 또한 사용 가능하다.

라고 말하고 있다.

range 그 뜻대로 어떤 범위로 이해해도 되지만, 난 다음처럼 이해했다. "노드 덩어리"

저 range를 이용해서 단순 text들의 범위 설정도 가능하지만, 노드 전체를 들었다놨다도 할 수 있기때문이다.

text에 대한 range 예시

우선 단순 text에 range를 이용한 것은 이 내용을 보면 확인할 수 있다.
html

<p>First paragraph.</p>
<p>Second paragraph.</p>
<p>Third paragraph.</p>
<p>Fourth paragraph.</p>

js

const paragraphs = document.querySelectorAll("p");

// Create new range
const range = new Range();

// Start range at second paragraph
range.setStartBefore(paragraphs[1]);

// End range at third paragraph
range.setEndAfter(paragraphs[2]);

// Get window selection
const selection = window.getSelection();

// Add range to window selection
selection.addRange(range);

결과물
2번째 ~ 3번째 영역을 냠냠. 했으니 2번째와 3번째는 getselection에 의해 냠냠 되었다.

node에 대한 range 예시

우선 선택 방법은

const range = document.createRange();

로 range를 만들어 준 다음
selectNode를 해주면 되는데,

selectNode()
selectNodeContents()

가 있다.

selectNode()는

<section>
  <div>
    <h1>h1태그는 짱 큼</h1>
    <p>p태그는 그냥 그럼</p>
  </div>
</section>

이런 문구에서 section까지 다 포함해서 선택을 하는 것이고,
selectNodeContents()는 sectionㄴㄴ 그 밑에놈들만 ㅇㅇ. 하는 것이다.
그래서 Contents가 붙었다.

얘네를 쓰는 이유는 그냥 만들면 허공에 만드는 것과 같은데, selectNode로 '이 코드는 이 div 안에서 뒹굴댈 녀석임 ㅇㅇ라고 정확히 잡아줘야 브라우저가 태그 구조를 올바르게 해석해주고 내가 써먹을 수 있기 때문이다.

selectNode는 요소를 통째로 뭐 옮기든 지우든 할 때

얘는 요롷게 쓴다.

let range = document.createRange();
let referenceNode = document.getElementsByTagName("div").item(0);

range.selectNode(referenceNode);

selectNodeContents는 그 안의 내용물을 후루룩짭짭하고 싶을 때 쓴다고 한다.

얘는 요롷게 쓴다

const range = document.createRange();
const referenceNode = document.querySelector("div");
range.selectNodeContents(referenceNode);

나의 경우는 Node를 선택했고, 그 안에 파일을 넣어야했다.

그래서 이런걸 썼다.

createContextualFragment(tagString)

https://developer.mozilla.org/en-US/docs/Web/API/Range/createContextualFragment

이걸 이용하면 html파일을 range 안에 넣을 수 있게 포장을 해준다.

tagString안에 내가 그 range안에 넣고 싶었던 것을 넣으면 된다.
단순히 짧은 div 덩어리를 를 넣고 싶으면 그걸 넣어도된다.

내가 넣고 싶은게 정해져서

range.createContextualFragment(넣을거)

를 하고 나면, 이제 내가 선택해뒀던, section이든 div든 박스 안에 포장물을 넣어주도록 하자.

그리고 내가 넣으려고 했던 녀석 안에 넣는 건 간단하다.

내가넣으려고했던것을담아둘_div든_section이든.appendChild(포장물)

요로코롬!!!!

이게 내가 필요했던 방식이다.

const tagString = "<div>I am a div node</div>";
const range = document.createRange();

// Make the parent of the first div in the document become the context node
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.createContextualFragment(tagString);
document.body.appendChild(documentFragment);

range를 생성해주고, 그 range를 선택해주고, 선택한 range안에 내용물을 넣기.

이 방식을 내가 골머리 앓던 곳에 넣으면 아래와 같다.

내가 한 작업

  async function openModal(내파일주소) {
    const modal = document.getElementById('모다리');
    const contentBox = document.getElementById('내파일집어넣을곳');

    modal.style.display = 'flex';

    // css transition이 먹힐 수 있게 잠깐 대기, opacity 1로 변경시키려고
    setTimeout(() => {
      modal.classList.add('show');
    }, 10);

    try {
      const response = await fetch(내파일주소)
      if (!response.ok) {
        throw new Error(`모달 불러오기 실패 ${response.status}`)
      }
      const htmlData = await response.text();
      contentBox.innerHTML = htmlData;
    } catch (error) {
      console.error('Error fetching modal', error)
      contentBox.innerHTML = '<p class="">컨텐츠를 불러오는 데 실패했습니다.</p>';
    }
  }

기존 코드는 이런식으로 생겨먹었었다.
너무나 눈에 명확히 innerHTML이 보이지 않는가. 왜 인지를 못했지;;;;

얘는 script를 못 먹으니까 요로코롬 바꿔줬다.

async function openModal(내파일주소) {
    const modal = document.getElementById('modalOverlay');
    const contentBox = document.getElementById('modalContent');

    modal.style.display = 'flex';

    // css transition이 먹힐 수 있게 잠깐 대기
    setTimeout(() => {
      modal.classList.add('show');
    }, 10);

    try {
      const response = await fetch(내파일주소)
      if (!response.ok) {
        throw new Error(`모달 불러오기 실패 ${response.status}`)
      }
      const htmlData = await response.text();
      contentBox.innerHTML = '';
      const range = document.createRange();
      range.selectNode(contentBox);
      const documentFragment = range.createContextualFragment(htmlData);
      contentBox.appendChild(documentFragment);
    } catch (error) {
      console.error('Error fetching modal', error)
      contentBox.innerHTML = '<p class="">컨텐츠를 불러오는 데 실패했습니다.</p>';
    }
  }

결론

세상엔 너무나 많은 씡기방기한 코드들이 있다.

또 천재들이 너무많다.

나는 멍청이다. 으어어어어

그래도 하나는 더 알아낸 멍청이다 으아아아아아아아

profile
반드시 결승점을 통과하는 개발자

0개의 댓글