0

I'm making a Tic-Tac-Toe web app. It isn't finished yet as this problem has thrown up a road block. When either X or O wins, it should turn the 3 winning boxes green (this part works if I remove the transition that I want to happen after that). Once the boxes are green, the entire 'Board' table should 'bounce out'. But what's actually happening is that the 'Board' is bouncing out before the 'mark' (X/O) is even shown and the winning boxes turned green. What's not making sense to me is that the focus of the code execution should be from top to bottom but it doesn't appear to be behaving like that. I've tried rearranging the code several different ways and still no luck.

Here is the Codepen

And here is the code for those who don't want to click the link :P (Sorry for the styling, the code snippet doesn't want to work correctly =/

BTW, thanks in advance!

console.clear();
const log = console.log.bind(console);

const game = new Vue({
	el: '#app',
	data: {
		turn: 'X',
		over: false,
		board: [[{val:'',bg:''}, {val:'',bg:''}, {val:'',bg:''}],
					  [{val:'',bg:''}, {val:'',bg:''}, {val:'',bg:''}],
					  [{val:'',bg:''}, {val:'',bg:''}, {val:'',bg:''}]],
		windex: [[[0,0], [0,1], [0,2]],
						 [[1,0], [1,1], [1,2]],
						 [[2,0], [2,1], [2,2]],
						 [[0,0], [1,0], [2,0]],
						 [[0,1], [1,1], [2,1]],
						 [[0,2], [1,2], [2,2]],
						 [[0,0], [1,1], [2,2]],
						 [[0,2], [1,1], [2,0]]],
		check() {
			const arr = this.board.map( x => x.map( y => y.val ));
			const winArr = this.windex.map( x => x.map( y => this.board[y[0]][y[1]].val ));
			const winner = winArr.map( (x,ind) => {
				if( x.every( y => y == 'X' )) return 'X';
				if( x.every( y => y == 'O' )) return 'O';
			});
			if(winner.includes('X')){
				const inds = this.windex[winner.indexOf('X')];
				inds.forEach( x => {
					this.board[x[0]][x[1]].bg = 'active';
				});
				this.over = true;
			};
			if(winner.includes('O')){
				const inds = this.windex[winner.indexOf('O')];
				inds.forEach( x => {
					this.board[x[0]][x[1]].bg = 'active';
				});
				this.over = true;
			};
			if(arr.every( x => x.every( y => y == 'X' || y == 'O' )))
				this.over = true;
		}
	},
	methods: {
		mark(box) {
			if(this.over) return
			if(box.val === ''){
				box.val = this.turn;
				this.turn = this.turn == 'X' ? 'O' : 'X';
			} else 
					alert('Invalid turn')
				this.check()
		}
	}
});
@import 'https://fonts.googleapis.com/css?family=Oswald';

h1 {
	font-family: 'Oswald';
	letter-spacing: 1.5vw;
	text-align: center;
	margin:1vw;
}

table {
	margin-left: auto;
	margin-right: auto;
	border-collapse: separate;
	border-spacing: 2px;
}

.square {
	width: 100px;
	height: 100px;
	background-color: #6C7A89;
	text-align: center;
	color: white;
	cursor: pointer;
	text-align: center;
	line-height: 100px;
	font-size: 50px;
	font-family: 'Oswald';
	display: block;
}

.square:hover {
	opacity: .8;
}

td {
	vertical-align: middle;
}

.active {
	background-color: #00B16A;
}

.bounce-leave-active {
  animation: bounce-out 1.5s;
}

@keyframes bounce-out {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(0);
  }
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script>

<div id='app'>
	<h1>TIC-TAC-TOE</h1>
	<transition name='bounce'>
	<table v-if='!over'>
		<tr v-for='row in board'>
			<td v-for='box in row'>
				<div class='square' 
						 v-bind:class='{active:box.bg}' 
						 v-on:click='mark(box)'>
					{{box.val}}
				</div>
			</td>
		</tr>
	</table>
	</transition>
</div>

4

1 に答える 1

0

コードはブロックとして実行されます。activeUI は設定との間で再描画されないoverため、UI に関する限り、それらは同時に効果的に行われます。はバインディングをoverトリガーするv-ifため、コンテンツは再描画されず、遷移するだけです。

Vue はnextTick、物事を順序付けできるようにします。のようsetTimeout(..., 0)に、コマンドをブロックから取り出しますが、実行前に DOM の更新サイクルが確実に行われるようにします。

于 2016-10-07T13:15:12.403 に答える