프론트엔드/Javascript 연습과제 해답

자바스크립트 문법 4 - 이벤트 (Event) 처리하기 2 해답

syleemomo 2022. 1. 15. 11:43
728x90

 

* 연습과제 1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="color-box"></div>
    <input id="color-input" type="text" placeholder="give color name ..."/>

    <script src='app.js'></script>
</body>
</html>
body{
    margin: 0;
    padding: 0;
    background: #0e1111;
}

.color-box{
    background-color: #0e1111;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100vh;
}
#color-input{
    all: unset;
    width: 300px;
    height: 50px;
    border: 2px solid lightgreen;
    padding: 10px;
    border-radius: 15px;
    color: lightgreen;
    font-size: 1.2rem;
    font-weight: bold;

    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}
#color-input::placeholder{
    color: lightgreen;
}
const colorBox = document.querySelector('.color-box')
const colorInput = document.getElementById('color-input')
console.log(colorInput)

function pickRandomColor(){
    return Math.floor(Math.random()*256)
}

function setColor(e){
    console.log(e.target.value)

    colorBox.style.backgroundColor = `rgb(${pickRandomColor()}, ${pickRandomColor()}, ${pickRandomColor()})`
}

colorInput.addEventListener('input', setColor)

 

* 연습과제 2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <input id="file-input" type="file">
    <button id='upload'>이미지 업로드</button>
    <div id='img-box'></div>

    <script src='app.js'></script>
</body>
</html>
body{
    margin: 0;
    padding: 0;
}
#file-input{
    display: none;
}
#img-box{
    width: 200px;
    height: 250px;
    overflow: hidden;

    position: absolute;
    left: 50%;
    top: 200px;
    transform: translate(-50%);
}
#img-box img{
    width: 100%;
    height: 100%;
}
#upload{
    position: absolute;
    left: 50%;
    top: 100px;
    transform: translate(-50%);
}
const fileInput = document.getElementById('file-input')
const imgBox = document.getElementById('img-box')
const uploadBtn = document.getElementById('upload')

function isValid(type){
    return type.split('/')[0] === 'image'
}

function displayImg(e){
    console.log(e.target.files)
    const file = e.target.files[0]

    if(!isValid(file.type)){
        imgBox.innerHTML = 'File type is not valid !'
        return;
    }

    const img = document.createElement('img')
    img.src = URL.createObjectURL(file)
    imgBox.appendChild(img)
    
}

function openFileWindow(){
    fileInput.click()
}

fileInput.addEventListener('change', displayImg)
uploadBtn.addEventListener('click', openFileWindow)

 

* 연습과제 3

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <label>사진업로드<input id="file-input" type="file" multiple></label>
    <div id='img-box'></div>

    <script src='app.js'></script>
</body>
</html>
body{
  margin: 0; padding: 0;
  box-sizing: border-box;

  display: flex;
  justify-content: center;
}
label{
  border: 2px solid goldenrod;
  padding: 1rem 2rem;
  cursor: pointer;
  color: goldenrod;

  position: fixed;
  right: 2rem; bottom: 2rem;
  z-index: 1;
}
label:hover{
  background-color: goldenrod;
  color: #fff;
}
#file-input{
  display: none;
}
#img-box{
  /* border: 1px solid red; */
  margin-top: 3rem;
  width: 80%;

  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 1rem;
}
#img-box img{
  height: 300px;
}
const fileInput = document.getElementById('file-input')
const imgBox = document.getElementById('img-box')

function isValid(type){
  return type.split('/')[0] === "image" // "image/jpg" => ["image", "jpg"]
}

function displayImg(e){
  console.log(e.target.files) // 사용자가 업로드한 파일 배열 
  const files = e.target.files

  if(files.length > 0){
    for(let file of files){
      if(!isValid(file.type)){
        continue;
      } // 파일 타입 검증
    
      const img = document.createElement('img') // 이미지 태그 동적으로 생성
      img.src = URL.createObjectURL(file) // 업로드한 파일의 임시경로 (이미지 경로)
      imgBox.appendChild(img) // 이미지 보여주기 
    }
  }
}

fileInput.addEventListener('change', displayImg)

 

* 연습과제 4

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id='auto-complete'>
        <input id="color-input" type="text" placeholder="give color name ..."/>
        <div class='color-list'></div>
    </div>
    <div class="color-box"></div>

    <script src='app.js'></script>
