前置
创建一个文件夹,打开编辑器,后台输入vue create . 当前目录下创建vue项目。功能比较单一,只选择babel就好了。上下移动,空格选择,回车确定。
是用分开的配件,还是全写在package里?第二个
要把刚才的配置保存下来以备日后用吗?建议不要
用yarn还是npm?yarn
设置好后回车等待,success成功就行了。运行yarn serve得到端口,复制在浏览器中打开就能看到页面了。
下面简单分析一下需求,我们要做的游戏长这样↓,画一个叉,下一次点击是画圈,当三个同样的符号连成排时,游戏结束。
如果你没思路,我们可以把这个功能作个拆分,直至简化成一个框,框里能画叉。
开始写代码
我们先让它点击空处,出现 X 吧。用 if else 来做数据的切换。
也可以用 template 代替 div,因为 template 最终会消失的(template不支持onclick事件!)
但是我们有9个格子,要复制9遍代码吗??必然不行啊,onclick绑定的都是一样的数据,一点击就会全部一起变X了,莫非要给每个编编号a1,a2吗?就很傻,这时就需要组件化了。
在src里创建一个Cell.vue的页面,把刚才的代码都复制过去,再在原先app.vue里引入进来。
这样每个格子都是独立的不会冲突,每个cell都有自己的a。
只会画x是不行的,我们需要点第一下是 x,下一次点击是o,如何确定是点 x 还是点 o 呢?我们得让这个 x 是可变的,还要随着用户点击的次数不同而变。
Vue组件通信
怎么能让这些组件知道自己该显示什么?
我们先在一个框里实验下:监听这个click
同时在组件里通知外面‘我被点了’
这就是监听事件,在外面写on:click,在组件里面写$emit('click')
加了点击监听,还要给每个cell加个号码 n。
给每个cell绑定一个 n,并且在Cell组件里获取这个 n 的值,这样每次点击时组件间就互相知道自己的值是多少,从而计算是该显示 x 还是 o 。
用bing传值,对方就要用props接收。
所有的v-on:click都可以缩写成@click,所有的v-bing也可以简略缩写成:n="n"
让text的值根据n来确定
这里如果用vue的计算属性computed的话,确实可以点一下是x,下次点是o,但是会一变全部一起变。因为n变了text就变了,不符合需求。
computed:{
text(){
return this.n % 2 === 0 ? "x" :"o"
}
}
所以还是不用上面的,把text值变成 '',且应该在点击的时候确定text的值
methods:{
onClickSelf(){
this.a=true
this.text = this.n % 2 === 0 ? "x" : "o"
this.$emit('click') //通知外面我被点了
}
}
每次点击再计算值,这样子就可以实现点下是x,下一次是o。
到此这部分的功能是基本实现了,不过还是有bug,一个格子里竟然可以重复点击,重复变值。所以我们还没有结束。 加个判断,如果格子里已经有x或o就不再接受点击。
if(this.text !== ''){
return
}
判断用户是否赢了
如何判断用户赢了?还是需要给每个cell加个序号。这里的函数并不会立即执行,而是在用户点击后才执行
<div >
<div class="row">
<Cell @click="onClickCell(0)" :n="n"/>
<Cell @click="onClickCell(1)" :n="n"/>
<Cell @click="onClickCell(2)" :n="n"/>
</div>
.......
</div>
...........
methods:{
onClickCell(i){
console.log(`${i}号被点击`)
this.n+=1
}
}
试验一下:
ok,我们还要知道被点击的格子是x还是o?
this.$emit('click',this.text) //通知外面我被点了,且告诉外面自己是x还是o
在组件里,我们需要用$emit 把text的值也传出去。同时在外面对应的地方,用$event接收传进来的text值。
<div class="row">
<Cell @click="onClickCell(0,$event)" :n="n"/>
<Cell @click="onClickCell(1,$event)" :n="n"/>
<Cell @click="onClickCell(2,$event)" :n="n"/>
</div>
.....
methods:{
onClickCell(i,text){
console.log(`${i}号被点击,内容是:${text}`)
this.n+=1
}
}
接下来用数组把它存下来,知道了是谁点击的,就把数据放在map里,当被点击时,map对应位置的值就会被改变成x或o。再调用tell判断输赢。
data(){
return {
n:0,
map:[
[null,null,null],
[null,null,null],
[null,null,null],
]
}
},
methods:{
onClickCell(i,text){
console.log(`${i}号被点击,内容是:${text}`)
this.map[Math.floor(i/3)][i%3] = text
this.n+=1
this.tell()
},
tell(){
const map = this.map
for(let i=0;i<2;i++){
if(map[i][0] !== null && map[i][0] === map[i][1] && map[i][1] === map[i][2]){
this.result = map[i][0]
}
}
for(let j=0;j<2;j++){
if(map[0][j] !== null && map[0][j] === map[1][j] && map[1][j] === map[2][j]){
this.result = map[0][j]
}
}
if(map[0][0] !== null && map[0][0] === map[1][1] && map[1][1] === map[2][2]){
this.result = map[0][0]
}
if(map[0][2] !== null && map[0][2] === map[1][1] && map[1][1] === map[2][0]){
this.result = map[0][2]
}
}
}
循环遍历判断横向和纵向,判断交叉向是否有连在一起一样的值,有则true,相连的一方赢。
如果你想看源码,可以查看:github.com/VHJFKDS/Tic…