본문 바로가기
CodeIt_Sprint/React_초급

(18)React_초급_DiceGame_React_Project_2_인라인 작성부분

by 코잼민 2024. 11. 26.

- 이전 JSX 작성 과정 링크  : https://kojammin.tistory.com/201

- CSS 예시자료 받을 수 있는 링크 : https://kojammin.tistory.com/199

 

▣저번 과정까지 기본 구조, 작동 부분을 구현했으니, 이제 CSS 스타일 작업으로 꾸미기를 하는 과정

◎ 6_ 전체 배경화면, 폰트의 Style 적용 => index.html의 style 시트에 직접 적용

- index.html 

<!DOCTYPE html>
<html lang="ko">

<head>
  <meta charset="utf-8" />
  <title>주사위 게임</title>
  <style>
    body {
      color: #fff;
      font-family: 'NanumSquareRound', sans-serif;
      background-color: #191f2c;
    }
    body div#root{
      display : flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
  </style>
</head>

<body>
  <div id="root"></div>
</body>

</html>

● 출력 장면 :

◎ 7_ Header 부분 

=> "F12"를 눌러 <div class="Header"> 부분이라는 것을 알 수 있다.

● 순서1_ [src]폴더에 [Style]폴더를 따로 생성, Header부분 담당의 [Header.css] 생성, <App> 컴포넌트에 import로 적용 하기

○ [src]폴더에 [Style] 폴더 생성 + [Style]폴더에 [Header.css] 생성

○ App.js에 [Header.css] 적용하기

- App.js 일부분

import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Board from './Board';

//CSS
import './Style/Header.css'

● 순서2_ <App> 컴포넌트에서 각 태그들에 class명 붙이기 => className 속성

- App.js 일부분

import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Board from './Board';

//CSS
import './Style/Header.css'

//... 생략

