[강의] 브라우저와 자바스크립

김하은·2023년 11월 6일
0

코드잇 강의 정리

목록 보기
33/60

브라우저도 객체다?

  • JavaScript: 웹 브라우저를 다루기 위해서 등장한 프로그래밍 언어
  • window객체: 브라우저의 창을 대변하면서 JavaScript에서는 최상단에 존재하는 객체
    • 최상단: 윈도우 객체가 JavaScript의 다른 모든 객체를 포함하고 있다는 뜻
    • 모든 내장 객체, 내장 함수들은 윈도우 객체에 속해 있음
    • JavaScript의 어느 곳에서나 접근할 수 있으므로 전역 객체 (Global Object)라고 함
    • window.은 생략할 수 있음
    • window 객체 더 알아보기
console.log(window);
console.log(typeof window); // object

DOM

  • 문서 객체 모델 (Document Object Model): 웹 페이지에 나타나는 html 문서 전체를 객체로 표현한 것
  • document 객체가 웹 문서의 최상단 객체로 진입점의 역할을 함
  • 따라서 document객체를 활용하면 웹 페이지 내부에 무엇이든 수정할 수 있고 새로운 콘텐츠를 만들어 낼 수 있음
  • 직접적으로 접근하려고 하면 window 객체와 다르게 객체가 아닌 html 태그가 출력 됨
console.log(document);
console.log(typeof document); // object

  • DOM을 태그가 아닌 객체로 보고 싶으면 콘솔 객체의 dir 메소드를 활용하면 됨
console.dir(document);

  • DOM 개념에 따르면 문서 내의 모든 태그들은 각각의 객체임

  • DOM을 활용하면 JavaScript로 html 태그를 객체처럼 자유롭게 다룰 수 있음

console.dir vs console.log

콘솔에서 값 자체를 확인하고 싶다면 log메소드를, 객체의 속성들을 살펴보고 싶다면 dir 메소드를 활용하면 좋음

  1. 출력하는 자료형이 다름
    • dir메소드는 문쟈열 표시 현식으로 콘솔에 출력함
  2. 출력 결과가 다름
    - log 메소드는 파라미터로 전달받은 값을 위주로 출력함
    - dir 메소드는 객체의 속성을 좀 더 자세하게 출력함
    - 특히 함수 부분에서는 클릭해서 펼쳤을 때 함수가 가진 속성들을 더 보여줌(log 메소드는 펼쳐지지 않음)
  3. 파라미터로 전달할 수 있는 값의 개수가 다름
    • log 메소드는 여러 값을 쉼표로 구분해서 전달하면 전달받은 모든 값을 출력함
    • dir 메소드는 여러 값을 전달하더라도 첫 번째 값만 출력함
console.log(str, num, bool, arr, obj, func);
console.dir(str, num, bool, arr, obj, func);


4. DOM 객체를 출력하는 결과가 다름

  • 값에 좀 더 중점을 둔 log 메소드는 대상을 HTML 형태로 출력함
  • 객체의 속성에 좀 더 중점을 둔 dir 메소드는 대상을 객체 형태로 출력함

DOM 트리

  • document 객체를 최상위로 해서 계층 구조를 이룬 것
  • 노드: DOM 트리에서는 각 개체를 노드라는 용어로 표현함
    • 각 노드 간의 관계를 부모 노드, 자식 노드, 형제 노드로 표현함
    • 노드 타입
      • 요소 노드(Element Node): 태그를 표현하는 노드
      • 텍스트 노드(Text Node): 문자열을 표현하는 노드
        • 일반적으로 텍스트 노드들은 요소 노드의 자식 노드가 됨
        • 따로 자식 노드를 가질 수 없기 때문에 잎 노드(leaf node)라고 부름
      • 코멘트 노드, 문서 노드 등 총 12가지의 노드 타입이 존재하지만 대부분 요소노드와 텍스트 노드로 구성 됨
      • 12 가지 노드들

DOM 트리 여행하기

  • DOM을 이용하면 JavaScript로 웹 문서를 자유롭게 다룰 수 있음
  • 원하는 태그를 선택하는 방법

1. document 객체의 메소드 활용하기

const myTag = document.querySelector('#content')
console.log(myTag);

2. DOM 트리의 부모, 자식, 형제 관계를 활용하기

- 자식 요소 노드
- console.log(myTag.children);

- console.log(myTag.children[1]);

- console.log(myTag.firstElementChild);
- console.log(myTag.lastElementChild);

- 부모 요소 노드
- console.log(myTag.parentElement);

