FrontEnd/Vue를 이용한 웹 게임 만들기

Chapter 04. 반응 속도 체크 게임

계란💕 2023. 4. 13. 17:00

반응 속도 체크와 webpack watch

  • 자바스크립트가 아닌 무언가가 추가될 때마다 config 파일의 rulesloader를 추가한다. 그러면 웹팩이 알아서 자바스크립트로 바꿔준다. 
  • ex) .vue로 끝나는 파일은 자바스크립트가 아니지만 vue-loader가 자바스크립트 파일로 바꿔준다. 따라서 한 번에 자바스크립트 파일로 합칠 수 있다. 
  • 앞으로도 css, 이미지, html 같은 파일도 마찬가지이다. 그 때도 각각 맞는 로더를 사용하면 하나의 자바스크립트 파일로 합칠 수 있다는 것이 웹팩의 장점이다. 
  • entry, module, plugins, output 은 꼭 알아두기

  Ex) 반응 속도 체크 게임

 

  • 비동기 작업(set timeout?)과 를 같이 쓰는 연습하려고 한다. 
  • 다음과 같이 새로운 폴더에서 초기화한다. 
    • npm -i를 입력하면  package.json에 있는 내용이 모두 설치된다. node modules라는 새로운 폴더에 설치된다.


  Ex) npm run build 를 매번 입력해서 실행하는게 번거롭다.  build가 자동으로 되도록 하려면?

 

  • 다음과 같이 "webpack" 뒷 부분에 "--watch"를 추가한다. 
  • 코드가 수정될 때마다 자동으로 빌드된다. 
<hide/>
{
  "name": "response-check",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --watch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vue": "^2.6.0"
  },
  "devDependencies": {
    "vue-loader": "^15.10.1",
    "vue-template-compiler": "^2.7.14",
    "webpack": "^5.77.0",
    "webpack-cli": "^5.0.1"
  }
}

 


 v-bind와 vue style

  • 클래스를 바꿔서 클래스에 연결된 스타일을 바꿔보려고 한다. 스크린에 가로 300, 세로 200의 div 공간을 만들고 클래스에 따라 색깔이 바뀐다. 
  • v-bind 
    • state를 원하는 게 아니라 state 값을 원하니까 v-bind를 사용한다. 
    • 클래스에 데이터를 넣어주기 위해 v-bind를 쓸 수 있다. 
  • npm i vue-style-loader -D
    • 웹팩 관련된 것은 모두  "-D"를 붙여서 개발 모드로 실행한다. 
  • 다음과 같이  css loader와 vue style loader를 추가한다. 
    • 추가했으니 npm run build
<hide/>
// const {VueLoaderPlugin} = require('vue-loader/lib/plugin');

const {VueLoaderPlugin} = require('vue-loader');
const path = require('path');

module.exports = {
    mode: "development",
    devtool: 'eval', 
    resolve: {
        extensions: ['.js', '.vue']
    },
    entry: {
        app: path.join(__dirname, 'main.js')
    },
    module: {
        rules: [
        {
            test: /\.vue$/,
            use: 'vue-loader'
        }, {
            test: /\.css$/,  
            use:[
                'vue-style-loader', 
                'css-loader'
            ] 
        }]
    },
    plugins: [
        new VueLoaderPlugin(), 
    ],
    output: {
        filename: '[name].js',
        path: path.join(__dirname, 'dist'),
    },
};

 

  • module과 plugins의 차이점은?
    • module웹팩의 대부분의 역할을 한다. 
      • (웹팩은 자바스크립트  코드를 모두 합쳐주는 역할을 하는데 ".vue " 같은 파일들까지도 자바스크립트로 만들어준다.)
      • loader는 자바스크립트가 아닌 파일들을 자바스크립트로 바꿔준다. 
    • plugin은 다른 부가적인 역할
  • css 영역 안에 있는 "screen"은 특정한 영역의 이름을 나타낸다. id가 screen인 곳을 찾아서 css를 적용한다. 
<hide/>
<template>
  <div>
    <div id = "screen" v-bind:class="state">{{message}}</div>
    <div>
      <div>평균 시간: {{}}</div>
      <button @click="onReset">리셋</button>
    </div>

  </div>
</template>

<script>
  
export default {
  data() {
    return {
      result: [],
      state: 'waiting',
      message: '클릭해서 시작하세요.'
    }
  },
  methods: {
   
  }
};
</script>
<style>
  #screen { 
    width: 300px;
    height: 200px;
    text-align: center;
    user-select: none;
  }

  #screen.waiting { 
    background-color:aqua;
  }

  #screen.ready { 
    background-color:red;
    color: white;
  }

  #screen.now { 
    background-color:greenyellow;
  }

</style>

 

  Note) 실행 결과

 

  • 컴포넌트의 특성
    • 재사용할 수 있기 때문에 CSS 내용을 공유한다. 
    • style 영역 안에 "#screen"을 붙이면 다른 컴포넌트에서도 id가 screen 인 부분에 css를 적용할 수 있다. 

 

  •  <style scoped> 
    • 만약, style 태그 안에 scoped 붙이면 <style scoped> 해당 컴포넌트에서만 css 내용을 쓸 수 있고 다른 컴포넌트에서는 사용 불가능하다. 

webpack-dev-server

  • 클릭할 때마다 화면 바꿔주는 이벤트 만들기
    • waiting 상태이면 'now' 로 상태 바꿔주기
    • 클릭할 때마다 state가 바뀐다.
