TIL2. 다크모드 구현하기

Byoungju Park·2021년 6월 14일
0
post-thumbnail
post-custom-banner

완성 결과물 : https://byoungjupark.github.io/Week1/
깃헙 코드 : https://github.com/byoungjupark/Week1.git

1. html에 버튼 만들기

1-1 JavaScript 파일 생성

<head>
  ...
  <script src="js.js"></script>
<head>

가장 먼저 JavaScript 파일을 따로 생성하여 html head 태그에 넣어주었다.

1-2 버튼 생성

그 다음 자바스크립트의 실행은 버튼을 클릭할 때마다 이루어지기로 한다.
input 태그에 속성을 넣는다.
type : 버튼 형태로 만들어보았고, type의 종류는 다양하다. (text, check box, radio 등) 기능에 알맞은 타입을 선택하면 된다.
value : 초기값은 Dark로 지정하였다.
onclick : 클릭을 할때마다 changeColor 함수가 실행된다.

2. JavsScript로 다크모드 함수 만들기

2-1 DOM을 이용해 html 요소 선택하기

어떻게 하면 html의 요소들을 JavaScript에 연결시킬 수 있을까?
DOM을 이용해서!

DOM(Document Object Model)은 html을 연결해주는 API!

다크모드를 구현할 때 변화될 요소는 크게 2가지이다.

  1. 배경화면 색상 (body, head)
document.querySelector("body").style.backgroundColor = "black";
document.querySelector("header").style.backgroundColor = "black";

나의 경우, body만 선택하면 상단의 header 색상은 변하지 않는다는 것이다. 이 부분은 아직 해결하지 못 하였고 우선 header도 선택하였다.
body와 head는 각각 1개씩 존재하여 querySelector 메소드로 연결시킨 후, 색상 속성을 통해 색상을 지정한다.

  1. 글자 색상 (h2, p, span, a)
let pTag = document.getElementsByTagName("p")
for(let i=0; i<pTag.length; i++) {
	pTag[i].style.color = "white";
}
let aTag = document.links
for(let i=0; i<aTag.length; i++) {
	aTag[i].style.color = "white";
}

나의 html에 들어있는 글자 요소는 h2, p, span이다. a에도 글자가 포함된 부분이 있기 때문에 글자색상에 간주하고 설명하겠다.

주의할 점!
querySelector를 사용한다면 p태그 여러 개 중 첫번째 p태그만 선택된다.
따라서 querySelectorAll이나 getElementsByTagName를 사용하여 태그 전체를 불러오도록 한다. 이 메소드들은 값을 배열 형태로 가져오기 때문에, for문을 사용하여 모든 p태그가 색상이 지정되도록 한다.

다른 글자 태그들도 getElementsByTagName 메소드를 사용한다. a태그는 links 메소드로 바로 연결이 되기 때문에 links를 사용한다.

2-2 버튼 클릭할 때 다크모드 실행되는 함수 만들기

위와 같이 html 요소들을 연결시켜 색상을 지정해주었다.
지정만 되었을 뿐,
버튼을 클릭할 때마다 일어날 함수인 changeColor와 연결되어 있지 않다.
changeColor 안에 넣어보자!

function changeColor() {
document.querySelector("body").style.backgroundColor = "black";
document.querySelector("header").style.backgroundColor = "black";
        
let pTag = document.getElementsByTagName("p")
for(let i=0; i<pTag.length; i++) {
	pTag[i].style.color = "white";
}
let h2Tag = document.getElementsByTagName("h2")
for(let i=0; i<h2Tag.length; i++) {
	h2Tag[i].style.color = "white";
}
let spanTag = document.getElementsByTagName("span")
for(let i=0; i<spanTag.length; i++) {
	spanTag[i].style.color = "white";
}
let aTag = document.links
for(let i=0; i<aTag.length; i++) {
	aTag[i].style.color = "white";
}
}

이제 버튼을 클릭하면 색상이 바뀌게 된다.

2-3 버튼 클릭할 때마다 다크모드, 라이트모드 전환하기 (if문 추가)

버튼을 재클릭해도 다크모드 그대로이다. 클릭할 때마다 다크모드, 라이트모드로 전환할 수 있도록 if문을 사용해보자!

function changeColor(self) {
  if(self.value === "Dark") {
    document.querySelector("body").style.backgroundColor = "black";
    .
    .
    let aTag = document.links
    for(let i=0; i<aTag.length; i++) {
	    aTag[i].style.color = "white";
    }
    self.value = "Light";
    } else {
    document.querySelector("body").style.backgroundColor = "white";
    .
    .
    let aTag = document.links
    for(let i=0; i<aTag.length; i++) {
	    aTag[i].style.color = "black";
    }
    self.value = "Dark";
}

input 태그의 value 값이 Dark 일 때, 다크모드를 구현하며 value 값을 Light로 동시에 바꾼다. value 값이 Light 일 때, 라이트모드를 구현하며 value 값을 다시 Dark로 바꾼다.

3. 리팩토링

반복되는 구조가 많아 리팩토링을 하여 효율적이고 간략하게 표현해보자!

3-1 변수 선언하기

const 변수로 선언하였다.
body와 header 태그는 둘다 배경화면 변경이라는 공통점을 지녔기 때문에 하나의 변수로 묶었다. 글자 태그들도 하나의 변수로 묶고 싶었지만, 여러 html 페이지마다 들어있는 태그들이 달라 undefined element error 가 발생하여 JavaScript가 실행되지 않았다. 그래서 우선 각각의 변수들을 선언하였다.

이들 변수들은 함수의 기능을 가지도록 함수로 표현하였다. 색상을 함수 안에 직접적으로 넣지 않고 parameter를 설정하여 parameter에 색상을 입력하도록 하였다.

3-2 함수 간략화하기

changeColor함수 안에 위에 변수로 선언한 객체들을 넣는다. parameter 값으로 원하는 색상을 입력한다.

4. 해결되지 못한 점

  1. header도 select를 해야했던 점
  • body만 select를 할 경우, header는 다크모드 구현이 되지 않았다.
    (header가 body의 자식 요소임에도 불구하고)
  1. 글자태그 (p, h2, span, a) 구조가 같지만 통합되지 못한 점
  • 일부 html에는 h2 element가 없어서 undefined element error가 발생하였다.
  1. 2번 문제로 인해 function도 2개로 나누어 만들었던 점
  • h2 element가 포함된 함수와 포함되지 않은 함수 2가지를 만들었다. (아래 그림 참조)
  • 이 부분은 overriding을 이용하면 되지 않을까 싶다.
  1. 다크모드를 실행한 후 다른 html에서 리셋되는 점
  • localStorage를 사용하면 된다고 하는데, 내 경우는 실행되지 못했다.

profile
wanna be good programmer
post-custom-banner

0개의 댓글