</body>
</html>
body{
  margin: 0;
  padding: 0;
  background: #0e1111;
}

#auto-complete{
  position: absolute;
  left: 50%;
  top: 100px;
  transform: translate(-50%);
}

#color-input{
  all: unset;
  width: 300px;
  height: 50px;
  border: 2px solid lightgreen;
  padding: 10px;
  border-radius: 15px;
  color: lightgreen;
  font-size: 1.2rem;
  font-weight: bold;
  box-sizing: border-box;
  position: relative;
}
#color-input::placeholder{
  color: lightgreen;
}
.color-list{
  width: 300px;
  margin-top: 10px;
  display: none;
  position: absolute;
}
.show{
  display: block;
}
.color-item{
  width: 100%;
  height: 50px;
  border: 1px solid #a9a9a9;
  color: lightgreen;
  line-height: 50px;
  text-align: center;
  font-weight: bold;
  cursor: pointer;
}
.color-item:hover{
  background-color: lightgreen;
  color: white;
}
.highlight{
  background-color: lightgreen;
  color: white;
}

.color-box{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  z-index: -1;
}
const colorBox = document.querySelector('.color-box')
const colorList = document.querySelector('.color-list')
const colorInput = document.getElementById('color-input')

const colors = ['orange', 'blue', 'brown', 'green', 'red', 'skyblue'] // 색상배열

let index = -1 // 사용자가 화살표키로 선택한 현재 색상에 대한 인덱스 값 
let prevIndex = -1 // 사용자가 화살표키로 선택한 직전 색상에 대한 인덱스 값 

function addColors(colors){
    for(let color of colors){
        const item = `<div class='color-item'>${color}</div>` // 색상 엘리먼트 
        colorList.innerHTML += item // 컨테이너에 색상 엘리먼트 추가하기
    }
}

function changeHighLightItem(key){
  prevIndex = index // 현재 사용자가 선택한 색상에 대한 인덱스값 저장하기 

  if(key === 40){ // 아래쪽 화살표키를 누른 경우 색상 인덱스 값 증가 
      index++
      if(index > colors.length -1){ // 인덱스 값이 색상 배열의 마지막 인덱스를 벗어난 경우 다시 첫번째 색상을 선택하도록 0 으로 초기화
          index = 0
      }
  }else if(key === 38){ // 위쪽 화살표키를 누른 경우 색상 인덱스 값 감소
      index--
      if(index < 0){ // 인덱스값이 0 보다 작은 경우 다시 마지막 색상을 선택하도록 색상 배열의 마지막 인덱스값으로 설정 
          index = colors.length -1
      }
  }else if(key === 13){ // 엔터키를 누른 경우 사용자가 화살표키로 선택한 현재 색상을 화면의 배경색으로 설정
    const colorItem = document.querySelectorAll('.color-item')[index]
    setBackground(colorItem.innerText) 
  }

  console.log('직전에 선택한 색상', prevIndex)
  console.log('현재 선택한 색상', index)
}

function unsetHightLightItem(colorIndex){
  if(colorIndex >= 0 && colorIndex < colors.length){ // colorIndex 의 유효범위가 색상배열의 인덱스 값인 경우 
      const colorItem = document.querySelectorAll('.color-item')[colorIndex]
      colorItem.classList.remove('highlight') // 해당 색상 엘리먼트에 대한 하이라이트 해제 
  }
}

function highLightColorItem(colorIndex){
  if(colorIndex >= 0 && colorIndex < colors.length){
      const colorItem = document.querySelectorAll('.color-item')[colorIndex]
      colorItem.classList.add('highlight') // 해당 색상 엘리먼트에 대한 하이라이트 적용
  }
}

function selectColor(e){ // 사용자가 화살표키로 색상을 선택할때 하이라이트 적용하기 
  console.log(e.keyCode) // 키보드 키에 대한 ID 값 

  if(e.keyCode){
      changeHighLightItem(e.keyCode) // 사용자가 선택한 색상에 대한 인덱스 값 변경
      unsetHightLightItem(prevIndex) // 사용자가 직전에 선택한 색상에 적용된 하이라이트 제거
      highLightColorItem(index) // 사용자가 현재 선택한 색상에 대한 하이라이트 적용
  }
}