- 형제 요소 노드
- console.log(myTag.previousElementSibling);
- console.log(myTag.nextElementSibling);

- 서로 연결해서 탐색도 가능함
- console.log(myTag.parentElement.nextElementSibling)

3. 요소 노드가 아닌 다른 노드들을 이동하고 싶은 경우

  • 자주 사용 되지는 않음
  • console.log(myTag.childNodes)

요소 노드 프로퍼티

const myTag = document.querySelector('#list-1');

1. innerHTML

  • 요소 안에 있는 html 자체를 문자열로 리턴해 줌

  • 내부에 있는 줄 바꿈이나 들여쓰기 모두 포함됨

  • 요소 안의 html을 수정 할 때 자주 활용 됨

    • innerHTML 프로퍼티에 html 코드를 문자열로 할당하면 해당 요소가 이 값으로 완전히 수정 됨
myTag.innerHTML = '<li>Exotic</li>'; // 요소 수정
myTag.innerHTML += '<li>Exotic</li>'; // 기존 html 마지막 부분에 요소 추가

2. outerHTML

  • 해당 요소를 포함한 전체 html 코드를 문자열로 리턴해줌
  • 내부에 있는 줄 바꿈이나 들여쓰기 모두 포함됨
  • outerHTML에 값을 할당 하게 되면 처음 선택한 요소는 사라짐

3. textContent

  • 요소 안에 있는 내용들 중 html을 제외한 텍스트만 가지고 옴
  • 내부에 있는 줄 바꿈이나 들여쓰기 모두 포함됨
  • innerHTML과 마찬가지로 요소 안의 내용을 수정할 수 있음
  • 특수 문자도 텍스트로 출력함
myTag.textContent = '<li>new text!</li>';
console.log(myTag.textContent);

  • 만약 사용자의 입력값을 웹 페이지에 반영해야 될 때 innerHTML보다는 textContent를 활용하면 원하지 않는 html 코드가 반영되는 걸 막을 수 있음

요소 노드 추가하기

  • innerHTML, outerHTML 은 내용을 덮어 써버려서 사용할 때 기존 내용을 보존하려면 기존의 값을 한 번 더 써줘야하는 불편함이 있음
  • 특히 outerHTML는 한번 프로퍼티를 수정하고 나면 완전히 새로운 요소가 돼서 이후에 그 요소를 다루려면 해당 요소를 다시 찾아야 함
  • 따라서 덮어쓰는 방식이 아닌 필요한 요소 노드만 생성해서 추가하는 방법을 사용해 보자
const tomorrow = document.querySelector('#tomorrow');

1. 요소 노드 만들기

  • document.createElement('태그이름')
  • const first = document.createElement('li'): 원하는 태그 이름으로 요소 노드를 만들 수 있음

2. 요소 노드 꾸미기

  • textContent, innerHTML, ...
  • first.textContent = '처음';
  • 내부에 '처음'이라는 글자를 담고 있는 li 태그가 완성됨

3. 요소 노드 추가하기

  • NODE.prepend, append, after, before
  • tomorrow.prepend(first);: 메소드를 호출한 노드의 제일 첫 번째 노드로 파라미터로 전달한 값을 추가할 수가 있음

  • 문자열을 바로 전달 할 수도 있음
tomottow.before('문자열', prev);

노드 삭제와 이동하기

const today = document.querySelector('#today');
const tomorrow = document.querySelector('#tomorrow');

remove

tomorrow.remove();
today.children[2].remove();

이동하기

  • prepend, append, before, after
today.append(tomorrow.children[1]);

tomorrow.children[1].after(today.children[1]);

HTML 속성 다루기

  • DOM의 메소드를 이용해서 html 속성 다루기
  • 상황에 따라서 html 속성과 DOM 프로퍼티의 이름이 일치하지 않을 수도 있음
<body>
  <div>
    <h1>오늘 할 일</h1>
		<ol id="today">
      <li class="item">자바스크립트 공부</li>
			<li class="item">고양이 화장실 청소</li>
			<li class="item">고양이 장난감 쇼핑</li>
		</ol>
		<h1>내일 할 일</h1>
    <ol id="tomorrow" href="https://www.codeit.kr">
      <li class="item"><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript">자바스크립트 공부</a></li>
			<li class="item">뮤지컬 공연 예매</li>
			<li class="item">유튜브 시청</li>
		</ol>
  </div>
  <script src="index.js"></script>
</body>

요소 노드의 프로퍼티

  • html 태그들이 가지고 있는 각각의 속성들은 요소 노드의 프로퍼티가 됨
  • 대부분의 html 속성들은 이름 그대로 요소 노드의 프로퍼티로 생성이 됨
