프론트엔드/DOM

DOM - 요소노드에 대한 접근

ksge7 2020. 10. 7. 01:32

'DOM'은 'HTML' 문서의 요소와 내용들을 객체화시킨 것이다.

 

그리고 이러한 객체에 접근하여 컨트롤을 해줄 수 있다.

 

그리고 이때 접근하기 쉽게 메서드와 프로퍼티가 제공된다.

 

여기서는 문서의 요소(Element) 노드에 어떻게하면 접근할 수 있는지를 알아본다.

단일 요소에 접근하기

1. getElementById()

 

대략 해석해서 쓰자면 다음과 같다.

 

'파라미터로 주어진 문자열과 동일한 id값를 통해 요소를 얻을 수 있게 한다.'

 

'getElementById()'에 제공한 문자열과 동일한 'id' 속성을 가진 요소를 HTML 문서에서 찾아준다.

 

그리고 이 'id' 속성을 가진 'Element' 객체를 반환한다.

 

즉 해당 요소를 이용할 수 있게 도와준다는 말이다.

 

<body>

    <p id="test"> ID테스트입니다. </p>

    <script>
        document.getElementById('test').innerHTML = "아이디 속성으로 접근합니다.";
        // 해당 코드를 실행하면
        // 'test'를 'id'로 가진 <p> 태그의 내용이
        // "아이디 속성으로 접근합니다"로 변경된다.

    </script>
</body>

 

코드는 위와 같다.

 

위와 같이 메서드를 안에 문자열을 넣어주면 해당 문자열과 동일한 'id'값을 가진 요소의 객체를 반환한다.

 

<body>

    <p id="test"> ID테스트입니다. </p>
    
    <p id="test"> ID테스트입니다.2 </p>

    <script>
        document.getElementById('test').innerHTML = "아이디 속성으로 접근합니다.";
        // 해당 코드를 실행하면
        // 첫번째 'test'를 'id'로 가진 <p> 태그의 내용이
        // "아이디 속성으로 접근합니다"로 변경된다.

    </script>
</body>

 

참고로 해당 메서드는 'html' 문서 내에서 단 하나만 존재해야하는 'id'값에 접근하는 것이다.

 

그래서 메서드의 이름도 자세히 보면 다른 요소 객체 반환 메서드와 달리 'getElement'다.

 

즉 여러개가 아닌 하나의 요소만 얻게해준다는 것이다.

 

그리고 위 코드처럼 같은 'id'값을 두개를 써도 둘 중 처음 나오는 'id'값의 요소 객체만을 반환한다.

복수 요소에 접근하기

복수 요소에 접근하는 대략 세가지 메서드가 존재한다.

 

● getElementsByTagName

 

● getElementsByClassName

 

● querySelectorAll

 

세 가지 메서드 모두 단일 요소를 선택하는 'getElementById'와 다르다.

 

메서드 이름에 'All'이나 'Elements'와 같이 복수 요소를 선택할 수 있다는 뜻의 단어를 내포하고 있다.

 

세가지 메서드를 이용하면 'HTML' 문서에서 내가 원하는 모든 요소의 객체를 반환해준다는 것이다.

 

앞서 'getElementById'는 동일 'id' 값이 아무리 많아도 그중 첫 번째 요소만 반환했다.

 

하지만 위의 세 가지 메서드는 메서드의 조건에 해당하는 모든 요소의 객체를 반환한다.

 

각 메서드 별로 살펴보자.

1. getElementsByTagName()

 

대략 해석해서 쓰자면 다음과 같다.

 

'파라미터로 주어진 태그명과 같은 복수의 태그 요소들의 객체를 반환한다.'

 

즉 'getElementsByTagName'를 쓰면 같은 태그 네임을 가진 복수의 요소의 객체를 반환한다는 것.

 

코드로 보자.

 

<body>
    <p> 일반 문장입니다. </p>
    <p> 일반 문장입니다. </p>
    <p> 일반 문장입니다. </p>

    <script>

        document.getElementsByTagName('p').innerHTML = "태그네임으로 접근합니다";

    </script>
</body>

 

위 코드를 실행하면 어떻게 될까? 결론부터 말하면 아무런 변화가 없다.

 

얼핏보면 <P> 태그를 가진 모든 요소의 내용이 "태그네임으로 접근합니다"로 바뀔 것 같다.

 

하지만 그렇지 않다.

 

'getElementsByTagName'는 문서 내에 있는 조건에 맞는 요소의 객체를 모두 반환한다고 했다.

 

