이벤트 버블링
- event.target은 이벤트가 발생한 직접적인 대상
- 이벤트가 발생한 태그가 아닌 이벤트를 연결한 태그에 접근하고 싶다면 event.currentTarget을 사용
- HTML에서는 이벤트가 발생할 때 부모 태그에도 순차적으로 동일한 이벤트가 발생
parnetNode와 children
현재 태그의 부모 태그를 찾고 싶을 때는 parnetNode
자식 태그를 찾으려면 children 속성
- children 속성을 배열 모양의 값이 됨, 진짜 배열아니고 배열 모양의 객체
rowIndex , cellIndex
rowIndex : tr태그에서 몇 번째 줄인지
cellIndex : td 태그는 몇 번째 칸인지
유사 배열 객체
배열이 아니므로 배열 메서드를 사용할 수 없다
배열 메서드를 사용하고 싶다면 Array.from 메서드로 유사 배열 객체를 배열로 바꿈
every , some
every는 모든 값이 조건에 해당하는지 판단
some은 하나라도 조건에 해당하는지 판단
every,some은 하나라도 조건이 충족 또는 불충족되면 멈춤
flat은 배열의 차원을 한단계 낮추는 메서드
n => n-1로 낮춤 (2차원 배열을 1차원 배열로)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>틱택토</title>
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
width: 40px;
height: 40px;
text-align: center;
}
</style>
</head>
<body>
</body>
<script>
//구조 분해 할당 => 객체안의 속성이름과 변수 이름이 같을 때 사용
//객체의 구조 분해 할당
const { body } = document;
// const body = document.body;
// const createElement = document.createElement;
const $table = document.createElement('table');
const $result = document.createElement('div'); // 결과창
const rows = [];
let turn = 'O';
const callback = (event) => {
if (event.target.textContent !== '') { // 칸이 이미 채워져 있는가?
console.log('빈칸이 아닙니다.');
return;
}
// 빈칸이면
console.log('빈칸입니다');
event.target.textContent = turn;
const hasWinner = checkWinner(event.target);
// 승자가 있으면
if (hasWinner) {
$result.textContent = `${turn}님이 승리!`;
$table.removeEventListener('click', callback);
return;
}
// 승자가 없으면
let draw = true;
//9칸 모두 비어있지 않으면됨
rows.forEach((row)=>{
row.forEach((cell)=>{
if(!cell.textContent){
draw = false;
}
})
});
if(draw){
$result.textContent = `무승부`;
return;
}
turn = turn === 'X' ? 'O' : 'X';
};
const checkWinner = (target) => {
// tr은 rowIndex라는 속성을 제공
// td는 cellIndex라는 속성을 제공
let rowIndex = target.parentNode.rowIndex;
let cellIndex = target.cellIndex;
console.log(target.parentNode.children);
let hasWinner = false;
rows.forEach((row, ri) => { //각 행
row.forEach((cell, ci) => { // 각 행의 cell
if (cell === target) {
//클릭한 행과 열
rowIndex = ri;
cellIndex = ci;
}
})
});
// 가로줄 검사
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;
}
for (let i = 1; i <= 3; i++) { // 행
const $tr = document.createElement('tr');
const cells = [];
for (let j = 1; j <= 3; j++) { //열
const $td = document.createElement('td');
cells.push($td); //td태그를 넣음
$tr.appendChild($td);
}
rows.push(cells);
$table.appendChild($tr);
$table.addEventListener('click', callback);
}
body.appendChild($table);
body.appendChild($result);
</script>
</html>