// HTML 속성 (HTML attribute)
const tomorrow = document.querySelector('#tomorrow');
const item = tomorrow.firstElementChild;
const link = item.firstElementChild;

// id 속성
console.log(tomorrow);
console.log(tomorrow.id);

// class 속성
console.log(item);
console.log(item.className);

// href 속성
console.log(link);
console.log(link.href);
console.log(tomorrow.href); // undefined

1. html 표준이 아닌 속성에 접근하기 (getAttribute 메소드)

  • 하지만 모든 html 속성이 요소 노드의 프로퍼티로 생성되지는 않음
  • html 표준 속성 확인
  • html 표준이 아닌 속성에 접근하려면 getAttribute 메소드를 활용하면 됨
// element.getAttribute('속성'): 속성에 접근하기
console.log(tomorrow.getAttribute('href'));
console.log(item.getAttribute('class'));

2. 속성 추가하기 (setAttribute 메소드)

// element.setAttribute('속성', '값'): 속성 추가(수정) 하기
tomorrow.setAttribute('class', 'list'); // 추가
link.setAttribute('href', 'https://www.codeit.kr'); // 수정

3. 속성 삭제하기 (removeAttribute 메소드)

// element.removeAttribute('속성'): 속성제거하기
tomorrow.removeAttribute('href');
tomorrow.removeAttribute('class');

  • 3 가지 메소드 모두 속성 이름들은 대소문자를 구분하지 않음
  • html 표준 속성은 모두 소문자임

스타일 다루기

<body>
  <div>
    <h1 class="title">오늘 할 일</h1>
		<ol id="today" class="list today">
			<li class="item">자바스크립트 공부</li>
			<li class="item">고양이 화장실 청소</li>
			<li class="item">고양이 장난감 쇼핑</li>
		</ol>
		<h1 class="title">내일 할 일</h1>
		<ol id="tomorrow" class="list tomorrow">
			<li class="item">자바스크립트 공부</li>
			<li class="item">뮤지컬 공연 예매</li>
			<li class="item">유튜브 시청</li>
		</ol>
  </div>
  <script src="index.js"></script>
</body>
const today = document.querySelector('#today');
const tomorrow = document.querySelector('#tomorrow');

1. style 프로퍼티 활용

  • 여러 단어를 이어서 만든 속성은 카멜 표기법을 이용해야 함
  • 태그에 직접적으로 값이 적용 돼서 스타일 우선 순위가 높아짐
  • 같은 스타일을 여러 태그에 적용할 때 비슷한 코드를 불필요하게 많이 작성해야 함
// style 프로퍼티
today.children[0].style.textDecoration = 'line-through';
today.children[0].style.backgroundColor = '#DDDDDD';
today.children[2].style.textDecoration = 'line-through';
today.children[2].style.backgroundColor = '#DDDDDD';

2. className 프로퍼티 활용

  • done클래스에 미리 작성해둔 스타일이 입혀지는 방식
  • 클래스 속성값 전체가 바뀐다는 단점이 있음
.done {
  opacity: 0.5;
  text-decoration: line-through;
}
today.children[1].className = 'done';

3. classList 프로퍼티 활용

  • 클래스의 속성 값을 유사 배열로 다루는 프로퍼티
  • add, remove, toggle 메소드 사용 가능
  • add
    • 여러 개의 클래스를 넣고 싶을 때는 쉼표로 구분해서 여러개의 파라미터로 전달하기 (remove도)
    • 같은 이름의 클래스를 중복 추가 해도 하나만 추가 됨
  • toggle
    • 있으면 제거하고 없으면 추가하는 메소드
    • 여러개의 파라미터를 전달한다고 해도 여러개를 토글 하지는 않음
    • 토글의 기능을 강제하는 기능이 있으나 많이 사용하지는 않음 (true, false)
const item = tomorrow.children[1];
item.classList.add('done');
item.classList.remove('done');
item.classList.toggle('done');

비표준 속성 다루기

  • 비표준 속성: html에서 정해진 속성이 아닌 개발자가 임의로 정한 속성으로 Javascript로 html을 조작하기 위해 사용할 수 있음

대괄호[]를 이용한 css 선택자

  • [속성이름]: 대괄호 안에 있는 속성이름을 가진 태그들을 선택할 수 있음
  • [속성이름="값"]: 속성이름에 해당 값을 가진 태그들을 선택할 수 있음
<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="UTF-8">
  <title>JS with Codeit</title>
</head>

