https://github.com/loy124/Vue/tree/master/틱택토Vuex
store을 활용해서 데이터를 모두 vuex store에 저장하고
root파트인 TicTacToe.vue에서 해당 데이터를 불러오는 방식이다
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//Vue.use 를 사용할때마다 $axios등 기능들이 추가되는 방식
//mutation의 이름들을 변수로 빼고 export 한다
//오타확률을 줄이기위해 이렇게 변수로 빼둔것
export const SET_WINNER = 'SET_WINNER';
export const CLICK_CELL = 'CLICK_CELL';
export const CHANGE_TURN = 'CHANGE_TURN';
export const RESET_GAME = 'RESET_GAME';
export const NO_WINNER = 'NO_WINNER';
//export default는 아무렇게 이름을 통해 가져올수 있으나 import store from './store
//export const 는 import {SET_WINNER} from ./store 등 중괄호를 사용해서 원래 이름을 통해서만 불러올 수 있다.
export default new Vuex.Store({
state: {
tableData: [
['', '', ''],
['', '', ''],
['', '', ''],
],
turn: 'O',
winner: '',
}, //vue의 data와 유사
getters: {
// vue의 computed와 유사
// turnMessage(state) {
// return state.turn + '님이 승리하셨습니다.';
// },
},
mutations: {
//대문자로 정하는게 Vue 커뮤니티의 규칙
[SET_WINNER](state, winner) {
state.winner = winner;
},
// SET_WINNER(state, winner) {
// state.winner = winner;
// },
[CLICK_CELL](state, { row, cell }) {
// state.tableData[row][cell] = state.turn;
//Vuex는 this.$set이 없다
Vue.set(state.tableData[row], cell, state.turn);
},
[CHANGE_TURN](state) {
state.turn = state.turn === 'O' ? 'X' : 'O';
},
[RESET_GAME](state) {
state.turn = 'O';
state.tableData = [
['', '', ''],
['', '', ''],
['', '', ''],
];
},
[NO_WINNER](state) {
state.winner = '';
},
}, // state를 수정할 때 사용 (동기적으로)
actions: {}, // 비동기를 사용할때, 또는 여러 mutation을 연달아 실행할때
});
TicTacToe.vue
<template>
<div>
<div>{{ turn }}님의 턴입니다.</div>
<!-- <table-component></table-component> -->
<table>
<tr
v-for="(rowData, rowIndex) in tableData"
:key="rowIndex"
:rowData="rowData"
>
<td
v-for="(cellData, cellIndex) in rowData"
@click="onClickTd(rowIndex, cellIndex, cellData)"
:key="cellIndex"
>
{{ cellData }}
</td>
</tr>
</table>
<div v-if="winner">{{ winner }}님의 승리!</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import store, {
RESET_GAME,
SET_WINNER,
CHANGE_TURN,
CLICK_CELL,
NO_WINNER,
} from './store';
// import TableComponent from './TableComponent';
export default {
store,
data() {
return {
data: 1,
};
},
computed: {
//화살표 함수는 this 사용불가 일반함숨나 this 사용가능
// winner: {
// get: function() {
// return this.$store.state.winner;
// },
// set: function() {},
// },
...mapState(['winner', 'turn', 'tableData']),
// ...mapState([{
// winner : state => state.winner,
// turnState: 'turn',
// winner(state){
// return state.winner + this.data;
// }
// }]),
// winner() {
// return this.$store.state.winner;
// },
// turn() {
// return this.$store.state.turn;
// },
},
methods: {
onClickTd(rowIndex, cellIndex, cellData) {
//this.$set으로 일치화해주는 작업을 실시한다
// 또한 인덱스를 여러번 쓰는경우 마지막 index를 key로 하면 된다
if (cellData) return;
//이벤트버스의 $on(this.onclickTd)
// this.$set(this.tableData[rowIndex], cellIndex, this.turn);
//뮤테이션을 부를때 commit을 사용한다
//오타 방지를 위한 변수명 호출
this.$store.commit(CLICK_CELL, {
row: rowIndex,
cell: cellIndex,
});
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.$store.commit(SET_WINNER, this.turn);
this.$store.commit(RESET_GAME);
} else {
//무승부일때
let all = true; //all이 true면 무승부
//무승부 검사
this.tableData.forEach(row => {
//2차원 배열이니 두번 forEach 실행
row.forEach(cell => {
// 칸이 비어있는경우면 all = false
if (!cell) {
all = false;
}
});
});
//무승부일때 값 초기화
if (all) {
this.$store.commit(NO_WINNER);
this.turn = 'O';
this.$store.commit(RESET_GAME);
//무승부가 아니므로 턴만 넘긴다
} else {
// this.turn = this.turn === 'O' ? 'X' : 'O';
this.$store.commit(CHANGE_TURN);
}
}
},
},
};
</script>
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
width: 40px;
height: 40px;
text-align: center;
}
</style>
슬롯 활용해보기
TicTacto.vue
tableComponet를 넣었다.
<template>
<div>
<div>{{ turn }}님의 턴입니다.</div>
<!-- <table-component></table-component> -->
<table-component>
<!-- 슬롯 활용의 장점: 부모 컴포넌트에 함수들을 다 모아두었는데
해당 함수들을 사용함과 동시에 렌더링은 TableComponent에서 되게 하는 장점-->
<tr
v-for="(rowData, rowIndex) in tableData"
:key="rowIndex"
:rowData="rowData"
>
<td
v-for="(cellData, cellIndex) in rowData"
@click="onClickTd(rowIndex, cellIndex, cellData)"
:key="cellIndex"
>
{{ cellData }}
</td>
</tr>
</table-component>
<div v-if="winner">{{ winner }}님의 승리!</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import TableComponent from './TableComponent';
import store, {
RESET_GAME,
SET_WINNER,
CHANGE_TURN,
CLICK_CELL,
NO_WINNER,
} from './store';
// import TableComponent from './TableComponent';
export default {
store,
components: {
TableComponent,
},
data() {
return {
data: 1,
};
},
computed: {
//화살표 함수는 this 사용불가 일반함숨나 this 사용가능
// winner: {
// get: function() {
// return this.$store.state.winner;
// },
// set: function() {},
// },
...mapState(['winner', 'turn', 'tableData']),
// ...mapState([{
// winner : state => state.winner,
// turnState: 'turn',
// winner(state){
// return state.winner + this.data;
// }
// }]),
// winner() {
// return this.$store.state.winner;
// },
// turn() {
// return this.$store.state.turn;
// },
},
methods: {
onClickTd(rowIndex, cellIndex, cellData) {
//this.$set으로 일치화해주는 작업을 실시한다
// 또한 인덱스를 여러번 쓰는경우 마지막 index를 key로 하면 된다
if (cellData) return;
//이벤트버스의 $on(this.onclickTd)
// this.$set(this.tableData[rowIndex], cellIndex, this.turn);
//뮤테이션을 부를때 commit을 사용한다
//오타 방지를 위한 변수명 호출
this.$store.commit(CLICK_CELL, {
row: rowIndex,
cell: cellIndex,
});
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.$store.commit(SET_WINNER, this.turn);
this.$store.commit(RESET_GAME);
} else {
//무승부일때
let all = true; //all이 true면 무승부
//무승부 검사
this.tableData.forEach(row => {
//2차원 배열이니 두번 forEach 실행
row.forEach(cell => {
// 칸이 비어있는경우면 all = false
if (!cell) {
all = false;
}
});
});
//무승부일때 값 초기화
if (all) {
this.$store.commit(NO_WINNER);
this.turn = 'O';
this.$store.commit(RESET_GAME);
//무승부가 아니므로 턴만 넘긴다
} else {
// this.turn = this.turn === 'O' ? 'X' : 'O';
this.$store.commit(CHANGE_TURN);
}
}
},
},
};
</script>
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
width: 40px;
height: 40px;
text-align: center;
}
</style>
슬롯 활용의 장점: 부모 컴포넌트에 함수들을 다 모아두었는데
해당 함수들을 사용함(데이터를 한곳에서 관리한다
TableComponet.vue
<template>
<table>
<slot>
<!-- 테이블 컴포넌트에 아무값도 안들어갔으면 슬롯 안에있는 기본값이 들어간다 -->
<tr>
<td></td>
</tr>
</slot>
</table>
</template>
<script>
export default {};
</script>
'Vue > vue 기초 공부하기' 카테고리의 다른 글
vue-router API 이해해보기 (0) | 2020.03.21 |
---|---|
MVVM 모델의 ViewModel에 다해 알아보기 (0) | 2020.03.08 |
Vue로 틱택토 만들기(EventBus 활용) (0) | 2020.02.22 |
Vue로 틱택토 만들기( $root.data를 활용) (0) | 2020.02.22 |
로또 번호 생성 프로그램 만들기 (props, component 활용) (0) | 2020.01.26 |