Vue做一个简单的井字棋小游戏

1,503 阅读3分钟

前置

创建一个文件夹,打开编辑器,后台输入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…