ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript 입문 : 우클릭 이벤트 - contextmenu, 우클릭 이벤트를 통한 깃발과 물음표 만들기
    컴퓨터 알아가기/JavaScript 2022. 10. 30. 19:30
    728x90
    반응형

    지금까지 마우스 좌클릭을 통해 클릭이벤트를 공부는 해보았지만 우측클릭으로 하는 경우는 이번이 처음 배워보는 것 같습니다. 

     

    보통 addEventListener를 사용하는 경우 좌클릭 이베트는 'click'이었는데 우클릭은 'contextmenu'라는 이벤트가 따로 있습니다. 

     

    지금 이 글을 쓰고 있는 화면에 우측클릭을 해보면 다음과 같이 나옵니다. 

     

    우클릭한 모습

     

    상기 그림과 같이 우측클릭을 하면 나오는 내용을 제어하고 만들 수 있는이벤트가 contextmenu입니다. 

    지금부터는 contextmenu를 통해 10 X 10 배열칸에 우클릭을 통하여 깃발이나 물음표를 표시하는 기능을 배워보도록 할 예쩡입니다. 

     

    이는 제로초 TV 지바스크립트 강좌를 통하여 공부를 하고 있습니다. 

     

    ▒ 우클릭이벤트 

     

    1. 우클릭이벤트로 만들어야 할 것 

     

    순서도를 기억해 보면 우클릭으로 깃발이나 물음표를 만들 예정입니다. 열린칸인지 아닌지를 판단하고 물음표를 표시할지 아니면 깃발을 표시할지 게임을 진행하면서 판단할 수 있는 기능을 만들어 주는게 기본 방향입니다. 물론 다시 닫힌칸으로 만드는 원상복귀까지 고려해야 할 듯 합니다. 

     

    2. 우클릭이벤트 선언

     

    지뢰모양이 나온 data에 같이 연결을 해줘야합니다. 각 칸을 나타내는 <td>태그인 target이 해당되는데 100칸에 전부 연결을 해주면 나중에 우클릭이벤트를 해지할때도 100칸에 전부 적용을 해줘야하는 번거로움이 있습니다. 

     

    이를 해결하기 위하여 이벤트버블링 원칙으로 자식태그와 부모태그가 서로 연결이 되는 원리를 이용하여 <tbody>태그에 우클릭이벤트를 연결합니다. 

     

     

    3. 우클릭을 통한 물음표와 깃발 만들기 

     

    우리가 처음 만든 코드숫자 구분에서 물음표와 깃발에 대한 코드를 다음과 같이 만든적이 있습니다. 이 중에 물음표와 깃발은 다음 코드숫자가 필요하겠죠. 

     

     

    또 필요한 사항은 각 이벤트가 일어나는 <td>태그를 변수에 저장하고 각 데이터를 가져올 수 있는 코드를 각 코드숫자와 연결시키는 작업이 필요합니다. 

     

    역시 사전에 data라는 광역변수를 선언해 주었기때문에 편의상 data를 이용합니다. 

     

    // 6.1 onRightclick()
        function onRightClick(e) {
          e.preventDefault(); // 우클릭 기본기능 삭제
          const target = e.target;
          // 몇번째 칸 클릭했는지 알기위해 row와 cell 변수
          const rowIndex = target.parentNode.rowIndex; // tr
          const cellIndex = target.cellIndex; 
          const cellData = data[rowIndex][cellIndex]; // data 변수 선언필요
    
          if (cellData === CODE.MINE) { // 지뢰면 물음표지뢰로
            data[rowIndex][cellIndex] = CODE.QUESTION_MINE; // data에 직접 입력       
            target.className = 'question';
            target.textContent = '?';
            
          } else if (cellData === CODE.QUESTION_MINE) { // 물음표지뢰면 깃발지뢰로
            data[rowIndex][cellIndex] = CODE.FLAG_MINE;
            target.className = 'flag';
            target.textContent = '!';
            
          } else if (cellData === CODE.FLAG_MINE) { // 깃발지뢰면 지뢰로
            data[rowIndex][cellIndex] = CODE.MINE;
            target.className = '';
            target.textContent = 'X';         
          
          } else if (cellData === CODE.NORMAL) { // 일반사항이면 물음표로
            data[rowIndex][cellIndex] = CODE.QUESTION;
            target.className = 'question';
            target.textContent = '?';            
            
          } else if (cellData === CODE.QUESTION) { // 물음표면 깃발로
            data[rowIndex][cellIndex] = CODE.FLAG;
            target.className = 'flag';
            target.textContent = '!';    
            
          } else if (cellData === CODE.FLAG) { // 깃발이면 일반사항으로 
            data[rowIndex][cellIndex] = CODE.NORMAL;
            target.className = '';
            target.textContent = '';        
    
          } 
        }

     

    이제 브라우저를 보게되면 우클릭으로 지뢰가 숨겨져 있다고 예상되는 칸에 물음표나 깃발 또는 원상태로 복귀시킬 수 있는 기능을 볼 수 있습니다.

     

     

     
    현재까지 진행된 자바스크립트 코드는 다음과 같습니다. 

     

    // 1. HTML 활성화 (자바스크립트로 연결)
        const $timer = document.querySelector('#timer');
        const $tbody = document.querySelector('#table tbody'); // tr, td가 기입예정
        const $result = document.querySelector('#result');
    
        // 2. 가로 세로 지뢰의 수 
        const row = 10; // 줄
        const cell = 10; // 칸
        const mine = 10; // 지뢰
    
        // 3. 종류에 대한 코드명과 코드숫자 넣기 
        const CODE = {
          NORMAL: -1, // 닫힌칸 (지뢰없음)
          QUESTION: -2, // 물음표칸 (지뢰없음)
          FLAG: -3, // 깃발칸 (지뢰없음)
          QUESTION_MINE: -4, // 물음표칸 (지뢰있음)
          FLAG_MINE: -5, // 깃발칸 (지뢰있음)
          MINE: -6, // 닫힌칸 (지뢰있음)
          OPENED: 0, // 열린칸, 0이상이면 (8까지) 모두 열린칸 
        }
    
        // 4. 변수 묶기     
        let data;
    
        // 5. 게임의 흐름 
    
        // 5.3 
        function plantMine() {
    
          // 10 X 10 테이블 각각 칸을 위한 인덱스 만들기 
          const candidate = Array(row * cell).fill().map((e, i) => {
            return i;
          });
          console.log(candidate);
    
          // 지뢰에 연결할 랜덤 10개 뽑기
          const shuffle = [];
          for (let i = 0; i < mine; i++) {
            const random = Math.floor(Math.random() * candidate.length);
            const choice = candidate.splice(random, 1)[0];
            shuffle.push(choice);
          }
          console.log(shuffle);
    
          // 100개의 칸 NORMAL 코드 심기 
          const data = []; // data에 최종 지뢰심기
          
          for (let i = 0; i < row; i++ ) {
            const normal = [];
            data.push(normal);
            for (j = 0; j < cell; j++) {
              normal.push(CODE.NORMAL); 
            }
          }
          console.log(data);
    
          // 10개의 칸 MINE 코드 심기
          for (k = 0; k < shuffle.length; k++) {
            const rowTen = Math.floor(shuffle[k] / row); // 2
            const cellOne = shuffle[k] % cell; // 2 
            data[rowTen][cellOne] = CODE.MINE;
          }
          return data;
    
          console.log(data);
        }
    
        // 6.1 onRightclick()
        function onRightClick(e) {
          e.preventDefault(); // 우클릭 기본기능 삭제
          const target = e.target;
          // 몇번째 칸 클릭했는지 알기위해 row와 cell 변수
          const rowIndex = target.parentNode.rowIndex; // tr
          const cellIndex = target.cellIndex; 
          const cellData = data[rowIndex][cellIndex]; // data 변수 선언필요
    
          if (cellData === CODE.MINE) { // 지뢰면 물음표지뢰로
            data[rowIndex][cellIndex] = CODE.QUESTION_MINE; // data에 직접 입력       
            target.className = 'question';
            target.textContent = '?';
            
          } else if (cellData === CODE.QUESTION_MINE) { // 물음표지뢰면 깃발지뢰로
            data[rowIndex][cellIndex] = CODE.FLAG_MINE;
            target.className = 'flag';
            target.textContent = '!';
            
          } else if (cellData === CODE.FLAG_MINE) { // 깃발지뢰면 지뢰로
            data[rowIndex][cellIndex] = CODE.MINE;
            target.className = '';
            target.textContent = 'X';         
          
          } else if (cellData === CODE.NORMAL) { // 일반사항이면 물음표로
            data[rowIndex][cellIndex] = CODE.QUESTION;
            target.className = 'question';
            target.textContent = '?';            
            
          } else if (cellData === CODE.QUESTION) { // 물음표면 깃발로
            data[rowIndex][cellIndex] = CODE.FLAG;
            target.className = 'flag';
            target.textContent = '!';    
            
          } else if (cellData === CODE.FLAG) { // 깃발이면 일반사항으로 
            data[rowIndex][cellIndex] = CODE.NORMAL;
            target.className = '';
            target.textContent = '';        
    
          } 
        }
    
    
    
        // 5.2 
        function startGame() {
          data = plantMine();
    
          // data와 연결하는 tr, td 화면 만들고 지뢰 연결
          data.forEach((row) => { // row부터
            const $tr = document.createElement('tr');
            row.forEach((cell) => {
              const $td = document.createElement('td');
              if (cell === CODE.MINE) {
                $td.textContent = 'X';
              }
              $tr.append($td);
            });
            $tbody.append($tr);
    
            // 6. 우클릭이벤트
            $tbody.addEventListener('contextmenu', onRightClick);
    
    
          });
        }
    
        startGame(); // 5.1

     

    참고로 브라우저상에는 다음과 같이 코드숫자가 잘 반영이 되고 있는지 확인할 수 있습니다.

     

     

     

     

    반응형

    댓글

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Designed by Tistory.