Vue拼图小游戏

创建两个文件,一个是App.vue,另一个是Puzzle.vue,App.vue是主文件,Puzzle.vue是子组件

<template>
    <div>
        <d-puzzle v-bind="puzzleConfig[leval]" @next="handleNext"/>
        <button @click="handleNext">next</button>
    </div>
</template>

<script>
import DPuzzle from './Puzzle';

export default {
    components:{
        DPuzzle
    },
    data(){
        return{
            leval: 0,
            puzzleConfig: [
                {row: 3, col: 3, img: './puzzleImg/a1.jpg'},
                {row: 4, col: 4, img: './puzzleImg/a2.jpg'},
                {row: 5, col: 5, img: './puzzleImg/a3.jpg'},
                {row: 8, col: 8, img: './puzzleImg/a4.jpg'}
            ]
        }
    },
    methods: {
        handleNext(){
            console.log("aaa");
            this.leval++;
            if(this.leval == this.puzzleConfig.length){
                const answerFlag = window.confirm("最后一关,再开始不?");
                if(answerFlag){
                    this.leval = 0;
                }
            }
            console.log("next");
        }
    }
}
</script>

<style>
</style>

后面是Puzzle.vue

<template>
  <div class="puzzle" :style="{width: width+'px', height: height+'px'}">
    <!-- 前面的key需要获取一个唯一值,但是后面的blockPotints里面是对象,但是唯一值不能为对象,所以这里定义了一个唯一的id
         backgroundImage这里注意需要使用反向单引号,实现代码
         backgroundPostion定义图片的位置
         最后设置一个opacity将图片中的最后一个设置为透明的
         绑定ref将前面的图片设置为block,最后一张图片设置为empty
         绑定自定义属性data-correctX和data-correctY,供下面使用-->
    <div
      class="puzzle__block"
      v-for="(item, index) in blockPoints"
      :key="item.id"
      :style="{
        width: blockWidth+'px', 
        height: blockHeight+'px',
        left: item.x+'px',
        top: item.y+'px',
        backgroundImage: `url(${img})`,
        backgroundPosition: `-${correctPoints[index].x}px -${correctPoints[index].y}px`,
        opacity: index === blockPoints.length - 1 && 0 
        }"
      @click="handleClick"
      :ref="index === blockPoints.length - 1 ? 'empty': 'block'"
      :data-correctX="correctPoints[index].x"
      :data-correctY="correctPoints[index].y"
    />
  </div>
</template>

<script>
export default {
  props: {
    width: {
      type: Number,
      default: 500
    },
    height: {
      type: Number,
      default: 500
    },
    row: {
      type: Number,
      default: 3
    },
    col: {
      type: Number,
      default: 3
    },
    img: {
      type: String,
      required: true
    }
  },
  methods: {
    /**
     * handleClick方法绑定在各个小图片上
     * 该方法主要实现的就是图片的交换,也就是点击的图片和空白图片的交换
     * 使用e获取事件,e.target获取事件对象,也就是被点击的那一个
     * 使用left,top获取被点击对象的left和top
     * 使用emptyDom获取前面绑定的ref中的空白图片,也就是empty[0]
     * 交换emptyDom和blockDom的top和left
     */
    handleClick(e) {
      const blockDom = e.target;
      const emptyDom = this.$refs.empty[0];
      const { left, top } = blockDom.style;
      //   if (!this.isAdjacent(blockDom, emptyDom)) {
      //     return;
      //   }
      blockDom.style.left = emptyDom.style.left;
      blockDom.style.top = emptyDom.style.top;
      emptyDom.style.left = left;
      emptyDom.style.top = top;
      const winFlag = this.chackWin();
      if (winFlag) {
        this.winGame(emptyDom);
        console.log("success");
      }
    },
    /**
     * 实现的主要功能是判断是否是邻近的图片,也就是逻辑中只能是相邻的图片进行交换
     * 获取block的left,top,width,height,left和top改了名字domleft,domtop
     * 获取empty的left,top,前面已经获取了width和height这里就不必再获取了
     * 判断domtop - emptytop的绝对值是不是等于width, 判断domleft - emptyleft的绝对值是不是等于height
     */
    isAdjacent(blockDom, emptyDom) {
      const { left: domleft, top: domtop, width, height } = blockDom.style;
      const { left: emptyleft, top: emptytop } = emptyDom.style;
      const xDis = Math.floor(
        Math.abs(parseFloat(domleft) - parseFloat(emptyleft))
      );
      const yDis = Math.floor(
        Math.abs(parseFloat(domtop) - parseFloat(emptytop))
      );
      const flag =
        (domleft === emptyleft && yDis === parseInt(height)) ||
        (domtop === emptytop && xDis === parseInt(width));
      return flag;
    },
    /**
     * 实现的功能主要是判断当前是否已经成功
     *
     */
    chackWin() {
      const blockDomArr = this.$refs.block;
      return blockDomArr.every(dom => {
        const { left: domLeft, top: domTop } = dom.style;
        const { correctx: correctX, correcty: correctY } = dom.dataset;
        const flag =
          parseInt(domLeft) === parseInt(correctX) &&
          parseInt(domTop) === parseInt(correctY);
        return flag;
      });
    },
    /**
     * 成功之后执行的方法
     */
    winGame(emptyDom) {
      setTimeout(() => {
        alert("成功");
        emptyDom.style.opacity = 1;
        setTimeout(() => {
          this.goToNextLeavel();
        }, 300);
      }, 300);
    },
    /**
     * 返回第一关的方法
     */
    goToNextLeavel() {
      console.log("213");
      const answerFlag = window.confirm("要玩下一关嘛?");
      if (answerFlag) {
        this.$emit("next");
      }
    }
  },
  computed: {
    // 计算当前图片的宽度
    blockWidth() {
      return this.width / this.col;
    },
    // 计算当前图片的高度
    blockHeight() {
      return this.height / this.row;
    },
    // 拿到全部的图片
    correctPoints() {
      const { row, col, blockWidth, blockHeight } = this; //es6语法,获取到this中的row,col
      const arr = [];
      for (let i = 0; i < row; i++) {
        for (let j = 0; j < row; j++) {
          arr.push({
            x: j * blockWidth,
            y: i * blockHeight,
            id: new Date().getTime() + Math.random() * 100
          });
        }
      }
      return arr;
    },
    // 返回打乱之后的图片
    blockPoints() {
      const points = this.correctPoints;
      const length = points.length;
      const lastEle = points[length - 1];
      const newArr = [...points];
      newArr.length = length - 1;
      newArr.sort(() => Math.random() - 0.5);
      newArr.push(lastEle);
      return newArr;
    }
  }
};
</script>

<style>
.puzzle {
  position: relative;
  border: 1px solid #ccc;
}
.puzzle__block {
  box-sizing: border-box;
  position: absolute;
  transition: all 0.3s;
  border: 2px solid #eeeeee;
}
</style>

这里需要注意一点,获取图片的时候,需要将图片文件放在public文件夹中,不允许直接放在外面,因为这里获取图片的时候使用的是绝对路径,也就是 8080/~ 。使用相对地址获取不到。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Feng_ye__/article/details/101064903