이번 시간에는 지난번에 만들었던 여행 준비물 체크 리스트에서 '드래그 앤 드롭' 기능을 추가 구현해보았다.

 

 

2024-08-22 :: 022 Java Script 활용 ①

자바 스크립트를 이용하여 나만의 여행 준비물 리스트 목록을 만들어 보았다.생각보다 막히는 부분이 많아서 고생을 좀 했지만...아래는 자바스크립트만 해석하고 기록해보겠다. (CSS는 사용자

hcl-yeon.tistory.com


 

   캡처에는 드래그 부분이 나오지 않지만 준비완료 체크 박스에 아이템이 담긴 것을 확인할 수 있다.

지난시간에 입력하고 추가하는 부분은 작성해두었으니 오늘은 드래그 앤 드롭 부분만 가져와 기록하려고 한다.

 


let dropList = [];
//드롭된 요소들이 담길 배열변수를 선언.
let dropZone = document.querySelector('#drop_box')
//드롭한 아이템들이 담길 div 태그를 들고왔다.

function showList() {
  let list = "<ul id='itemUl' >"
  //기존의 showList 기능으로 만들었던 ul태그를 선택하기 쉽도록 아이디를 붙여주었다.

  for (let i = 0; i < itemList.length; i++) {
    list += `<li>${itemList[i]}<span class='close' id=${i}> X <span></li>`
  }
  list += "</ul>"

  document.querySelector('#itemList').innerHTML = list;

  let itemUl = document.querySelector('#itemUl')
  //변수에 해당 ul태그를 담아두었다.

  //반복문을 사용해 ul태그 안에 생겨날 자식들에게 드래그 효과를 지정해주었다.
  //자식의 인덱스도 0부터 시작하는 것에 유의하자.

  for (let i = 0; i < itemUl.children.length; i++) {
    itemUl.children[i].setAttribute("draggable", "true");
    //드래그가 가능한 상태가 되도록 속성을 추가하는 작업이다.

    itemUl.children[i].addEventListener('dragstart', dragStart)
    //드래그가 시작될 때 이벤트가 발생한다.

    itemUl.children[i].addEventListener('dragend', dragEnd)
    //드래그가 끝날 때 이벤트가 발생한다.
  }

  removeEvent()
}


function dragStart() {
  this.classList.add('dragging');
  //드래그 이벤트가 발생한 요소에 dragging 이라는 클래스를 추가한다.
}

function dragEnd() {
  this.classList.remove('dragging');
  //드래그 이벤트가 끝난 요소에 dragging 이라는 클래스를 삭제한다.
}


// e : 이벤트(event)가 발생한 객체
dropZone.addEventListener('dragover', function (e) {
  e.preventDefault();
  //기본 동작 방지, 폼 제출 방지, 링크 클릭 시 페이지 이동 방지 등... 드래그 앤 드롭을 위한 기본 설정이다.

  dropZone.classList.add('hovered');
  //드래그 한 상태로 해당 div 요소에 오버되면 hovered 라는 클래스를 추가한다.

});

dropZone.addEventListener('dragleave', function () {
  dropZone.classList.remove('hovered');
  //드래그 한 상태로 해당 div 요소를 떠나면 hovered 라는 클래스를 삭제한다.

});

dropZone.addEventListener('drop', function (e) {
  e.preventDefault();
  dropZone.classList.remove('hovered');
  //드래그 한 상태로 해당 div 요소 안에서 드롭되면 hovered 라는 클래스를 삭제한다.

  let item = document.querySelector('.dragging');
  //앞서 드래그 이벤트가 시작되면 추가되는 클래스 속성을 가진 요소를 지역변수에 담는다.


  dropZone.appendChild(item)
  //해당 요소를 div 태그의 자식으로 붙여넣는다.


  let text item.textContent;
  //들고 온 요소의 텍스트만 지역변수에 담는다.

  //span으로 삭제 버튼을 만들어 두었기 때문에 그 요소까지 나타난다.

  let index_str = text.slice(0,text.length-3)
  //span 부분을 삭제하기 위해 3글자를 빼주었다.

  let index = itemList.indexOf(index_str)
  //itemList(input값을 담은 장소)에 담겨있는 글자들과 대조해서 일치하는 값 = 해당 배열의 인덱스가 반환된다.

  if(index != -1){
    itemList.splice(index,1)
    //찾아낸 인덱스 값에서 부터 하나의 요소를 제거한다.

  }

  dropList = this.children
  //드롭이 일어난 요소의 자식들을 해당 배열변수에 담는다. (덮어쓰기)

  for(let i=0; i<dropList.length; i++){
    dropList[i].children[0].id = `drop${i}`
    //배열변수의 첫번째 자식들의 아이디를 초기화한다. (기존 input 태그로 생성한 아이디가 그대로 옮겨오기 때문)

  }

    showList()
  removeEvent()
  //드롭된 이후, itemList들이 가진 id를 재할당하기 위해 기능을 리로드 시킨다.
  //드롭된 부분의 리무브 이벤트를 재할당하기 위해 기능을 리로드 시킨다.


});


function removeEvent() {
  let delBut = document.querySelectorAll('.close')
  for (let i = 0; i < delBut.length; i++) {
    delBut[i].addEventListener("click", delList);
  }

  //기존 리무브 이벤트에서 드롭된 아이템들에 한해 삭제 이벤트를 재설정 해준다.
  for(let i=0; i<dropList.length; i++){
    dropList[i].children[0].removeEventListener("click", delList)
    //먼저 선언되어 있던 기능을 삭제한다.
    dropList[i].children[0].addEventListener("click", delDrop)
    //새로운 삭제 이벤트를 추가한다.
  }
}

function delDrop(){
  dropZone.removeChild(this.parentNode)
  //해당 div의 자식 요소를 삭제하는데, 선택한 요소의 부모를 삭제함으로써 HTML에서 완전히 삭제가 된다.
  //부모 = 드롭장소인 div태그, 자식 = 드롭된 li 태그, 선택한 요소(this) = span 태그
}

   오늘은 랜덤한 숫자값을 맞추는 간단한 게임을 만들어 보았다 :)

 

