/ JAVASCRIPT

JavaScript(14) - basic

JavaScript 관련 포스팅

※ 이 글은 윤인성님의 Youtube 강의 내용을 참고 작성한 글입니다.
예시는 변경해 적용한 부분이 많으니 참고하시기 바랍니다.
원본 출처는 문서 하단을 확인하시기 바랍니다.

1. 요소 값 추출 및 입력

1-1. 요소 값 추출

  • textContent, innerHTML

      <body>
          <h1 id="first">h1 태그에 입력된 기존 문자열입니다.</h1>
          <script src="main.js"></script>
      </body>
    
      document.addEventListener('DOMContentLoaded', () => {
          const header1 = document.querySelector('#first');
    
          // 태그 확인
          console.log(header1);   
            
          // 값 추출 
          console.log(header1.textContent);
          console.log(header1.innerHTML);
      });
    

    image

  • querySelector('selector') 사용 방법

    • selector: CSS selector를 string으로 넣음
    • <h1 id="header">제목</h1>
        document.querySelector('h1')
        document.querySelector('#header')
        document.querySelector('h1#header')
      
    • <span class="choose">선택</span>
        document.querySelector('span')
        document.querySelector('.choose')
        document.querySelector('span.choose')
      
    • <input id="name-input" type="text" name="name">
        document.querySelector('input')
        document.querySelector('#name-input')
        document.querySelector('[type=text]')
        document.querySelector('input[type=text]')
        document.querySelector('input[type=text][name=name]')
      

1-2. 요소에 원하는 값 입력

  • textContent
    • tag일반 문자열로 인식
    • 많이 사용
  • innerHTML
    • tag를 인식
    • 보안상 문제가 될 수 있어서 많이 사용하지 않음
<body>
    <h1 id="first">h1 태그에 입력된 기존 문자열입니다.</h1>
    <h2 id="second">h2 태그에 입력된 기존 문자열입니다.</h2>
    <script src="main.js"></script>
</body>
document.addEventListener('DOMContentLoaded', () => {
    const header1 = document.querySelector('#first');
    const header2 = document.querySelector('#second');

    // 값 입력
    header1.textContent = 'apple pie<br>🥧';
    header2.innerHTML = 'apple pie<br>🥧'
    
    // 값 추출
    console.log(header1.textContent);
    console.log(header2.textContent);
});

image

2. 속성 조작하기

2-1. 표준에 있는 속성 조작하기

  • 해당 속성을 직접 지정
      <body>
          <img src="" alt="">
          <script src="main.js"></script>
      </body>
    
    document.addEventListener('DOMContentLoaded', () => {
      const img = document.querySelector('img');
        
      // 값 입력
      img.src = 'http://placekitten.com/200/200';
      // 값 추출
      console.log(img.src);
    });
    

    image

2-2. 표준에 없는 속성(사용자 정의 속성) 조작하기

  • setAttribute('속성 이름', '값')
  • getAttribute('속성 이름')

      <body>
          <img src="" alt="">
      </body>
    
      document.addEventListener('DOMContentLoaded', () => {
          const img = document.querySelector('img');
            
          // 값 입력
          img.setAttribute('src', 'http://placekitten.com/152/152');
    
          // 값 추출
          console.log(img.getAttribute('src'));
      });
    

    image

3. 스타일 조작하기

  • style.backgroundColor
    • 일반적으로 많이 사용
  • style['background-color']
    • CSS의 속성 명으로 쓰고 싶을 때 사용
      <body>
          <!-- div tag 10개 -->
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <script src="main.js"></script>
      </body>
    
      document.addEventListener('DOMContentLoaded', () => {
          const divs = document.querySelectorAll('div'); // div 여러 개 이므로 divs로 표현
          divs.forEach((div, key) => { // key는 index값
          // 값 입력
          div.style.backgroundColor = `rgb(${key*25.5}, ${key*25.5}, ${key*25.5})`;
          div.style.height = '30px'; // 반드시 문자열로 넣고 단위 생략하면 안 됨!
            
                  // 값 추출
          console.log(div.style.backgroundColor)
          })
      });
    

    image

