vue拼图实现
Vue 拼图实现方案
核心思路
通过动态渲染拼图块数组,利用拖拽或点击交换逻辑实现拼图功能。关键点在于拼图块的随机排列、位置计算和交互逻辑。
基础实现步骤
初始化拼图数据
data() {
return {
rows: 3, // 行数
cols: 3, // 列数
pieces: [], // 拼图块数组
emptyPos: { x: 2, y: 2 } // 空白块位置
}
},
created() {
this.initPuzzle()
}
拼图初始化方法
methods: {
initPuzzle() {
const total = this.rows * this.cols - 1
this.pieces = Array.from({ length: total }, (_, i) => ({
id: i + 1,
x: i % this.cols,
y: Math.floor(i / this.cols)
}))
this.shufflePieces()
}
}
随机打乱拼图
shufflePieces() {
for (let i = this.pieces.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.pieces[i].x, this.pieces[j].x] = [this.pieces[j].x, this.pieces[i].x]
[this.pieces[i].y, this.pieces[j].y] = [this.pieces[j].y, this.pieces[i].y]
}
}
点击交换逻辑
handleClick(piece) {
const dx = Math.abs(piece.x - this.emptyPos.x)
const dy = Math.abs(piece.y - this.emptyPos.y)
if ((dx === 1 && dy === 0) || (dx === 0 && dy === 1)) {
[piece.x, this.emptyPos.x] = [this.emptyPos.x, piece.x]
[piece.y, this.emptyPos.y] = [this.emptyPos.y, piece.y]
this.checkComplete()
}
}
进阶优化方案
使用拖拽库实现
安装vuedraggable:
npm install vuedraggable
组件实现示例
<template>
<draggable
v-model="pieces"
:group="{ name: 'puzzle' }"
@end="onDragEnd"
class="puzzle-container">
<div v-for="piece in pieces" :key="piece.id" class="puzzle-piece">
{{ piece.id }}
</div>
</draggable>
</template>
图片拼图实现 需要将图片分割后作为拼图块背景:
getPieceStyle(piece) {
return {
backgroundImage: `url(${this.puzzleImage})`,
backgroundPosition: `-${piece.x * 100}px -${piece.y * 100}px`,
backgroundSize: `${this.cols * 100}px ${this.rows * 100}px`
}
}
完整示例组件
<template>
<div class="puzzle-game">
<div
v-for="piece in pieces"
:key="piece.id"
class="puzzle-piece"
:style="{
left: `${piece.x * 100}px`,
top: `${piece.y * 100}px`
}"
@click="handleClick(piece)">
{{ piece.id }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
rows: 3,
cols: 3,
pieces: [],
emptyPos: { x: 2, y: 2 }
}
},
created() {
this.initPuzzle()
},
methods: {
initPuzzle() {
const total = this.rows * this.cols - 1
this.pieces = Array.from({ length: total }, (_, i) => ({
id: i + 1,
x: i % this.cols,
y: Math.floor(i / this.cols)
}))
this.shufflePieces()
},
shufflePieces() {
for (let i = this.pieces.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.pieces[i].x, this.pieces[j].x] = [this.pieces[j].x, this.pieces[i].x]
[this.pieces[i].y, this.pieces[j].y] = [this.pieces[j].y, this.pieces[i].y]
}
},
handleClick(piece) {
const dx = Math.abs(piece.x - this.emptyPos.x)
const dy = Math.abs(piece.y - this.emptyPos.y)
if ((dx === 1 && dy === 0) || (dx === 0 && dy === 1)) {
[piece.x, this.emptyPos.x] = [this.emptyPos.x, piece.x]
[piece.y, this.emptyPos.y] = [this.emptyPos.y, piece.y]
this.checkComplete()
}
},
checkComplete() {
const isComplete = this.pieces.every(p =>
p.x === (p.id - 1) % this.cols &&
p.y === Math.floor((p.id - 1) / this.cols)
)
if (isComplete) alert('拼图完成!')
}
}
}
</script>
<style>
.puzzle-game {
position: relative;
width: 300px;
height: 300px;
border: 1px solid #ccc;
}
.puzzle-piece {
position: absolute;
width: 100px;
height: 100px;
background: #eee;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
transition: all 0.3s;
}
</style>