하지만 요소의 객체를 모두 반환한다고해서 모든 <p> 태그의 내용을 바꿔버린다면 문제가 생길 것이다.

 

만약 세 개의 <p> 태그 중 마지막 <p> 태그만 바꾸고 싶다면 이 메서드를 사용할 수 없기 때문이다.

 

그래서 'getElementsByTagName' 뿐 아니라 다른 복수 요소에 접근하는 모든 메서드는

 

조건에 맞는 객체를 유사 배열이라는 객체라는 배열과 유사한 형태로 만들어 객체를 반환한다.

 

우선 위 코드에서 쓴 'document.getElementsByTagName('p')' 를 'console.log'로 출력해보자.

 

<body>
    <p> 일반 문장입니다. </p>
    <p> 일반 문장입니다. </p>
    <p> 일반 문장입니다. </p>

    <script>

        console.log(document.getElementsByTagName('p'));

    </script>
</body>

 

 

위 코드를 실행한 결과는 아래와 같다.

 

 

어딘지 우리가 알고있는 배열과 비슷하다. 실제로 사용법도 동일하다.

 

<body>
    <p> 일반 문장입니다 1. </p>
    <p> 일반 문장입니다 2. </p>
    <p> 일반 문장입니다 3. </p>

    <script>

        document.getElementsByTagName('p')[0].innerHTML = "유사배열 1"
        document.getElementsByTagName('p')[1].innerHTML = "유사배열 2"
        document.getElementsByTagName('p')[2].innerHTML = "유사배열 3"
        
        // 메서드 뒤에 배열처럼 []로 인덱스를 선택해줬다.
        
        // 이 상태로 코드를 실행하면
        // <p> 태그들은 각각 
        // "유사배열 1", "유사배열 2", "유사배열 3"으로 바뀐다.

    </script>
</body>

 

만약 복수의 요소 중 한 개만 선택해서 사용하고 싶다면 위의 코드처럼 하면된다.

 

배열 쓰듯이 인덱스 넘버를 지정해주면 거기에 맞는 요소를 컨트롤 할 수 있다.

 

만약 복수로 <p> 태그의 한번에 컨트롤 하고 싶다면 다음과 같이 하면 된다.

 

<body>
    <p> 일반 문장입니다 1. </p>
    <p> 일반 문장입니다 2. </p>
    <p> 일반 문장입니다 3. </p>

    <script>

        for(i=0; i < document.getElementsByTagName('p').length; i++){
            document.getElementsByTagName('p')[i].innerHTML = "유사배열 "+(i+1);
        }
        
        // for 문을 이용하면 인덱스의 값을 자동으로 바꾸면서
        // 해당 HTML에서 원하는 모든 요소를 한번에 컨트롤 할 수 있다.
        // 참고로 해당 코드를 실행하면 다음과 같다.
        // 각각의 <p> 태그 내용은
        // "유사배열 1", "유사배열 2", "유사배열 3"로 바뀐다.

    </script>
</body>

 

for문을 이용해서 인덱스를 자동으로 지정하면 HTML 문서 내에서 해당 조건에 맞는 모든 요소를 컨트롤할 수 있다.

 

하지만 뭔가 복잡하다. 더 쉬운 방법도 존재한다.

 

하지만 지금은 아니고 추후 유사배열로 다시 정리할 예정이다.

 

우선 여기선 남은 두 메서드를 살펴보자.

 

2. getElementsByClassName()

 

대략 풀어쓰면 이렇다.

 

'파라미터로 주어진 문장과 일치하는 클래스 네임을 가진 복수 요소들의 객체를 반환한다.'

 

즉 'getElementsByClassName'는 원하는 조건에 맞는 클래스 속성을 가진 요소의 객체를 컨트롤 할수 있게 한다.

 

그리고 당연하게도 복수 요소에 접근하는 메서드라

 

'getElementsByTagName'과 같이 유사배열의 형태로 객체를 반환한다.

 

<body>
    <p class = "t_class"> 클래스적용 문장입니다 1. </p>
    <p class = "t_class"> 클래스적용 문장입니다 2. </p>
    <p class = "t_class"> 클래스적용 문장입니다 3. </p>

    <script>
        
        document.getElementsByClassName('t_class')[0].innerHTML = "클래스로 접근합니다 1";
        document.getElementsByClassName('t_class')[1].innerHTML = "클래스로 접근합니다 2";
        document.getElementsByClassName('t_class')[2].innerHTML = "클래스로 접근합니다 3";
        // 해당 내용을 실행하면 다음과 같다
        // <p> 태그의 내용은 순서대로 이렇게 바뀐다.
        // "클래스로 접근합니다 1"
        // "클래스로 접근합니다 2"
        // "클래스로 접근합니다 3"
        
    </script>