4. 문서 객체 생성하기

  • document.createElement('태그 이름')
    • element 생성
  • appendChild()
    • 화면에 element 붙이기
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 만들기
          // createElement()
          const header = document.createElement('h1');
                
          // element의 속성 지정
          header.textContent = 'createElement로 만든 tag';
          header.style.color = 'salmon';
    
          // element 붙이기
          // appendChild()
          const body = document.querySelector('body');
          body.appendChild(header);
      });
    

    image

5. 문서 객체 제거하기

  • removeChild()
    • 해당 요소를 직접 제거
  • parentNode.removeChild()
    • 부모 요소를 이용해 제거하는 방법
    • 많이 사용
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 만들기
          // createElement()
          const header1 = document.createElement('h1');
          const header2 = document.createElement('h2');
          header1.textContent = 'createElement로 만든 tag1입니다!';
          header2.textContent = 'createElement로 만든 tag2입니다!';
          header1.style.color = 'green';
          header2.style.color = 'red';
    
          // element 붙이기
          // appendChild()
          const body = document.querySelector('body');
          body.appendChild(header1);
          body.appendChild(header2);
    
          // element 제거하기
          // 편의상 2초 뒤에 element가 제거되도록 setTimeout() 사용
          setTimeout(() => {
              // body.removeChild(header1);
              header1.parentNode.removeChild(header1); // 많이 사용함
          }, 2000);
      });
    
  • body.removeChild() vs. header.parentNode.removeChild()
    • bodyheader.parentNode는 같은 의미임
    • header.parentNode의 경우, 부모요소(body) 언급없이 제거할 요소만 지칭하므로 사용하기 편리해 많이 씀 image

      image

6. 문서 객체 이동하기

  • setTimeout(function, delay)

      <!-- index.html -->
      <body>
          <div class="first">
              <h1>첫 번째 div tag 내부</h1>
          </div>
          <hr>
          <div class="second">
              <h1>두 번째 div tag 내부</h1>
          </div>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 만들기
          const header = document.createElement('h2');
          header.textContent = '추가된 h2 tag입니다';
    
          const first = document.querySelector('.first');
          const second = document.querySelector('.second');
              // element 붙이기
          first.appendChild(header); 
            
          const toFirst = () => {
              first.appendChild(header);
              setTimeout(toSecond, 1000); // 1초 뒤에 toSecond() 실행
          }
            
          const toSecond = () => {
              second.appendChild(header);
              setTimeout(toFirst, 1000); // 1초 뒤에 toFirst() 실행
          }
          toFirst(); 
      });
    
  • 1초마다 두 화면이 번갈아가며 나타남 image

    image

  • 또는 다음과 같은 방법으로 실행할 수도 있음

    • array에 element를 넣음
    • setInterval()
      <!-- index.html -->
      <body>
          <div class="first">
              <h1>첫 번째 div tag 내부</h1>
          </div>
          <hr>
          <div class="second">
              <h1>두 번째 div tag 내부</h1>
          </div>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 만들기
          const header = document.createElement('h2');
          header.textContent = '추가된 h2 tag입니다';
                
          const array = [
              document.querySelector('.first'), 
              document.querySelector('.second')
          ];
    
          let counter = 0;
          const move = () => {
              array[counter % 2].appendChild(header);
              counter ++;
          };
    
          setInterval(move, 1000);
          move(); // 1초 뒤부터 h2 tag가 나타나므로 처음 한 번은 실행해 줌
      });
    

7. event 연결

  • addEventLister('이벤트_이름', 이벤트 리스너(이벤트 핸들러))
    • 이벤트가 실행될 때 호출되는 callBack fn이벤트 리스너 또는 이벤트 핸들러라고 부름
    • 문서 객체에서 on으로 시작하는 속성들을 이벤트와 관련되므로 적절한 항목을 골라 사용자에 반응하는 프로그램을 만들 수 있음 e.g.) onmousedown, onmouseenter, onmouseleave
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 생성
          const header = document.createElement('h1'); 
          header.textContent = 'Click = 0'
          header.style.color = 'salmon';
          header.style.border = '1px solid salmon';
          header.style.userSelect = 'none'; // 연속 click시 text가 선택되지 않도록 설정	  
    
          // element 붙이기 
          // body 태그 내부에 붙이기
          document.body.appendChild(header); 
            
          let count = 0; // 변수 설정
            
          // h1 태그를 click할 때마다 이벤트를 발생시킴
          header.addEventListener('click', () => {
              count ++;
              header.textContent = `Click = ${count}`;
          });
      });
    
    • h1 태그를 click할 때마다 숫자가 하나씩 증가함 image image

