效果如图:
具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body{
padding: 0;
margin: 0;
height: 100vh;
}
#app{
height: 100vh;
}
.border{
width: 300px;
height: 300px;
border: 1px solid #000;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
display: flex;
flex-wrap: wrap;
}
.box{
width: 100px;
height: 100px;
box-sizing: border-box;
border: 1px solid #000;
position: relative;
}
.box.circle::after,.box.cross::after{
position: absolute;
content: "o";
line-height: 100px;
text-align: center;
width: 100px;
height: 100px;
font-size: 5em;
color: yellowgreen;
animation: ani .5s forwards;
}
.box.cross::after{
content: "x";
color: red;
}
@keyframes ani{
0%{
opacity: 0;
transform: rotateY(645deg) scale(0);
}
100%{
opacity: 1;
transform: rotateY(0deg) scale(1);
}
}
.title{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, .4);
z-index: 99;
display: flex;
justify-content: center;
align-items: center;
}
.title center{
width: 300px;
height: 300px;
background-color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.title .center span{
color: red;
display: inline-block;
margin-bottom: 20px;
}
.fade-enter,.fade-leave-to{
opacity: 0;
}
.fade-enter-active,.fade-leave-active{
transition: opacity .5s;
}
</style>
</head>
<body>
<div id="app">
<div class="border">
<div class="box" v-for="(item,index) in sections" :key='index' @click='draw(index)' :class="{circle:item === 1,cross:item === 10}"></div>
</div>
<transition name="fade">
<div class="title" v-if="checkWinner">
<div class="center">
<span>{{checkWinner}} Win!</span>
<button @click="reset">Reset</button>
</div>
</div>
</transition>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.js"></script>
<script>
(function(Vue){
let vm = new Vue({
el:"#app",
data(){
return{
sections: [0, 0, 0, 0, 0, 0, 0, 0, 0],
step: 0
}
},
methods:{
draw(index){
if(this.sections[index] === 0){
this.$set(this.sections, index, this.step % 2 === 0 ? 1 : 10)
this.step++
}
},reset(){
this.step = 0;
this.sections = [0, 0, 0, 0, 0, 0, 0, 0, 0]
}
},
computed:{
status(){
return[
this.sections[0] + this.sections[1] + this.sections[2],
this.sections[3] + this.sections[4] + this.sections[5],
this.sections[6] + this.sections[7] + this.sections[8],
this.sections[1] + this.sections[4] + this.sections[7],
this.sections[2] + this.sections[5] + this.sections[8],
this.sections[0] + this.sections[3] + this.sections[6],
this.sections[0] + this.sections[4] + this.sections[8],
this.sections[2] + this.sections[4] + this.sections[6]
]
},
checkWinner(){
let winner;
if(this.step >= 5){
winner = this.status.find(item =>{
return item === 3 || item === 30
}) || null;
}
if(winner === 3){
winner = 'Circle'
}else if(winner === 30){
winner = 'Cross'
}else if(winner = null && this.step > 8){
winner = "平局 :Nobody!"
}
return winner;
}
}
})
})(Vue)
</script>
</body>
</html>