function typeColor(e){
  console.log(e.target.value)

  if(e.target.value !== ''){
      console.log('you typed something')
      colorList.classList.add('show') // 색상목록 보여주기
      colorInput.addEventListener('keyup', selectColor) // 화살표키로 색상목록을 선택하기 위한 키 이벤트 등록하기
  }else{
      console.log('you didn\'t type anything')
      colorList.classList.remove('show') // 색상목록 감추기
      colorInput.removeEventListener('keyup', selectColor) // 화살표키로 색상목록을 선택하지 못하도록 키 이벤트 해제하기
  }
}

function initHighlight(){
  unsetHightLightItem(index) // 현재 인덱스 값에 대한 하이라이트 해제
  index = -1 // 인덱스 값 초기화 
  prevIndex = -1
}

function setBackground(color){
  console.log('you picked color !', color)
  colorInput.value = color // 사용자가 선택한 색상을 입력창에 보여주기 
  colorList.classList.remove('show') // 색상 목록 감추기 
  colorBox.style.background = color // 사용자가 선택한 색상으로 화면 배경색 변경하기 
  initHighlight() // 하이라이트 초기화 
  colorInput.removeEventListener('keyup', selectColor) // 색상목록이 안보일때는 화살표키로 색상을 선택하지 못하도록 키 이벤트 해제하기 
}

function setColor(e){
  console.log(e.target)

  if(e.target.className === 'color-item'){
      const pickedColor = e.target.innerText // 사용자가 마우스로 선택한 색상 문자열
      setBackground(pickedColor) // 배경색 변경
  }
}

addColors(colors) // 화면에 색상 목록 기보여주기
colorInput.addEventListener('input', typeColor) // 사용자가 색상을 입력할때 적용할 이벤트
colorList.addEventListener('click', setColor) // 사용자가 색상목록에서 특정 색상을 마우스로 선택할때 적용할 이벤트
colorList.addEventListener('mouseenter', initHighlight)

colorList 요소에 mouseenter 이벤트를 등록하고 그때 initHighlight 함수를 이용하여 키 이벤트로 선택한 하이라이트를 초기화한다.

 

* 연습과제 5

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="window">
    <div class="expand">
      <span class="material-icons exp">
        aspect_ratio
      </span>
      <span class="material-icons shrink">
        unfold_less
      </span>
    </div>

    <div class="container">
      <div class="box" id="1"></div>
      <div class="box" id="2"></div>
      <div class="box" id="3"></div>
      <div class="box" id="4"></div>
      <div class="box" id="5"></div>
      <div class="box" id="6"></div>
      <div class="box" id="7"></div>
    </div>
  </div>
  <div class="actions">
    <button class="prev">prev</button>
    <button class="next">next</button>
  </div>

  <script src='app.js'></script>
</body>
</html>
*{
  box-sizing: border-box;
}
body{
  width: 100%; height: 100vh;
  background-color: #0e1111;

  display: flex;  
  flex-flow: column;
  justify-content: center;
  align-items: center;
  margin: 0; padding: 0;
}
.window{
  /* border: 1px solid red; */
  width: 50vw;
  height: 500px;
  margin-bottom: 2rem;
  overflow: hidden;
  position: relative;
  transition: .5s  ease-in-out; /* 중앙에서 확대하기 */
}
.window .container{
  width: calc(50vw * 7);
  /* border: 1px solid green; */
  height: 100%;

  display: flex;
  margin-left: -50vw; /* 두번째 사진부터 시작 */
  transition: .5s  ease-in-out;
}
.window .container .box{
  width: 100%;
  height: 100%;
  background-size: cover;
}
.window .container .box:nth-child(1){
  background: url('https://www.institutostrom.org/wp-content/uploads/2018/04/NZ.jpg') no-repeat center;
}
.window .container .box:nth-child(2) {
  background: url("https://icepipeled.com/wp-content/uploads/2020/03/1.-ICEPIPE_2020_4_PC_bg.png") no-repeat center;
}
.window .container .box:nth-child(3) {
  background: url("https://digitalassets-retail.cdn-apple.com/retail-image-server/a90/c85/1bd/c2d/1af/8ba/a2a/349/93e/fe2/11b8d32a-7f9f-372c-bca3-0a05d871e8c7_iMac_Wallpaper_4480x2520.jpg") no-repeat center;
}
.window .container .box:nth-child(4) {
  background: url("http://file.instiz.net/data/file/20121125/5/6/0/5609249762358c2bcb65a46580549c99") no-repeat center;
}
.window .container .box:nth-child(5) {
  background: url("https://s1.pearlcdn.com/KR/Upload/Community/434174d044320230412231123488.jpg") no-repeat center;
}
.window .container .box:nth-child(6){
  background: url('https://www.institutostrom.org/wp-content/uploads/2018/04/NZ.jpg') no-repeat center;
}
.window .container .box:nth-child(7) {
  background: url("https://icepipeled.com/wp-content/uploads/2020/03/1.-ICEPIPE_2020_4_PC_bg.png") no-repeat center;
}