8. 이벤트 제거

  • removeEventLister()
    • click연결 시 사용했던 eventLister를 별도의 변수(여기서는 listener)에 담아 주어야 함
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      let count = 0;
    
      const listener = () => {
          header.textContent = `클릭 횟수 = ${++count}`;
      }
    
      // element 생성(h1)
      const header = document.createElement('h1');
      header.style.border = '1px solid black';
      header.style.userSelect = 'none'; // click시 text가 선택되지 않도록 설정
      header.textContent = '클릭 횟수 = 0';
    
      // element 생성(p)
      const p = document.createElement('p');
      p.textContent = '이벤트 연결 상태: 해제';
      p.style.userSelect = 'none'; // click시 text가 선택되지 않도록 설정
    
      // element 생성(button)
      const connectButton = document.createElement('button');
      connectButton.textContent = '이벤트 연결';
      connectButton.addEventListener('click', () => {
          header.addEventListener('click', listener)
          p.textContent = '이벤트 연결 상태: 연결'; 
      });
    
      // element 생성(button)
      const disconnectButton = document.createElement('button');
      disconnectButton.textContent = '이벤트 제거';
      disconnectButton.addEventListener('click', () => {
          header.removeEventListener('click', listener)
          p.textContent = '이벤트 연결 상태: 해제';
      });
    
      // 화면에 element 추가(순서대로)
      document.body.appendChild(header);
      document.body.appendChild(connectButton);
      document.body.appendChild(disconnectButton);
      document.body.appendChild(p);
    

    이벤트 연결 버튼을 클릭하면,

    1. 이벤트 연결 상태가 ON 로 바뀌면서
    2. header 클릭시 클릭 횟수가 증가

    이벤트 제거 버튼을 클릭하면,

    1. 이벤트 연결 상태가 OFF로 바뀌면서
    2. header 클릭시 클릭 횟수가 증가하지 않음

    image image

9. 키보드 이벤트

  • event가 발생했을 때, 해당 event와 관련된 정보가 이벤트 객체 형태로 callback fn의 첫 번째 parameter로 가져옴
      document.addEventListener('이벤트', (이벤트 객체) => {
        
      });
    
    • 일반적으로 이 parameter의 이름은 event 또는 e 로 설정함
      • e.code: 입력한 키
      • e.keyCode: 입력한 키를 나타내는 숫자
      • e.altKey: Alt 키를 눌렀는지
      • e.ctrlKey: Ctrl 키 를 눌렀는지
      • e.shiftKey: Shift 키를 눌렀는지
      • e.currentTarget: event를 발생시킨 객체
  • currentTarget, this 를 사용한 코드 숙지하기

      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 생성(h1)
          const header = document.createElement('h1');
          header.textContent = '글자 수 = 0';
          header.style.color = 'salmon';
          header.style.border = '1px solid salmon';
    		
          // element 생성(textarea)
          const textarea = document.createElement('textarea');
          textarea.placeholder = '글자를 입력하세요';
    
          // 화면에 element 추가
          document.body.appendChild(header);
          document.body.appendChild(textarea);
    
          // 첫 번째 방법
          textarea.addEventListener('keyup', (e) => {
              h1.textContent = `글자 수: ${textarea.value.length}`;
          });
    
          // 두 번째 방법
          // currentTarget 사용
          textarea.addEventListener('keyup', (e) => {
              h1.textContent = `글자 수: ${e.currentTarget.value.length}`;
          });
    
          // 세 번째 방법
          // function을 만들어 this를 사용
          textarea.addEventListener('keyup', function () {
              h1.textContent = `글자 수: ${this.value.length}`;
          });
      });
    
    • 글을 입력하면 글자 수를 알려줌 image

    • console.log(e.currentTarget)를 보면, 이벤트를 발생시킨 객체가 나옴 image

    • 첫 번째 방법
      • keyup
      • keydown인 상태에서는 입력한 글자 수를 알 수 없음
    • 두 번째 방법
      • keypress
      • 아시아 문자에서는 제대로 작동하지 않는 경우가 있음
    • 세 번째 방법
      • this 사용
      • eventHandler내부에서 this가 이벤트 발생 객체를 의미함

