BEB 07 2-1

Donghun Seol·2022년 9월 19일
0

코드스테이츠 BEB 07

목록 보기
4/39

DOM 이해와 조작

DOM

HTML 요소들을 객체화 하여 조작하기 편리하게 만든 모델

주 학습내용

const tweetDiv = document.createElement('div')
document.body.append(tweetDiv)
const tweets = document.querySelectorAll('.tweet') // returns Array-like Object

document 하위 DOM 객체에 대해서도 querySelector 적용 가능하다.

유연한 querySelector 예시

const el = document.querySelector("div.user-panel:not(.main) input[name='login']");

Array-like Object

배열처럼 동작하지만 배열의 인터페이스를 모두 제공하진 않는다.

const arrLikeObj = document.querySelector('body').children // returns <HTMLCollection> obj
arrLikeObj.forEach(e => console.dir(e)); // Error
Array.from(arrLikeObj).forEach(e => console.dir(e)); // Works

const nodeList = document.querySelectorAll('.tweet'); // returns <nodeList> object
nodeList.forEach(e => console.dir(e)); // Works on <nodeList> object
nodeList.reduce(e => e + 1); // reduce does not works on nodeList -array like object

//using spread operator to convert nodelist to array
const nodeListArr = [...nodeList] // now reduce, map works on nodeListArr

createDocumentFragment

성능이나 가독성을 위해 임시로 사용하는 HTML 엘리먼트 조각
메인 DOM에 들어가지 않으므로 page reflow를 발생시키지 않는다.
John Resig님에 따르면 요정도로 빠르다 카더라

const $fragment = document.createDocumentFragment();
  [1, 2, 3, 4].forEach(() => {
    const rowData = [];
    // data.push(rowData);
    const $tr = document.createElement('tr');
    [1, 2, 3, 4,].forEach(() => {
      // rowData.push(0);
      const $td = document.createElement('td');
      $tr.appendChild($td);
    });
    $fragment.appendChild($tr);
  });
  console.log($fragment);
  $table.appendChild($fragment);

template tag

말 그대로 템플릿을 담은 태그다.
html에 포함되어 있지만 페이지 로딩시에 바로 화면에 보여주지 않고, 자바스크립트를 통해
데이터를 입력하면 화면에 나타나게 하는 것.
최근에는 템플릿 엔진이 있으므로 굳이 활용하지는 않을 것 같다.

node와 element의 차이

노드는 웹 문서안의 모든 요소를 의미한다. 주석도 노드가 된다.
element는 html태그로 둘러쌓인 노드를 의미한다. 엘리먼트는 특별한 노드이므로 id나 class를 가질 수 있다.

document.querySelector("#main").childNodes // 모든 자식 노드를 반환(주석도)
document.querySelector("#main").children // 모든 자식 element(=element node)를 반환

생성한 tweetDiv 를 container 에 넣기 위해서는, container 를 먼저 찾아야 합니다. 어떻게 container 를 찾을 수 있을까요? 위에서 언급했던 DOM 트리를 순회해서 찾을 수 있습니다. 그러나 보다 더 편리한 방법이 있으니 검색해보시기 바랍니다.

같은 엘리먼트를 appendChild하면, 기존 엘리먼트를 복사할까?

<div class="a">
    <span></span>
</div>
<div class="b"></div>
const divB = document.querySelector(.b’); 
divB.appendChild(span);

span은 어디로 갈까?
1. a에 그대로 있나?
2. 양쪽에 다 포함되나?
3. b로 이동하나?

답은 3번 b로 이동한다.
객체이므로 포인터만 바꿔주니까 이동할 것이라고 직관적으로 이해했다.
아래에 더 상세한 설명있음.
관련 글

sprint 유효성 검사

pre

regex

정규식 정리, 다음 강의를 수강하면서 정리해본다. 정규표현식 , 더이상 미루지 말자 🤩
드림코딩 채널인데, 정규식이라는 내용자체는 어떤 자료를 가지고해도 대동소이하겠지만 강사 엘리님의 목소리와 발음이 좋고, 진행을 지루하지 않게 잘 해주셔서 자주 찾게 되는 것 같다.

결국 서비스의 성패는 비기능적 요구사항에 달려 있다는 생각이 든다. 기능적 요구사항을 충족하는 것은 당연히 기본중의 기본이고...
1. Group

| 또는
() 그룹
[] 문자셋, 괄호안의 어떤 문자든지 매칭
[^] 부정 문자셋, 괄호안의 모든 문자도 아닌 것
(?:) 찾지만 기억하진 않음

  • "|" 를 활용하여 or 연산으로 그룹내, 그룹간 여러 글자를 매칭할 수 있다.


2. Quantifier

? : zero or one
* : zero or more
+ : one or more
{n} : n번 반복
{min,}
{min,max}

  • + 연산자 사용
  • 반복 횟수 지정
  • 최솟값 지정

3. Boundary

\b : 단어 경계, 단어의 앞이나 뒤에 붙여 시작과 끝을 명시 가능
\B : 단어 경계가 아님, 소문자 \b의 반대 역할
^ : 줄 단위 시작 경계, 멀티라인모드 아닐시 전체 문서대상
$ : 줄 단위 끝 경계, 멀티라인 아닐시 전체 문서를 대상


4. Character Classes

\ : 이스케이프
. : 줄바뀜 문자가아닌 모든 문자
\d : 숫자
\D : 숫자 아님
\w : 문자
\W : 문자 아님
\s : 공백
\S : 공백 아님

Quiz

아래의 정규식을 해석해 보세요.
그룹핑을 잘 활용하면 엄청 편리합니다.
그리고 특정 그룹의 데이터를 가져오지 않으려면 어떻게 할까요?

Regex in JS
url.match()가 배열을 반환한다는 점을 유의!

regex Quiz
regex REPL

sprint

유효성 검사의 최초 과제는 쉽게 해결했으나, 추가 기능 구현에서 예상치 못한 버그가 발생했고, 페어분과 해결하면서 많은 공부가 되었다. 페어분에게 다시 한번 감사드린다.

오류는 forEach 루프에서 return를 하고 break처럼 작동한다고 착각해서 발생하였다.
foreEach에서는 break가 동작하지 않고, forEach를 every로 바꾸고 return false; 하면 break 처럼 동작한다. 아래 코드가 제대로 동작하는 샘플

enroll.addEventListener('change', () => {
  if (elPassword.value !== elPasswordRetype.value) {
    submitBtn.disabled = true;
    return;
  }
  enroll.querySelectorAll('input').forEach(elem => {
    if (elem.value.length === 0) {
      submitBtn.disabled = true;
      return // ERROR HERE!!!
    }
    submitBtn.disabled = false;
  });
});

// Fixed Like Below
enroll.addEventListener('change', () => {
  if (elPassword.value !== elPasswordRetype.value) {
    submitBtn.disabled = true;
    return;
  }
  enroll.querySelectorAll('input').every(elem => {
    if (elem.value.length === 0) {
      submitBtn.disabled = true;
      return false;
    }
    submitBtn.disabled = false;
  });
});
profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글