.actions button{
  border: 2px solid wheat;
  background: none;
  color: wheat;
  padding: 1rem 2rem;
  margin-right: 1rem;
  font-size: 1.5rem;
  cursor: pointer
}
.actions button:hover{
  transform: scale(1.02);
  border: 2px solid wheat;
  background-color: wheat;
  color: #0e1111;
}

.expand span{
  color: wheat;
  font-size: 2rem;
  position: absolute;
  right: 1rem; top: 1rem;
  cursor: pointer;
  user-select: none;
  transition: .2s;
  z-index: 1; 
}
.expand span:hover{
  transform: scale(1.05);
}
.expand .shrink{
  display: none;
  transform: rotate(45deg);
}

.window.expandWindow{
  width: 100vw;
  height: 100vh;
  margin-bottom: 0;
}
.container.expandContainer{
  width: calc(100vw * 7);
  height: 100%;
  margin-left: -100vw; /* 두번째 사진부터 시작 */
}
.window.container.box.expandBox{
  height: 100vh;
}
.hide{
  display: none;
}
.shrink.show{
  display: block;
}
/* 문제점 : 클릭을 빠르게 하면 이상하게 동작함 */
/* 쓰로틀링과 디바운싱 적용해서 막아야 할듯 */
/* 첫번째 사진이나 마지막 사진으로 이동하고 100ms 후에 트랜지션 적용하므로 그사이 클릭하면 트랜지션이 먹히지 않음 */
/* 그렇다고 트랜지션을 곧바로 다시 살리면 첫번째 사진이나 마지막 사진으로 이동하면서 트랜지션이 적용되서 이동하는게 보임 */
/* 쓰로틀링 참고자료 : https://www.zerocho.com/category/JavaScript/post/59a8e9cb15ac0000182794fa */

const frame = document.querySelector('.window')
const container = document.querySelector('.container')
const boxes = container.querySelectorAll('.box')
const prev = document.querySelector('.prev')
const next = document.querySelector('.next')
const expandBtn = document.querySelector('.expand')
const exp = expandBtn.querySelector('.exp')
const shrink = expandBtn.querySelector('.shrink')
const unit = 'vw', duration = 500 // ms
let widthOfPhoto = 50
let index = 1
let timer, throttleDuration = 1000 // 쓰로틀링을 위한 타이머 설정 (1s 이상으로 설정하기 )
let isDown, startX, walk, walk2vw, isOver

// 시작점 또는 끝점으로 이동하는 함수
function slideToEnd(container, index, widthOfPhoto, unit, duration){
  let timerOutside = setTimeout(function(){ // 마지막 사진 이동 끝남
    container.style.transition = 'none'
    container.style.opacity = '0' // 마지막 사진 가림
    container.style.marginLeft = -1 * index  * widthOfPhoto + unit // 첫번째 사진으로 이동
    container.style.opacity = '1' // 첫번째 사진 보여줌
    
    let timerInside = setTimeout(function(){ // 트랜지션은 나중에 다시 설정하기
      container.style.transition = `${duration}ms  ease-in-out`
      clearTimeout(timerOutside)
      clearTimeout(timerInside)
      console.log('타이머 해제')
    }, 100)
  }, duration)
}