10. 기본 이벤트 막기

  • preventDefault()
    • 기본 이벤트를 막음
  • a 태그
    • 기본 이벤트: 클릭하면 지정된 주소로 이동
    • click 이벤트에 preventDefault() 를 설정하면 지정 주소로 이동하지 않음
  • 요소에서 우클릭
    • 기본 이벤트: context menu가 나옴
    • contextmenu 이벤트에 preventDefault() 를 설정하면 context menu가 나오지 않음
    • 블로그의 우클릭 방지기능
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 생성(a 태그)
          const link = document.createElement('a');
          link.textContent = 'Google';
          link.href = 'https://www.google.com';
    		
          // element 추가
          document.body.appendChild(link);
    
          // a 태그 click시 링크가 연결되는 것 막기
          link.addEventListener('click', (event) => {
              event.preventDefault();
          });
        
          // a 태그 우click시 context menu가 나오는 것 막기
          link.addEventListener('contextmenu', (event) => {
              event.preventDefault();
          });
      });
    
    • preventDefault() 적용 전 image
    • preventDefault() 적용 후 image

11. 입력 양식(1) - Button

  • 세 가지 형태가 존재
      // 1.
      <button>글자</button>
        
      // 2.
      <input type="button" value="글자">
        
      // 3.
      <form action="">
          <input type="submit" value="글자">
      </form>
    
    • 첫 번째와 두 번째는 click 이벤트 활용시에 사용
    • 세 번째는 submit 이벤트 활용시에 사용

11-(1) click 이벤트 사용하기

  • event.currentTarget: 이벤트를 발생시킨 객체
      <!-- index.html -->
      <body>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
              // element 선택(button)
          const firstButton = document.querySelector('button');
          const secondButton = document.querySelector('input[type=button]');
    
          // button 클릭시 event 지정
          firstButton.addEventListener('click', (event) => {
              event.currentTarget.textContent += '😎'; 
          });
          secondButton.addEventListener('click', (event) => {
              event.currentTarget.value += '🌈'; 
          });
      });
    
    • button을 클릭할 때마다 버튼의 내용이 바뀜 image image

11-(2) click 이벤트 사용하기

  • form 태그의 button을 클릭하면,
  • 태그 안의 데이터를 서버로 넘김
    ⇒ 주소가 바뀜
  • submit 이벤트는 form 태그를 선택해(document.querySelector('form')) 이벤트를 연결해야 함!
  • form 태그 내부에 있는 button은 submit 태그와 동일하게 동작하므로 주의!
  • form 태그 내부에 input[type=button] button을 만들어야 submit 이벤트가 일어나지 않음

      <!-- index.html -->
      <body>
          <form action="">
              이메일 형식으로 입력하세요!<br>
              <!-- name 값을 반드시 입력해야 함 -->
              <input type="text" name="test" id="">
              <input type="submit" value="글자">
          </form>
          <script src="main.js"></script>
      </body> 
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 선택(form)
          const form = document.querySelector('form');
        
          // (주의!) form 태그를 선택해 submit 이벤트를 관리함
          form.addEventListener('submit', (event) => {
              const text = document.querySelector('input[type=text]');
    			  
              // indexOf()로 '@'가 있는지 확인
              if (text.value.indexOf('@') >= 0) {
                  alert('정상 제출합니다!');
              } else {
                  alert('이메일 형식으로 입력해주세요!');
            
                  // 이메일 형식이 아닐경우 기본 submit 이벤트를 막음
                  event.preventDefault();
              }
          });
      });
    
    • @ 가 포함되어있지 않으면 주소 변경이 일어나지 않음 image
    • 정상제출을 하면, 주소가 바뀜 image image

12. 입력 양식(2) - 글자 입력

  • <input type="text">
    • 한 줄의 글자 입력
  • <textarea></textarea>
    • 여러 줄의 글자 입력
  • contenteditable="true"
    • 해당 태그의 내용을 직접 수정가능하게 만들어줌

        <p contenteditable="true">contenteditable!</p>
      

      image