function App()
[
/.. 생략
	return (
    <>
      <div className='Header'>
      	//<img> 태그에 class 속성 "Header-logo"
        <img className='Header-logo' src={HeadImg} alt='head-logo-img'></img>
        //<img> 태그에 class 속성 "Header-title"
        <h1 className='Header-title'>주사위 게임</h1>
      </div>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>
        <Button onClick={handleRollReset}>처음부터</Button>
      </div>
      <div className='Board'>
        <Board name="나" color="blue" record={myRecord}></Board>
        <Board name="상대" color="red" record={otherRecord}></Board>
      </div>
    </>
}

● 순서3_ [Header.css] 작성

- Header.css

.Header{
  display : flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.Header .Header-logo{
  height: 65px; 
}

.Header .Header-title{
  margin: 10px auto 28px;
  font-size: 28px;
}

◎ 8_ Button 컴포넌트 style 시트 꾸미기

=> 같은 원리로 [Button.css] 생성 => Button.js에 import => CSS 코드 작성 //이과정은 생략함

★생각해야 될 개념1 : "던지기"버튼 => Blue , "처음부터"버튼 => Red

§ 해결방법 : 

1_일단 CSS에는 기본 버튼 CSS 시트인 .Button 를 작성하고

2_1_"던지기" Button은 .Button .blue{} 클래스로 상속받아 적용되도록 한다.

2_2_"처음부터" Button은 .Button.red{} 클래스로 상속받아 적용되도록 한다.

- Button.css :

//버튼이면, 기본적으로 적용될 CSS
.Button {
  min-width: 120px;
  padding: 14px 27px;
  border-radius: 9999px;
  outline: none;
  font-size: 18px;
  font-family: 'NanumSquareRoundEB';
  cursor: pointer;
}

//던지기 버튼 CSS = .Board + .Board.blue
.Button.blue {
  border: 1px solid #7090ff;
  color: #7090ff;
  background-color: rgba(0, 89, 255, 0.2);
}

.Button.blue:hover {
  background-color: rgba(0, 89, 255, 0.3);
}

//처음부터 버튼 CSS = .Board + .Board.red
.Button.red {
  border: 1px solid #ff4664;
  color: #ff4664;
  background-color: rgba(255, 78, 78, 0.2);
}

.Button.red:hover {
  background-color: rgba(255, 78, 78, 0.3);
}

 

순서1_ "던지기"<Button> 컴포넌트에 props.className 객체 프로퍼티에 "blue" 값을 대입하고, 전달받은 "blue" 값에 따라 class 상속으로 css 적용하기

○ Button.js 컴포넌트에 매개인자 className을 추가 + <button> 태그에 className 속성값 대입시 "blue" || "red"입력에 따라, .Button ."blue"||."red" 가 되도록 코드 작성

//Button.js
import './Style/Button.css';

function Button({onClick ,children, className=""})
{
  return (<button className={`Button ${className}`} onClick = {onClick}>{children}</button>);
}

export default Button;

○ App.js에서, <Button>컴포넌트 태그에 props.className ="blue"를 "던지기"버튼 , props.className ="red"를 "처음부터"버튼에 적용

//App.js 일부

function App()
{
 return (
    <>
      <div className='Header'>
        <img className='Header-logo' src={HeadImg} alt='head-logo-img'></img>
        <h1 className='Header-title'>주사위 게임</h1>
      </div>
      <div>
      	//던지기 버튼 "blue"을 className에 대입
        <Button className="blue" onClick={handleRollClick}>던지기</Button>
        //처음부터 버튼 "red"을 className에 대입
        <Button className="red" onClick={handleRollReset}>처음부터</Button>
      </div>
      <div className='Board'>
        <Board name="나" color="blue" record={myRecord}></Board>
        <Board name="상대" color="red" record={otherRecord}></Board>
      </div>
    </>
  );
}

export default Button;

 

● 출력 장면 :

★생각해야 될 개념2 : 

  • 버튼 요소 내부에 대한 꾸미기 => Button.css에 적용
  • 버튼 요소 외부에 대한 꾸미기 => Button.css의 부모인 App.css에 적용

다시 말하면, "던지기"버튼과 "처음부터"버튼 사이의 거리 조절 => App.css에 적용

 순서2_ [Style]폴더의 [App.css] 생성, 버튼 사이의 거리 조절 코드 작성

//App.css

.Middle-Button{
  /*버튼 사이의 거리*/
  display : flex;
  gap : 20px;
}

 

◎ 9_ Board style 시트 꾸미기

§전략 :

Board 외부 : "나"와 "상대" 끼리는 거리를 좀 두기 => App.css에 작성

Board 내부 : 세로 중심으로 정렬 +> Board.css에 작성

- App.css

.Middle-Button{
  /*버튼 사이의 거리*/
  display : flex;
  gap : 20px;
}

.Board-Box{
  /*플레이어 박스의 배치*/
  margin-top : 20px;

  display : flex;
  gap : 20px 20px;
}

- Board.css

.Board {
  display : flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 35px 30px;
  border: 1px solid transparent;
  border-radius: 12px;
  font-size: 16px;
  text-align: center;
  background-color: #272b38;
}

 

 

◎ 10_ Board 중 나온 눈의 수에 따라 승자 결정 + 승자를 나타내는 CSS 시트 적용

※꽤 고난이었음

■ 전략 :

● [Board.css]에 주사위 눈이 큰 Board에는 winner클래스 자식을 덧붙인다.

○ Board.css

.Board {
  display : flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 35px 30px;
  border: 1px solid transparent;
  border-radius: 12px;
  font-size: 16px;
  text-align: center;
  background-color: #272b38;
}

.Board.winner{
  border: 1px solid #fff;
  box-shadow: 0 0 12px 0 hsla(0, 0%, 100%, 0.48);
}

● [App.js]에 주사위 눈을 비교해서, "나"와 "상대" 중 눈이 높은 놈한테 winner 상속

○ App.js

import { useState } from 'react';
import HeadImg from './assets/logo.png';
import Button from './Button';
import Board from './Board';

//CSS
import './Style/Header.css';
import './Style/App.css';
import './Style/Board.css';

function randNum()//1~6 넌수 발생 메소드
{
  return Math.floor(Math.random()*(6-0)) +1;
}

function App() {

  //배열 선언
  const [myRecord,setMyRecord] = useState([]);
  const [otherRecord,setOtherRecord] = useState([]);

  //★승자 결정 정보 변수=> Defalut 값으로 "" 초기값
  const [winner,setWinner] = useState("");

  //던지기에 대한 핸들러 메소드
  const handleRollClick = ()=>
  {
    const blueNum = randNum();
    const redNum = randNum();

        // 기록 업데이트
        setMyRecord((myRecord) => [...myRecord, blueNum]);
        setOtherRecord((otherRecord) => [...otherRecord, redNum]);

        /★ 버튼을 누를시, blueNum vs redNum 으로 승자 결정
        if(blueNum>redNum)//내가 이겼을 때,
        { 
          setWinner("나");
        }
        else if(blueNum<redNum)
        {
          setWinner("상대");
        }

  };

  const handleRollReset = () =>
  {


    //기록을 빈 배열로 초기화
    setMyRecord([]);
    setOtherRecord([]);
  }


  return (
    <>
      <div className='Header'>
        <img className='Header-logo' src={HeadImg} alt='head-logo-img'></img>
        <h1 className='Header-title'>주사위 게임</h1>
      </div>
      <div className="Middle-Button">
        <Button className='blue' onClick={handleRollClick}>던지기</Button>
        <Button className='red' onClick={handleRollReset}>처음부터</Button>
      </div>
      <div className='Board-Box'>
      <Board 
      		//★삼항 연산자를 이용해, "나"가 승리할 시, className으로 "winner" 전달
          className={`${(winner === "나") ? "winner" : ""}`} 
          name="나" 
          color="blue" 
          record={myRecord} 
        />
        <Board 
          className={`${(winner === "상대") ? "winner" : ""}`} 
          name="상대" 
          color="red" 
          record={otherRecord} 
        />
      </div>
    </>
  );
}

export default App;

● App.js에서 받은 props.winner 값을 [Board.js]에서 <div> 태그의 class값 적용

○ Board.js

import Dice from "./Dice";
import './Style/Board.css'


function Board({name, color,record, className}) {//★className 매개인자 추가
  
  let num = 1;
  if(record.length>0)
  {
    num = record[record.length-1]
  }

  const sum = record.reduce((a,b)=>a+b,0);

  return (
    <div className={`Board ${className}`}>
    //★div 박스 board에 적용하여, "winner"값이면, 클래스 상속되고, 아니면 ,기본 .Board 클래스 css 적용된다.

      <h2>{name}</h2>
      <Dice color={color} num={num}></Dice>
      <h2>총점</h2>
      <p>{sum}</p>
      <h2>기록</h2>
      <p>{record.join(", ")}</p>
    </div>
  );
}

export default Board;

- 출력장면 :