function moveToRight(e){
  index--
  container.style.marginLeft = -1 * index * widthOfPhoto + unit

  if(index === 0){ // 첫번째 사진(마지막사진 복사본) 이동시작 
    index = 5
    slideToEnd(container, index, widthOfPhoto, unit, duration)
  }
}
function moveToLeft(e){
  index++
  container.style.marginLeft = -1 * index  * widthOfPhoto + unit

  if(index === 6){ // 마지막 사진(첫번째사진 복사본) 이동시작 
    index = 1
    slideToEnd(container, index, widthOfPhoto, unit, duration)
  }
}
function throttling(handler){
  if(!timer){
    timer = setTimeout(function(){
      console.log('실행')
      handler()
      timer = null 
    }, throttleDuration)
  }
}

function px2vw(px){  
  return px * 100 / document.documentElement.clientWidth
}

function handleMouseDown(e){
  console.log('down')
  isDown = true 
  startX = e.pageX 
}
function handleMouseUp(){
  console.log('up', isOver)
  isDown = false 

  if(isOver){ // 드래그한 거리가 슬라이드 너비의 절반 이하인 경우
    console.log('못넘음')
    container.style.marginLeft = -1 * index * widthOfPhoto + unit  // 드래그하기전 원래 위치로 되돌아가기 
    isOver = false
  }
}
function handleMouseLeave(){
  console.log('leave')
  isDown = false 
}
function handleMouseMove(e){
  if(!isDown) return 
  console.log('move')

  walk = e.pageX - startX 
  walk2vw = px2vw(Math.abs(walk))
  console.log(walk, walk2vw)

  if(walk < 0){ // 왼쪽 방향으로 드래그한 경우
    if(walk2vw < widthOfPhoto / 2){ // 드래그한 거리가 슬라이드 절반에 못미치는 경우
      console.log('다음사진')
      container.style.marginLeft = `${-1 * index  * widthOfPhoto - walk2vw}vw` // 현재 위치에서 드래그한 거리만큼 왼쪽으로 더 이동
      isOver = true // 절반을 넘지 못한 경우 플래그 ON
    }else{
      throttling(moveToLeft) // 다음사진 보여주기
      isOver = false // 절반을 넘은 경우 플래그 OFF
    }
  }else{ // 오른쪽 방향으로 드래그한 경우
    if(walk2vw < widthOfPhoto / 2){ // 드래그한 거리가 슬라이드 절반에 못미치는 경우
      console.log('이전사진')
      container.style.marginLeft = `${-1 * index  * widthOfPhoto + walk2vw}vw` // 현재 위치에서 드래그한 거리만큼 오른쪽으로 더 이동
      isOver = true // 절반을 넘지 못한 경우 플래그 ON
    }else{
      throttling(moveToRight) // 이전사진 보여주기
      isOver = false // 절반을 넘은 경우 플래그 OFF
    }
  }
}

function expandSlider(e){
  if(e.target.innerText === 'aspect_ratio'){
    console.log('확장')
    console.log(e.target.innerText)
    frame.classList.add('expandWindow')
    container.classList.add('expandContainer')
    prev.classList.add('hide')
    next.classList.add('hide')
    exp.classList.add('hide')
    shrink.classList.add('show')
    for(let box of boxes){
      box.classList.add('expandBox')
    }
    widthOfPhoto = 100
    container.style.marginLeft = -1 * index * widthOfPhoto + unit // 확대시 변경된 슬라이드 너비로 marginLeft 새로 계산하기
  }else if(e.target.innerText === 'unfold_less'){
    console.log('축소')
    frame.classList.remove('expandWindow')
    container.classList.remove('expandContainer')
    prev.classList.remove('hide')
    next.classList.remove('hide')
    exp.classList.remove('hide')
    shrink.classList.remove('show')
    for(let box of boxes){
      box.classList.remove('expandBox')
    }
    widthOfPhoto = 50
    container.style.marginLeft = -1 * index * widthOfPhoto + unit // 축소시 변경된 슬라이드 너비로 marginLeft 새로 계산하기
  }
}

function handleKeyUp(e){
    console.log(e.key)
    if(e.key === "Escape" || e.key === 'e'){
      expandBtn.click()
    }
}

prev.addEventListener('click', () => throttling(moveToRight))
next.addEventListener('click', () => throttling(moveToLeft))

container.addEventListener('mousedown', handleMouseDown)
container.addEventListener('mousemove', handleMouseMove)
container.addEventListener('mouseup', handleMouseUp)
container.addEventListener('mouseleave', handleMouseLeave)

