본문 바로가기

Vue/vue 기초 공부하기

Vue로 틱택토 만들기(EventBus 활용)

https://loy124.tistory.com/185

 

Vue로 틱택토 만들기( $root.data를 활용)

https://github.com/loy124/Vue/tree/master/틱택토 loy124/Vue Vue 공부. Contribute to loy124/Vue development by creating an account on GitHub. github.com 일일히 props에 데이터를 넘겨주는 방식에 굉장..

loy124.tistory.com

위 코드와 거의 유사하나 EventBus를 활용하여 중앙 통제 함수를 만들어서 활용한다

 

EventBus는 함수를 중앙통제 관리하고

 

Vuex는 데이터를 중앙통제 관리하는점이 차이라고 한다 

 

빈 껍데기인 EventBus.js를 만들어준다 

import Vue from 'vue';

export default new Vue();

 

 

기존의 TdComponent.vue

 

 

 

<template>
  <td @click="onClickTd">{{ cellData }}</td>
</template>

<script>
export default {
  props: {
    cellData: String,
    rowIndex: Number,
    cellIndex: Number,
  },
  methods: {
    onClickTd() {
      //root값의 데이터를 가져온다
      // console.log(this.$root.$data);
      //부모의 데이터를 가져온다
      // console.log(this.$parent.$data);
      //자식 컴포넌트에서 부모컴포넌트의 데이터를 변경할 수 있다.
      //화면에서 반영이 되지 않는다

      //부모의 데이터는 잘 변경이되는데 화면에는 그려지지 않는다
      // this.$root.$data.tableData[this.rowIndex][
      //   this.cellIndex
      // ] = this.$root.$data.turn;

      //this.$set으로 일치화해주는 작업을 실시한다
      // 또한 인덱스를 여러번 쓰는경우 마지막 index를 key로 하면 된다
      if (this.cellData) return;
      const rootData = this.$root.$data;
      this.$set(
        rootData.tableData[this.rowIndex],
        this.cellIndex,
        rootData.turn,
      );

      let win = false;
      if (
        rootData.tableData[this.rowIndex][0] === rootData.turn &&
        rootData.tableData[this.rowIndex][1] === rootData.turn &&
        rootData.tableData[this.rowIndex][2] === rootData.turn
      ) {
        win = true;
      }
      if (
        rootData.tableData[0][this.cellIndex] === rootData.turn &&
        rootData.tableData[1][this.cellIndex] === rootData.turn &&
        rootData.tableData[2][this.cellIndex] === rootData.turn
      ) {
        win = true;
      }

      //대각선
      if (
        rootData.tableData[0][0] === rootData.turn &&
        rootData.tableData[1][1] === rootData.turn &&
        rootData.tableData[2][2] === rootData.turn
      ) {
        win = true;
      }
      if (
        rootData.tableData[0][2] === rootData.turn &&
        rootData.tableData[1][1] === rootData.turn &&
        rootData.tableData[2][0] === rootData.turn
      ) {
        win = true;
      }
      //승리했을때
      if (win) {
        rootData.winner = rootData.turn;
        rootData.turn = 'O';
        rootData.tableData = [
          ['', '', ''],
          ['', '', ''],
          ['', '', ''],
        ];
      } else {
        //무승부일때
        let all = true; //all이 true면 무승부
        //무승부 검사
        rootData.tableData.forEach(row => {
          //2차원 배열이니 두번 forEach 실행
          row.forEach(cell => {
            // 칸이 비어있는경우면 all = false
            if (!cell) {
              all = false;
            }
          });
        });
        //무승부일때 값 초기화
        if (all) {
          rootData.winner = '';
          rootData.turn = 'O';
          rootData.tableData = [
            ['', '', ''],
            ['', '', ''],
            ['', '', ''],
          ];
          //무승부가 아니므로 턴만 넘긴다
        } else {
          rootData.turn = rootData.turn === 'O' ? 'X' : 'O';
        }
      }

      // console.log(rootData);
    },
  },
};
</script>

<style></style>

 

 

 

해당부분의 클릭 처리함수를 

TicTacToe.vue에 가져온다

 

TicTacToe.vue(루트부분)

빈껍데기인 EventBus를 import해주고 

 

EventBus.$on('함수이름', 실제로 사용한 함수);

방식으로 활용한다 

 

<template>
  <div>
    <div>{{ turn }}님의 턴입니다.</div>
    <table-component :table-data="tableData"></table-component>
    <div v-if="winner">{{ winner }}님의 승리!</div>
  </div>
</template>