<hide/>
<template>
  <div>
    <div id="screen" :class="state" @click="onClickScreen">{{ message }}</div>
    <div>
      <div>평균 시간: {{}}</div>
      <button @click="onReset">리셋</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      result: [],
      state: "waiting",
      message: "클릭해서 시작하세요.",
    };
  },
  methods: {
    onReset() {},
    onClickScreen() {
      if (this.state === "waiting") {
        this.state = "ready";
      } else if (this.state === "ready") {
        this.state = "now";
      } else if (this.state === "now") {
        this.state = "waiting";
      }
    },
  },
};
</script>
<style>
#screen {
  width: 300px;
  height: 200px;
  text-align: center;
  user-select: none;
}

#screen.waiting {
  background-color: aqua;
}

#screen.ready {
  background-color: red;
  color: white;
}

#screen.now {
  background-color: greenyellow;
}
</style>

 

  Note) 실행 결과

  • 클릭할 때마다 v-bind class가 바뀌므로 state가 바뀌기 때문에 색이 바뀐다. 


  Ex) Webpack dev server 세팅 - 새로 고침을 생략하고 싶은 경우

 

  • 자동으로 업데이트, 빌드, 새로고침 모두 생략할 수 있어서 편리하다.. 
  • npm i -D webpack-dev-server 입력한다. 
  • webpack watch의 진화판이라고 볼 수 있다. 

 

  • package.json 파일에 다음과 같이 "dev" : "webpack-sev-server --hot"를 추가한다. 
    • hot를 추가해야  기능 추가한 다음에 새로 고침할 필요도 없다. 
"scripts": {
"build": "webpack --watch",
"dev" : "webpack-sev-server"
},

 

  Note) 실행 결과

  • 그럼 이제 코드를 수정하면 새로 고침할 필요 없이 바로 서버에 반영된다. 

 

 

  • webpck.config 파일의 output 영역에 publicPath를 다음과 같이 추가해준다. 
    •  publicPath: 
output: {
    filename: "[name].js",
    path: path.join(__dirname, "dist"),
    publicPath: '/dist'
},

반응 속도 체크 게임 완성하기

 result.reduce((a, c) =>  a + c, 0)
  • 클릭했을 때 바로 setTimeOut()으로 반응 속도를 재려고 한다. 
  • 시작 시간, 클릭 시간 두 값이 필요하다. 차이가 반응 속도 
    • startTime: 화면이 보여진 시간
    • endTime: 클릭한 시간
    • startTime과  endTime을 data{} 영역에 넣지 않는 이유는?
    • => 화면과 관련 없기 때문이다. 
  • result 배열에는 반응 속도를 모두 저장해서 평균을 내려고한다. 
  • 배열의 값 모두 더하려면?
    •  result.reduce((a, c) =>  a + c, 0) 
  • 기본 값은 0으로 세팅 " || 0 "
<hide/>
<template>
  <div>
    <div id="screen" :class="state" @click="onClickScreen">{{ message }}</div>
    <div>
      <div>평균 시간: {{ result.reduce((a, c) => a + c, 0) / result.length || 0}}ms</div>
      <button @click="onReset">리셋</button>
    </div>
  </div>
</template>
<script>
let startTime = 0;
let endTime = 0;
export default {
  data() {
    return {
      result: [],
      state: "waiting",
      message: "클릭해서 시작하세요.",
    };
  },
  methods: {
    onReset() {},
    onClickScreen() {
      if (this.state === "waiting") {
        this.state = "ready";
        this.message = "초록색이 되면 클릭하세요";
        timeout = setTimeout(() => {
          this.state = "now";
          this.message = "지금 클릭!!";
          startTime = new Date();
        }, Math.floor(Math.random() * 1000 ) + 2000);
      } else if (this.state === "ready") {
        clearTimeout(timeout);
        this.state = "waiting";
        this.message = "너무 성급하시군요! 초록색이 된 후에 클릭하세요";
      } else if (this.state === "now") {
        endTime = new Date();
        this.state = "waiting";
        this.message = "클릭해서 시작하세요";
        this.result.push(endTime - startTime);
      }
    },
  },
};
</script>
<style>
#screen {
  width: 300px;
  height: 200px;
  text-align: center;
  user-select: none;
}

#screen.waiting {
  background-color: aqua;
}

#screen.ready {
  background-color: red;
  color: white;
}

#screen.now {
  background-color: greenyellow;
}
</style>

 

  Note) 실행 결과


computed와 v-show, template

  • 그런데, 앞에서 템플릿 태그 안에서 평균 계산하는 코드를 넣었는데 이 부분은 data{} 영역으로 다음과 같이 이동하는 게 적합하다. 
  • 일반 데이터를 가공할 때는 보통 computed를 쓴다. 
  • 굳이 data {} 영역으로 옮겼을 때의 장점은?
    • 캐싱이 되기 때문에 효율적이다.
    • 만약, 템플릿 영역 안에서  result는 그대로인데 message가 바뀌는 경우라면? 템플릿 영역이 재실행되고 따라서 평균값을 구하는 계산이 다시 수행된다. 
    • 성능에 영향을 주는 요소이므로 중요하다. 
    • 따라서 데이터가 가공되는 부분이라면 template 영역이 아닌 data 영역 안에서 실행하도록 한다. 

v-show와 v-if 차이점은?

  • v-show
    • 아래 사진과 같이 style = "display:none"
    • 클릭 전에는 "평균 시간" 내용이 안 보인다. 

클릭 전
클릭 후

  • v-if
    • 아까와는 다르게 style = "display:none" 태그가  사라졌다. 
    • 태그의 유무는 전체 레이아웃에 아주 큰 영향을 준다. 
    • 태그가 완전히 필요없는 경우에 v-if를 쓴다. 
    • 보통, v-if를 더 많이 쓴다. (나중에 v-else-if도 쓸 수 있다.)


Note

  •  content

찾아보기

  •  content

 

출처 - https://www.inflearn.com/course/web-game-vue/dashboard