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/~ 。使用相對地址獲取不到。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章