</body>

 

사용법도 'getElementsByTagName'과 같다.

 

복수의 요소를 한번에 컨트롤 하는 것도 동일하다.

 

<body>
    <p class = "t_class"> 클래스적용 문장입니다 1. </p>
    <p class = "t_class"> 클래스적용 문장입니다 2. </p>
    <p class = "t_class"> 클래스적용 문장입니다 3. </p>

    <script>

        for(i=0; i < document.getElementsByClassName('t_class').length; i++){
            document.getElementsByClassName('t_class')[i].innerHTML = "클래스로 접근합니다";
        }
        // 해당 코드 실행시
        // <p> 태그의 내용은 모두 "클래스로 접근합니다"로 변경

    </script>
</body>

 

이 또한 더 편하게 복수의 요소를 컨트롤할 수 있는 방법이 있지만 우선은 넘어간다.

 

3. querySelectorAll()

 

대략 해석하면 다음과 같다.

 

'파라미터를 통해 주어진 선택자를 이용해 조건에 맞는 복수 요소들의 객체를 반환한다.'

 

앞서 말한 메서드들은 'tagname', 'class', 'id' 와 같이 'HTML'에서 제공하는 기능을 가지고

 

반환반을 요소들을 선택할 수 있었다.

 

하지만 'querySelectorAll()'를 쓰면 CSS 선택자를 이용하여 요소들을 선택할 수 있다.

 

이 방법을 이용하면 'id', 'class' 처럼 일일이 속성을 지정하지 않아도 요소들을 구분하여 선택이 가능하다.

 

'tagname'의 경우 'HTML'에서 조건에 해당하는 모든 요소들의 객체를 반환하기에 부담스럽다.

 

하지만 'querySelectorAll'는 조금 더 세밀한 조건 설정을 통해 원하는 객체 반환이 비교적 쉽다.

 

우선 코드를 보자.

 

<body>
    <ul>
        <li> 일번 </li>
        <li> 이번 </li>
    </ul>
    <div>
        <li> 일번 </li>
        <li> 이번 </li>
    </div>

    <script>
        
        document.querySelectorAll('li')[0].innerHTML = " ul > li 쿼리셀렉터로 접근합니다";
        document.querySelectorAll('li')[1].innerHTML = " ul > li 쿼리셀렉터로 접근합니다";
        document.querySelectorAll('li')[2].innerHTML = " div > li 쿼리셀렉터로 접근합니다";
        document.querySelectorAll('li')[3].innerHTML = " div > li 쿼리셀렉터로 접근합니다";
        
        // 모든 <li> 태그 내의 내용은 순서대로 아래처럼 바뀐다.
        // " ul > li 쿼리셀렉터로 접근합니다";
        // " ul > li 쿼리셀렉터로 접근합니다";
        // " div > li 쿼리셀렉터로 접근합니다";
        // " div > li 쿼리셀렉터로 접근합니다";

    </script>
</body>

 

위 코드는 우선 문서 내의 모든 <li> 태그의 객체를 반환받아 컨트롤하는 코드다.

 

'tagname' 선택과 비슷한 모양새다.

 

하지만 이럴 때보다 아래 코드의 경우 'querySelectorAll'의 진가가 드러난다.

 

<body>
    <ul>
        <li> 일번 </li>
        <li> 이번 </li>
    </ul>
    <div>
        <li> 일번 </li>
        <li> 이번 </li>
    </div>

    <script>
        
        document.querySelectorAll('ul > li')[0].innerHTML = " ul > li 쿼리셀렉터로 접근합니다";

        document.querySelectorAll('div > li')[0].innerHTML = " div > li 쿼리셀렉터로 접근합니다";

        // 위 코드를 실행하면 <li> 태그는 순서대로 이렇게 바뀐다.

        // "ul > li 쿼리셀렉터로 접근합니다"
        // "이번"
        // "div > li 쿼리셀렉터로 접근합니다"
        // "이번"

    </script>
</body>

 

전의 코드처럼 투박하게 <li> 태그를 전부 선택한 것이 아니라 CSS 선택자 방식을 이용했다.

 

각각 <div>, <ul>의 아래 있는 <li> 태그를 구분하여 선택했다.

 

당연히 유사배열을 통해 돌려받는 인덱스도 달라진다.

 

그리고 당연히 'querySelectorAll' 메서드도 조건에 맞는 모든 요소를 선택하고 싶다면 for 문을 쓴다.