See the Pen Untitled by IT배움터 (@gfifvcbf-the-typescripter) on CodePen.


     let count = 0;
    //사용자가 몇 번만에 맞췄는지 나타낼 변수다, 초기값은 0

    let alertDiv = document.querySelector('.text_box')
    //사용자가 정답을 맞추거나 틀렸을 경우 문구를 띄울 장소를 가져오기

    let inputNumber = document.querySelector('input')
    //사용자가 입력한 값을 받아오기 위해 input 태그를 들고오기

    inputNumber.id = Math.floor(Math.random() * 100) + 1
    //여기서 랜덤 값을 input의 아이디에 저장하기로 했다. 굳이 id에 줄 필요는 없고 따로 변수를 만들어 그 곳에 저장해도
    똑같은 결과가 나올 것이다... (기능을 좀 더 다양하게 써보기 위해 input태그의 id 공간에 넣기로 했을 뿐)


    let randomId = inputNumber.getAttribute("id")
    //랜덤하게 바뀐 input 태그의 ID를 가져와서 변수에 저장했다.
    //문자열로 저장되기 때문에 숫자로 바꿔줘야 한다.


    let nBtu = document.querySelector('button')
    nBtu.addEventListener('click', numberAnswer)
    //사용자가 버튼을 눌렀을 때 기능이 실행되도록 한다


    function numberAnswer() {
      let userA = Number(inputNumber.value)
      //input태그에 받아온 값을 지역변수로 선언
      //input태그에 담기는 값은 문자열이기 때문에 숫자로 바꿔주는 작업이 필요하다.


      if (userA > 0 && userA < 101) {
        if (userA == randomId) {
          count++
          //사용자가 시도한 횟수 만큼 count 값을 증가시키기 때문에 모든 조건문에 붙는다.
          alertDiv.innerHTML = `정답입니다! ${count}번 만에 맞추셨습니다!`

          inputNumber.id = Math.floor(Math.random() * 100) + 1
          randomId = inputNumber.getAttribute("id")
          //정답을 맞춘 후, 기존 변수를 재선언함으로써 새로운 랜덤값이 생성된다.

          inputNumber.value = ""
            //사용자가 입력한 값을 없앤다.

          count = 0;
          //정답을 맞췄기 때문에 시도횟수는 초기화

        } else if (userA > randomId) {
          count++
          alertDiv.innerHTML = `입력한 값 ${userA}보다 낮은 숫자입니다. 다시 시도해보세요.`
          inputNumber.value = ""

        } else if (userA < randomId) {
          count++
          alertDiv.innerHTML = `입력한 값 ${userA}보다 높은 숫자입니다. 다시 시도해보세요.`
          inputNumber.value = ""
        }

      } else {
        alertDiv.innerHTML = `1~100 사이의 숫자를 입력해주세요.`
        //앞서 사용자가 1~100까지의 숫자를 입력했는지 확인하고 아닐시 else문을 실행한다.
      }
    }

 


   한 글자만 맞아도 검색 목록에 뜨는 화면을 만들어보자.

 

See the Pen Untitled by IT배움터 (@gfifvcbf-the-typescripter) on CodePen.


    let item = [ ];
    //아이템들을 담을 변수 선언

    let itemList = document.querySelectorAll('#itemList > li')
    let itemSearch = document.querySelector('input')
    itemSearch.addEventListener('input', itemValue)
    //input = form 요소의 값이 변경될 때마다 이벤트 발생


    for (let i = 0; i < itemList.length; i++) {
      item.push(itemList[i].innerHTML)
      //배열변수에 li태그가 가지고 있는 텍스트 이름을 모두 저장

    }

    function itemValue() {
      for(let i=0; i<item.length; i++){
        let itemCode = String(item[i]) 
        let userSerach = String(itemSearch.value)

        //includes = 해당 문자열이 포함이 되어 있을 경우 true를 반환

        if(itemCode.includes(userSerach)){
          itemList[i].style.display = "block"
        } else{
          itemList[i].style.display = "none"
        }
      }
    }
    

 


    let itemList = document.querySelectorAll('#itemList > li')
    let itemSearch = document.querySelector('input')

    //keyup = 키보드를 누를 때마다 이벤트 발생
    itemSearch.addEventListener('keyup', function(){
      let itemText = itemSearch.value;
      //지역변수에 input태그에서 받아온 값을 키보드를 누를때마다 저장


      itemList.forEach(function(array){
        let listText = array.textContent;
        //textContent = 요소가 가지고 있는 텍스트를 가져옴


        //indexOf = 해당 문자열을 가지고 있을 경우 해당 위치의 인덱스 반환, 없으면 -1을 반환함
        if(listText.indexOf(itemText) !== -1){
          array.style.display = "block"
        } else {
          array.style.display = "none"
        }
      })
         //indexOf로 반환받은 숫자가 양수면 해당 li태그를 block 처리, 음수면 none처리

    })

 

+ Recent posts