<script>
import Vue from 'vue';
import TableComponent from './TableComponent';
import EventBus from './EventBus';
export default {
  components: {
    TableComponent,
  },
  data() {
    return {
      tableData: [
        ['', '', ''],
        ['', '', ''],
        ['', '', ''],
      ],
      turn: 'O',
      winner: '',
    };
  },

  methods: {
    //뷰에서 객체나 배열이 있고 내부의값을 인덱스로 변경하면 화면에 적용되지 않는다
    //객체로 key값을 바꾸는경우도 마찬가지
    // //push등으로 사용하면 적용이 된다
    // onChangeData(){
    //   this.tableData[0][1] = 'O';
    // }
    onChangeData() {
      //this.tableData[1][0] = 'X' 작동하지 않는다
      //Vue를 import하고 바꾸고싶은 값을 Vue.set을 사용한다
      // this.tableData[1][0]에 'X'를 넣는다
      // Vue.set(this.tableData[1], 0, 'X');
      //Vue를 import 안하더라도 해당 방식으로 해결가능하다
      // this.$set(this.tableData[1], 0, 'X');
    },
    onClickTd(rowIndex, cellIndex) {
      console.log(rowIndex, cellIndex);
      this.$set(this.tableData[rowIndex], cellIndex, this.turn);

      let win = false;
      if (
        this.tableData[rowIndex][0] === this.turn &&
        this.tableData[rowIndex][1] === this.turn &&
        this.tableData[rowIndex][2] === this.turn
      ) {
        win = true;
      }
      if (
        this.tableData[0][cellIndex] === this.turn &&
        this.tableData[1][cellIndex] === this.turn &&
        this.tableData[2][cellIndex] === this.turn
      ) {
        win = true;
      }

      //대각선
      if (
        this.tableData[0][0] === this.turn &&
        this.tableData[1][1] === this.turn &&
        this.tableData[2][2] === this.turn
      ) {
        win = true;
      }
      if (
        this.tableData[0][2] === this.turn &&
        this.tableData[1][1] === this.turn &&
        this.tableData[2][0] === this.turn
      ) {
        win = true;
      }
      //승리했을때
      if (win) {
        this.winner = this.turn;
        this.turn = 'O';
        this.tableData = [
          ['', '', ''],
          ['', '', ''],
          ['', '', ''],
        ];
      } else {
        //무승부일때
        let all = true; //all이 true면 무승부
        //무승부 검사
        this.tableData.forEach(row => {
          //2차원 배열이니 두번 forEach 실행
          row.forEach(cell => {
            // 칸이 비어있는경우면 all = false
            if (!cell) {
              all = false;
            }
          });
        });
        //무승부일때 값 초기화
        if (all) {
          this.winner = '';
          this.turn = 'O';
          this.tableData = [
            ['', '', ''],
            ['', '', ''],
            ['', '', ''],
          ];
          //무승부가 아니므로 턴만 넘긴다
        } else {
          this.turn = this.turn === 'O' ? 'X' : 'O';
        }
      }
    },
  },
  created() {
    //사용자 정의 이벤트 등록
    EventBus.$on('clickTd', this.onClickTd);
  },
};
</script>

<style scoped></style>

 

 

변경된 TdComponent.vue

 

EventBus.$emit('clickTd')를 활용하여 호출을 해준다 

 

<template>
  <td @click="onClickTd">{{ cellData }}</td>
</template>

<script>
import EventBus from './EventBus';
export default {
  props: {
    cellData: String,
    rowIndex: Number,
    cellIndex: Number,
  },
  methods: {
    onClickTd() {
      //root값의 데이터를 가져온다
      // console.log(this.$root.$data);
      //부모의 데이터를 가져온다
      // console.log(this.$parent.$data);
      //자식 컴포넌트에서 부모컴포넌트의 데이터를 변경할 수 있다.
      //화면에서 반영이 되지 않는다

      //부모의 데이터는 잘 변경이되는데 화면에는 그려지지 않는다
      // this.$root.$data.tableData[this.rowIndex][
      //   this.cellIndex
      // ] = this.$root.$data.turn;

      //this.$set으로 일치화해주는 작업을 실시한다
      // 또한 인덱스를 여러번 쓰는경우 마지막 index를 key로 하면 된다
      if (this.cellData) return;
      //이벤트버스의 $on(this.onclickTd)
      EventBus.$emit('clickTd', this.rowIndex, this.cellIndex);
      // console.log(rootData);
    },
  },
};
</script>

<style></style>

 

 

 

중앙처리를 활용해서 쉽게 처리할 수 있으나 중앙코드가 너무 길어지는 단점이있다