(참고) keydown, keypress, keyup, change 이벤트

  • 키 이벤트와 입력 순서
    • keydownkeypress → ★입력양식에 값이 들어감★→ keyup
    • keydown 이나, keypress 이벤트를 주면,
      입력 양식에 값이 들어가는 것이 시간상 더 이후이므로 코드 실행시 변환이 일어나지 않은 결과를 보여줌

        button.addEventListener('keydown', () => {
                p.textContent = `${Number(input.value) * 2.54}cm`;
        });
      
      • keydown시점에 이벤트가 실행되므로 입력 양식에 값이 들어가기 전이라 p태그에 값이 없음 image
    • 참고로 change 이벤트의 경우, 값 입력을 마쳤다는 선언(enter 키 입력)이 있어야 함

<예제> 입력받은 cm 단위를 inch로 변환하기

<!-- index.html -->
<body>
    <input type="text" name="inch" id="" placeholder="숫자"> inch <br>
    <p id="result">숫자를 입력해주세요</p>
    <script src="main.js"></script>
</body>
// main.js
document.addEventListener('DOMContentLoaded', () => {
    // element 선택
    const input = document.querySelector('input[name=inch]');
    const p = document.querySelector('#result');

    // 입력한 값을 숫자로 변경해 inch 단위로 변경
    button.addEventListener('click', () => {
        p.textContent = `${Number(input.value) * 2.54}cm`;
    });
});

image image

  • <textarea></textarea> 를 사용했을 때도 마찬가지로 value 속성으로 text를 추출하면 됨

13. 입력 양식(3) - 체크박스/라디오버튼

  • 체크 박스
    • true 또는 false 가 선택됨
  • 라디오 버튼
    • name 속성 지정 필수
    • 같은 name 속성을 갖는 그룹으로 묶임

<예제> checkbox, radio button 선택시 해당 내용 출력하기

  • forEach()
    • 라디오 버튼이 여러 개 이므로 각각 돌면서 addEventListener()를 실행
      <!-- index.html -->
      <body>
          <!-- true 또는 false를 선택 -->
          <input type="checkbox" name="" id="">
          <p id="checkValue"></p>
    
          <!-- 여러 대상 중 하나만 선택 -->
          <input type="radio" name="food" value="아이스크림">🍦
          <input type="radio" name="food" value="치킨">🍗
          <input type="radio" name="food" value="도넛">🍩
          <p id="radioValue"></p>    
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 선택
          const checkBox = document.querySelector("input[type=checkbox]");
          // 라디오 버튼 모두 선택
          const radios = document.querySelectorAll("input[type=radio][name=food]"); 
          const checkValue = document.querySelector("p#checkValue");
          const radioValue = document.querySelector("p#radioValue");
    	
          // 체크박스가 체크되면 이벤트 실행
          checkBox.addEventListener("change", () => {
              if (checkBox.checked) {
                  checkValue.textContent = "체크!";
              } else {
                  checkValue.textContent = "안 체크!";
              }
          });
    	
          // 라디오버튼이 선택되면 이벤트 실행
          // forEach문으로 각 radio버튼 돎
          radios.forEach((radio) => {
              radio.addEventListener('change', (event) => {
                  radioValue.textContent = event.currentTarget.value;
              })
          })
      });
    

    image image

<예제> checkbox 선택시 배경색 바뀌면서, 타이머 작동시키기

  • 구조 분해 할당(destructuring assignment)
    • 객체나 배열을 변수로 분해할 수 있게 해주는 특별한 문법
    • 참고 예시
  • setInterval()clearInterval()
      <!-- index.html -->
      <body>
          <input type="checkbox" name="" id=""> 타이머 ON
          <p id="timer">0초</p>
          <script src="main.js"></script>
      </body>
    
      // main.js
      document.addEventListener('DOMContentLoaded', () => {
          // element 선택
          const checkBox = document.querySelector("input[type=checkbox]");
          const timer = document.querySelector("p#timer");
    
          let [seconds, timerId] = [0, 0]; // 구조분해 할당
    
          // 체크박스가 체크되면 이벤트 실행
          checkBox.addEventListener("change", () => {
              if (checkBox.checked) {
                  document.body.style.backgroundColor = 'pink';
                  timerId = setInterval(() => {
                      seconds += 1;
                      timer.textContent = `${seconds}초`;
                  }, 1000)
              } else {
                  document.body.style.backgroundColor = 'white';
                  clearInterval(timerId);
              }
          });
      });
    

    image image

< 출처 >

“혼공 자바스크립트 40~46강,” 게시자 “윤인성,” https://www.youtube.com/playlist?list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl