创建两个文件,一个是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/~ 。使用相对地址获取不到。