expandBtn.addEventListener('click', expandSlider)
window.addEventListener('keyup', handleKeyUp)

Esc, e 키를 누르면 확장, 축소 버튼을 동적으로 클릭하도록 구현하였다. 

 

* 연습과제 6

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
  <input type="text" placeholder="비밀번호를 입력해주세요!">
  <button>로그인</button>

  <script src='app.js'></script>
</body>
</html>
const specialChars = "~!@#$%^&*_-+=`|\(){}[]:;\"'<>,.?/"
const numbers = '1234567890'

const input = document.querySelector('input')
const button = document.querySelector('button')

function login(e){
  console.log(input.value)
  const flags = {'sc': false, 'number': false}

  outer: for(let char of input.value){
    if(!flags['sc']){
      for(let sc of specialChars){
        if(char === sc){
          flags['sc'] = true 
          continue outer; 
        }
      }
    }
    if(!flags['number']){
      for(let n of numbers){
        if(char === n){
          flags['number'] = true 
          continue outer;
        }
      }
    }
  }
  
  if(flags['sc'] && flags['number']){
    console.log('비밀번호 조건을 만족합니다.')
  }else{
    alert('비밀번호가 안전하지 않습니다.')
  }
}

button.addEventListener('click', login)

기본적인 알고리즘은 아래와 같다. 

1. 로그인 버튼을 클릭할때마다 플래그를 초기화한다. 
2. 사용자가 입력한 비밀번호의 글자마다 특수문자, 숫자, 영문자를 검사한다. 
3. 플래그값이 참인 경우(특수문자, 숫자, 영문자를 이미 찾은 경우)는 더이상 검사하지 않는다. 
4. 특수문자, 숫자, 영문자를 찾은 경우에는 플래그값을 참으로 변경하고, 
다음 글자를 검사하기 위하여 continue [label] 로 다음 이터레이션을 실행한다.
5. 플래그값이 모두 참인 경우에만 비밀번호 조건을 만족한다고 판단한다.

 

* 연습과제 7

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>자바스크립트 연습</title>
    <link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
  <input type="text" placeholder="비밀번호를 입력해주세요!">
  <button>로그인</button>
  
  <div class="progress">
    <div class="progress-bar"></div>
  </div>

  <script src='app.js'></script>
</body>
</html>
.progress{
  width: 600px;
  height: 50px;
  border: 2px solid #0e1111;
  margin: 2rem;
}
.progress-bar{
  width: 0;
  height: 100%;
}
const specialChars = "~!@#$%^&*_-+=`|\(){}[]:;\"'<>,.?/"
const numbers = '1234567890'
const alphabetsLower = 'abcdefghijklmnopqrstuvwxyz'
const alphabetsUpper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

const input = document.querySelector('input')
const button = document.querySelector('button')
const progressbar = document.querySelector('.progress-bar')

function login(e){
  console.log(input.value)
  const flags = {'sc': false, 'number': false, 'al': false, 'au': false}

  outer: for(let char of input.value){
    if(!flags['sc']){
      for(let sc of specialChars){
        if(char === sc){
          flags['sc'] = true 
          continue outer; 
        }
      }
    }
    if(!flags['number']){
      for(let n of numbers){
        if(char === n){
          flags['number'] = true 
          continue outer;
        }
      }
    }
    if(!flags['al']){
      for(let en of alphabetsLower){
        if(char === en){
          flags['al'] = true 
          continue outer;
        }
      }
    }
    if(!flags['au']){
      for(let en of alphabetsUpper){
        if(char === en){
          flags['au'] = true 
          continue outer;
        }
      }
    }
  }
  
  if(flags['sc'] && flags['number'] && flags['al'] && flags['au']){
    console.log('비밀번호 조건을 만족합니다.')
  }else{
    alert('비밀번호가 안전하지 않습니다.')
  }
  
  let count = 0
  for(let key in flags){
    if(flags[key]) count++
  }
  if(count === 1){
    progressbar.style.width = '200px'
    progressbar.style.backgroundColor = 'red'
  }else if(count === 2 || count === 3){
    progressbar.style.width = '400px'
    progressbar.style.backgroundColor = 'orange'
  }else if(count === 4){
    progressbar.style.width = '600px'
    progressbar.style.backgroundColor = 'green'
  }
}

button.addEventListener('click', login)
728x90