<body>
  <p>할 일 : <b field="title"></b></p>
  <p>담당자 : <b field="manager"></b></p>
  <p>상태 : <b field="status"></b></p>
  <div>
    상태 변경: 
    <button class="btn" status="대기중">대기중</button>
    <button class="btn" status="진행중">진행중</button>
    <button class="btn" status="완료">완료</button>
  </div>
  <script src="index.js"></script>
</body>

</html>
[status] {
  padding: 5px 10px;
}

[status="대기중"] {
  background-color: #FF6767;
  color: #FFFFFF;
}

[status="진행중"] {
  background-color: #5f62ff;
  color: #FFFFFF;
}

[status="완료"] {
  background-color: #07c456;
  color: #FFFFFF;
}

1. 선택자로 활용

  • css 선택자를 활용해서 태그를 선택하는 데에 활용할 수 있음
const fields = document.querySelectorAll('[field]');
console.log(fields);


2. 값을 표시할 태그를 구분할 때 활용

  • 비표준 속성은 객체 형태의 데이터가 있을 때, 각 프로퍼티 값들이 들어갈 태그를 구분하는데 활용할 수도 있음
const fields = document.querySelectorAll('[field]'); // 3개의 b태그들
const task = {
  title: '코드 에디터 개발',
  manager: 'CastleRing, Raccoon Lee',
  status: '',
};

for (let tag of fields) {
  const field = tag.getAttribute('field'); // field 속성의 값들 즉, title, manager, status
  tag.textContent = task[field]; // task 객체의 key에 대한 값들 즉, '코드 에디터 개발', 'CastleRing, Raccoon Lee'
}


3. 스타일이나 데이터 변경에 활용

  • getAttribute 메소드를 활용해서 속성값을 가져오고, setAttribute 메소드를 활용해서 속성값을 설정해주는 원리로 이벤트를 통해 실시간으로 스타일을 변경하거나 데이터를 변경하는데 활용할 수 있음
const fields = document.querySelectorAll('[field]');
const task = {
  title: '코드 에디터 개발',
  manager: 'CastleRing, Raccoon Lee',
  status: '',
};

for (let tag of fields) {
  const field = tag.getAttribute('field');
  tag.textContent = task[field];
}

const btns = document.querySelectorAll('.btn');
for (let btn of btns) {
  const status = btn.getAttribute('status'); // status 속성의 값들 즉, 대기중, 진행중, 완료
  btn.onclick = function () {
    fields[2].textContent = status; // text 값 대기중, 진행중, 완료 설정
    fields[2].setAttribute('status', status); //속성 status에 대기중, 진행중, 완료 추가
  };
}


dataset 프로퍼티

  • 비표준 속성을 사용해 코드를 작성했을 때 시간이 지나서 나중에 그 속성이 표준으로 등록되면 문제가 발생할 수 있음
  • 따라서 비표준 속성을 사용하기 위해 미리 약속된 방식인 data-* 속성이 있음
  • data-로 시작하는 속성은 모두 dataset이라는 프로퍼티에 저장됨
  • data-status라는 속성이 있다면, element.dataset.status라는 프로퍼티에 접근해서 그 값을 가져올 수 있음
<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="UTF-8">
  <title>JS with Codeit</title>
</head>

<body>
  <p>할 일 : <b data-field="title"></b></p>
  <p>담당자 : <b data-field="manager"></b></p>
  <p>상태 : <b data-field="status"></b></p>
  <div>
    상태 변경: 
    <button class="btn" data-status="대기중">대기중</button>
    <button class="btn" data-status="진행중">진행중</button>
    <button class="btn" data-status="완료">완료</button>
  </div>
  <script src="index.js"></script>
</body>

</html>
[data-status] {
  padding: 5px 10px;
}

[data-status="대기중"] {
  background-color: #FF6767;
  color: #FFFFFF;
}

[data-status="진행중"] {
  background-color: #5f62ff;
  color: #FFFFFF;
}

[data-status="완료"] {
  background-color: #07c456;
  color: #FFFFFF;
}
const fields = document.querySelectorAll('[data-field]');
const task = {
  title: '코드 에디터 개발',
  manager: 'CastleRing, Raccoon Lee',
  status: '',
};

for (let tag of fields) {
  const field = tag.dataset.field;
  tag.textContent = task[field];
}

const btns = document.querySelectorAll('.btn');
for (let btn of btns) {
  const status = btn.dataset.status;
  btn.onclick = function () {
    fields[2].textContent = status;
    fields[2].dataset.status = status;
  };
}

참고 자료

profile
아이디어와 구현을 좋아합니다!

0개의 댓글