* 데이터를 2차원 배열로 관리하고 배열 데이터를 HTML 화면에 그대로 표시하는 작업
* 2차원 배열
: 배열을 포함하는 배열
(
(null, 'X', null)
('0', null, '0')
(null, '0', 'X')
)
* 테이블을 직접 그리기
– 작업 파괴
: 개체 내 속성 이름 및 할당할 변수 같은 경우 코드를 단축할 수 있습니다.
const body = document.body; // 원래 코드
const { body } = document; // 구조 분해 할당
const obj = {a:1, b:2 };
const a = obj.a;
const b = obj.b;
// 구조분해할당 후
const { a, b } = obj;
const arr = (1, 2, 3, 4, 5);
const one = arr(0);
const three = arr(2);
const four = arr(3);
const five = arr(4);
// 구조 분해 할당으로 코드 줄이기
const (one, , three, four, five) = arr;
// 두 번째 배열을 제외하려면 , , 하고 콤마 안을 빈칸으로 두면 알아서 스킵함
1분 퀴즈)
// a,c,e 속성을 구조분해할당 문법으로 변수에 할당해보세요 //
const obj = {
a: 'hello'
b: {
c: 'hi',
d: { e: 'wow' },
},
};
const a = obj.a;
const c = obj.b.c;
const e = obj.b.d.e;
// 구조 분해할당으로 코드 줄이기 후
const { a, b: { c, d: { e } } } = obj;
– JS로 테이블 그리기
arr = (
($td, $td, $td),
($td, $td, $td),
($td, $td, $td),
)
arr (0)(1).textContent; // 배열 첫번째 줄에 두번째 td
HTML)
<table>
<tr>
<td id="td00"></td>
<td id="td01"></td>
<td id="td02"></td>
</tr>
<tr>
<td id="td10"></td>
<td id="td11"></td>
<td id="td12"></td>
</tr>
<tr>
<td id="td20"></td>
<td id="td21"></td>
<td id="td22"></td>
</tr>
</table>
js)
const rows = (); // 줄을 저장할 공간을 배열로 만듦.
for(let i = 1; i <= 3; i++) { // tr 3줄
const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
const $td = document.createElement('td'); // td를 선택하는 태그
cells.push($td); // td의 내용을 cells 배열에 push 한다.
$tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
}
rows.push(cells);
$table.appendChild($tr);
}
body.appendChild($table);
body.appendChild($result);
* 회전 스위치
: addEventListener를 사용하여 클릭한 셀에 O를 입력합니다. 아래 내용 추가
let turn = 'O'; // turn은 o
const callback = (e) => {
if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
console.log('빈 칸이 아닙니다');
} else { // 클릭된 칸이 빈칸이면
console.log('빈 칸입니다');
e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
// if문으로 바꾸면
// if (turn === 'X') {
// turn = 'O';
// } else {
// turn = 'X';
// }
}
};
$td.addEventListener('click', callback); // td칸이 클릭되면 callback 함수를 실행
– 추가 후 코드
let turn = 'O'; // turn은 o
const callback = (e) => {
if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
console.log('빈 칸이 아닙니다');
} else { // 클릭된 칸이 빈칸이면
console.log('빈 칸입니다');
e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
// if문으로 바꾸면
// if (turn === 'X') {
// turn = 'O';
// } else {
// turn = 'X';
// }
}
};
for(let i = 1; i <= 3; i++) { // tr 3줄
const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
const $td = document.createElement('td'); // td를 선택하는 태그
$td.addEventListener('click', callback); // td칸이 클릭되면 callback 함수를 실행
cells.push($td); // td의 내용을 cells 배열에 push 한다.
$tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
}
rows.push(cells);
$table.appendChild($tr);
}
body.appendChild($table);
body.appendChild($result);
* 이벤트 거품
: 자식 또는 자식 태그에서 이벤트가 발생하면 부모 및 부모 부모 태그에서 이벤트가 발생합니다.
즉, $td에 addEventListener를 적용하면 $tr, $table 모두에서 이벤트가 발생한다. (HTML 속성 기준)
$td.addEventListener('click', callback);
// 이벤트 버블링에 의해
$table.addEventListener('click', callback);
– 이벤트 거품 방지
event.stopPropagation();
* 이벤트 캡처
: 부모에게 발생한 사건이 자식에게로 가는 경우
* 게임을 결정
const { body } = document;
const $table = document.createElement('table');
const $result = document.createElement('div'); // 결과창
const rows = (); // 줄을 저장할 공간을 배열로 만듦.
let turn = 'O'; // turn은 o
// (
// (td, td, td),
// (td, td, td),
// (td, td, td),
// )
const checkWinner = (target) => {
let rowIndex; // 몇 번째 줄인지
let cellIndex; // 몇 번째 칸인지
rows.forEach((row, ri) => { // forEach는 인덱스를 제공해줌
row.forEach((cell, ci) => {
if( cell === target ) {
rowIndex = ri;
cellIndex = ci;
}
});
});
// 세 칸 다 채워졌나?
let hasWinner = false; // 검사할 때 시작은 false로 하고 승자가 있으면 true로 바꿔줌.
// 가로줄 검사
if (
rows(rowIndex)(0).textContent === turn &&
rows(rowIndex)(1).textContent === turn &&
rows(rowIndex)(2).textContent === turn)
{
hasWinner = true;
}
// 세로줄 검사
if (
rows(0)(cellIndex).textContent === turn &&
rows(1)(cellIndex).textContent === turn &&
rows(2)(cellIndex).textContent === turn)
{
hasWinner = true;
}
// 대각선 검사
if (
rows(0)(0).textContent === turn &&
rows(1)(1).textContent === turn &&
rows(2)(2).textContent === turn
) {
hasWinner = true;
}
if (
rows(0)(2).textContent === turn &&
rows(1)(1).textContent === turn &&
rows(2)(0).textContent === turn
) {
hasWinner = true;
}
return hasWinner;
};
const callback = (e) => {
if(e.target.textContent !== '') { // 클릭된 칸이 빈칸이 아니면
console.log('빈 칸이 아닙니다');
} else { // 클릭된 칸이 빈칸이면
console.log('빈 칸입니다');
e.target.textContent = turn; // 클릭된 칸의 텍스트를 'O'로 채우겠다.
if (checkWinner(e.target)) {
$result.textContent = `${turn}님이 승리!`;
return;
}
// 무승부 검사
let draw = true;
rows.forEach((row) => {
row.forEach((cell) => {
if(!cell.textContent) { // 한 칸이라도 비어있으면
draw = false; // 무승부가 아님
}
});
});
if(draw) { // 모든 칸이 차 있으면
$result.textContent = `무승부`; // 무승부다.
return;
}
turn = turn === 'X' ? 'O' : 'X'; //turn이 X면 O로 바꾸고 아니면 X로 바꿔라.
// if문으로 바꾸면
// if (turn === 'X') {
// turn = 'O';
// } else {
// turn = 'X';
// }
};
}
for(let i = 1; i <= 3; i++) { // tr 3줄
const $tr = document.createElement('tr'); // 한 줄을 선택하는 태그
const cells = (); // 한 줄 안에 요소인 td를 저장할 배열을 만듦.
for (let j = 1; j <= 3; j++) { // td 3개/1줄당, 총 9개
const $td = document.createElement('td'); // td를 선택하는 태그
cells.push($td); // td의 내용을 cells 배열에 push 한다.
$tr.appendChild($td); // tr에 td를 추가한다. (줄에 td칸을 추가한다)
}
rows.push(cells);
$table.appendChild($tr);
}
$table.addEventListener('click', callback); // 이벤트버블링
body.appendChild($table);
body.appendChild($result);