一起学Vue自定义组件之拼图小游戏

通过学习Vue自定义组件,可以开发一些小功能,自娱自乐,巩固学习的基础知识,本文以一个简单的拼图小游戏的例子,简述Vue自定义组件的开发,调用等基本流程,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点

关于Vue组件的基础知识,前篇已有介绍,本例涉及知识点如下:

  • 拼图游戏,只有相邻的元素才可以交换位置,那如何判断两个元素相邻,方法如下:

    • 左右相邻:y轴坐标相同,x轴相减的绝对值等于一个元素的宽度。

    • 上下相邻:x轴坐标相同,y轴相减的绝对值等于一个元素的高度。

  • 如何判断拼图中的可以与之交换位置的空白,方法如下:

    • 通过ref引用属性,将空白属性,定义为empty,其他定义为block,以便区分。

  • 如何将一张图放到每一个元素上,并只显示一块内容,方法如下:

    • 将背景图的位置和元素的坐标起始位置关联起来,即将图片的向左上方平移即可。

  • 元素之间的切换平滑过渡。在本例中,通过css样式设置,所有元素的移动都在0.3s内完成,达到平滑过渡的效果。

示例效果图

本例中拼图游戏一共分5关,分别是3*3,4*4等,难度逐级增加,所用图片的均是500px*500px大小,如下图所示:

当拼图完成时,询问是否进行下一关,如下所示:

下一关,效果如下所示:

其他效果图类似,只是分的行和列递增,拼图难度增加,但是处理逻辑都是相同的。

核心源码

关于Puzzle.vue源码,如下所示:

模板部分(template),主要是元素的布局,本例采用v-for动态加载,如下所示:

1 <template> 2   <div class="puzzle" :style="{width:width+'px',height:height+'px'}"> 3     <div 4       v-for="(item,index) in blockPoints" 5       :key="item.id" 6       :style="{width:blockWidth+'px', 7         height:blockHeight+'px', 8         left:item.x+'px',top:item.y+'px', 9         backgroundImage:`url(${img})`,10         backgroundPosition:`-${correctPoints[index].x}px -${correctPoints[index].y}px`,11         opacity: index===blockPoints.length-1 && 0 }"12       v-on:click="handleClick"13       class="puzzle__block"14       :ref="index===blockPoints.length-1?'empty':'block'"15       :data-correctX="correctPoints[index].x"16       :data-correctY="correctPoints[index].y"17     ></div>18   </div>19 </template>

View Code

脚本部分(Script),主要用于逻辑的校验和判断,如下所示:

1 <script>  2 export default {  3   props: {  4     img: {  5       // 图片路径  6       type: String,  7       required: true,  8     },  9     width: { 10       // 图片总宽度 11       type: Number, 12       default: 500, 13     }, 14     height: { 15       // 图片总高度 16       type: Number, 17       default: 500, 18     }, 19     row: { 20       // 行数 21       type: Number, 22       default: 3, 23     }, 24     col: { 25       // 列数 26       type: Number, 27       default: 3, 28     }, 29   }, 30   data() { 31     return { 32       status: { 33         type: String, 34         default: "进行中......", 35       }, 36     }; 37   }, 38   methods: { 39     handleClick(e) { 40       const blockDom = e.target; 41       const empthDom = this.$refs.empty[0]; 42       const { left, top } = blockDom.style; 43       if (!this.isAdjacent(blockDom, empthDom)) { 44         return; 45       } 46       //交换元素 47       blockDom.style.left = empthDom.style.left; 48       blockDom.style.top = empthDom.style.top; 49       empthDom.style.left = left; 50       empthDom.style.top = top; 51       const winFlag = this.winCheck(); 52       if (winFlag) { 53         //   console.log('success'); 54         this.winGame(empthDom); 55       } 56     }, 57     isAdjacent(blockDom, empthDom) { 58       // 判断是否相邻 59       const { left: blockLeft, top: blockTop, width, height } = blockDom.style; 60       const { left: emptyLeft, top: emptyTop } = empthDom.style; 61       const xDis = Math.floor( 62         Math.abs(parseFloat(blockLeft) - parseFloat(emptyLeft)) 63       ); 64       const yDis = Math.floor( 65         Math.abs(parseFloat(blockTop) - parseFloat(emptyTop)) 66       ); 67       const flag = 68         (blockLeft === emptyLeft && yDis === parseInt(height)) || 69         (blockTop === emptyTop && xDis === parseInt(width)); 70       console.log(flag); 71       return flag; 72     }, 73     winCheck() { 74       // 判断是否完成 75       const blockDomArr = this.$refs.block; 76       return blockDomArr.every((dom) => { 77         const { left: domLeft, top: domTop } = dom.style; 78         const { correctx: correctX, correcty: correctY } = dom.dataset; 79         const flag = 80           parseInt(domLeft) === parseInt(correctX) && 81           parseInt(domTop) === parseInt(correctY); 82         return flag; 83       }); 84       // console.log(blockDomArr.length); 85     }, 86     winGame(empthDom) { 87       //通关 88       setTimeout(() => { 89         this.status = "胜利"; 90         alert("恭喜通关"); 91         empthDom.style.opacity = 1; 92         this.$emit("getStatus"); 93         setTimeout(() => { 94           this.goToNextLevel(); 95         }, 300); 96       }, 300); 97     }, 98     goToNextLevel() { 99       const answerFlag = window.confirm("现在进行下一关么?");100       if (answerFlag) {101         this.status = "进行中......";102         this.$emit("next");103       }104     },105   },106   computed: {107     blockWidth() {108       return this.width / this.col;109     },110     blockHeight() {111       return this.height / this.row;112     },113     correctPoints() {114       const { row, col, blockWidth, blockHeight } = this;115       const arr = [];116       for (let i = 0; i < row; i++) {117         for (let j = 0; j < col; j++) {118           arr.push({119             x: j * blockWidth,120             y: i * blockHeight,121             id: new Date().getTime() + Math.random() * 100,122           });123         }124       }125       return arr;126     },127     blockPoints() {128       const points = this.correctPoints;129       const length = points.length; //数组的长度130       const lastEle = points[length - 1]; //最后一个元素131       const newArr = [...points];132       newArr.length = length - 1;133       //打乱顺序134       newArr.sort(() => Math.random() - 0.5);135       newArr.push(lastEle);136       return newArr;137     },138   },139 };140 </script>

View Code

样式部分(Style),主要用于外观样式的设置,如下所示:

1 <style> 2 .puzzle { 3   box-sizing: content-box; 4   border: 2px solid #cccccc; 5   position: relative; 6 } 7 .puzzle__block { 8   border: 1px solid #ffffff; 9   box-sizing: border-box;10   /* background-color: rebeccapurple; */11   position: absolute;12   transition: all 0.3s;13 }14 </style>

View Code

拼图组件的调用App.vue

首先组件需要引入和注册,采用使用,如下所示:

1 <script> 2 import puzzle from "./Puzzle"; 3 export default { 4   components: { 5     puzzle, 6   }, 7   data() { 8     return { 9       level: 0,10       puzzleConfig: [11         { img: "./img/001.jpg", row: 3, col: 3 },12         { img: "./img/002.jpg", row: 4, col: 4 },13         { img: "./img/003.jpg", row: 5, col: 5 },14         { img: "./img/004.jpg", row: 6, col: 6 },15         { img: "./img/005.jpg", row: 7, col: 7 },16       ],17       status: "进行中......",18     };19   },20   methods: {21     handleNext() {22       console.log("next");23       this.status = this.$refs.dpuzzle.status;24       this.level++;25       if (this.level == this.puzzleConfig.length - 1) {26         const answerFlag = window.confirm("已经是最后一关了,需要重新开始么?");27         if (answerFlag) {28           this.level = 0;29         }30       }31     },32     getStatus() {33       this.status = this.$refs.dpuzzle.status;34     },35   },36 };37 </script>

View Code

组件的调用,如下所示:

1 <template>2   <div>3     <h3>[拼图游戏]当前是第{{level+1}}关,当前状态[{{status}}]</h3>4     <puzzle ref="dpuzzle" @getStatus="getStatus" @next="handleNext" v-bind="puzzleConfig[level]" />5     <!-- <button @click="handleNext" style="width:20px,height:20px" value="下一关">下一关</button> -->6   </div>7 </template>

View Code

注意事项:

如果获取组件内部的元素的值,在组件调用时采用ref属性,然后获取组件内的data属性值。

组件内如果调用父组件的方法,本文采用触发注册事件的方式this.$emit("next");

如果需要学习参考源码的朋友,可以点击源码链接进行下载。

源码链接

备注

浪淘沙令·帘外雨潺潺

作者:李煜【五代十国南唐后主】

帘外雨潺潺,春意阑珊。

罗衾不耐五更寒。

梦里不知身是客,一晌贪欢。

独自莫凭栏,无限江山,别时容易见时难。

流水落花春去也,天上人间。

(0)

相关推荐

  • 一起学Vue自定义组件之进度条

    在日常开发中,随着需求的个性化,逻辑的复杂化,自定义组件也变得越来越常见,而且组件具有扩展性强,易复用,封装复杂的代码逻辑等优点,可以用小组件来构建大型应用系统.本文以一个简单的小例子,简述Vue进行 ...

  • 梦幻拼图小游戏:拼图消砖块小程序立即玩

    沐沐带你发现好游戏! 只有你想不到, 没有我找不到的好游戏! 「良心好游戏推荐」 搜罗了好玩的微信小游戏大全, 模拟经营游戏.恐怖游戏.消除游戏.休闲游戏. 益智游戏.解密游戏.烧脑游戏.解谜游戏大全 ...

  • 微信上线了一款拼图小游戏,但不是每个人都玩得转

    将「雷科技Lite」收藏为我的小程序,不再错过精彩内容 微信小程序推出后,迅速普及了起来.很大程度上,它可以被视作是简化版的应用,但在交互上又比公众号要方便友好.至少,有了小程序后,小雷(微信:lei ...

  • 如何学web前端-几款前端小游戏推荐

    如何学web前端?web前端开发学习困难,有什么好的学习方法吗?今天小朗就来给各位小伙伴推荐几款学习web前端的练习游戏.非常适合web开发者和编程人员. 第一款::CSS 选择器练习  CSS DI ...

  • 我同王熙凤学了一招:把小三弄进了家门

    我叫罗美君转眼我已经40岁了,有一个事业有成的老公,还有一个乖巧听话学习成绩优秀的儿子.儿子住校以后,作为一个家庭主妇我觉得好像突然失业了一样,在也不用忙碌的早起,还有惦记着晚上该做什么好吃的.老公最 ...

  • 后视镜不能乱调!#学车 #驾考知识 @DOU 小助手

    后视镜不能乱调!#学车 #驾考知识 @DOU 小助手

  • 孩子厌学家长怎么办? 4个小妙招,让孩子不再讨厌学习

    面对孩子的厌学,家长要用正确的方法去对待.孩子不想上学,肯定是因为对学习不感兴趣,家长让孩子感受到学习的快乐之后,孩子就会慢慢喜欢上学习.那么孩子厌学家长该怎么办呢?接下来就一起来看看吧. 1.培养孩 ...

  • 荣耀手机快速拼图小技巧

    荣耀手机快速拼图小技巧

  • 教孩子学做得体小主人、小客人

    张洪军 对于生活在大都市的孩子们来说,节日带来的喜悦感日渐变淡,不少孩子竟然或多或少地染上了春节"烦恼病". 听听这些抱怨吧:随父母走亲访友吃酒宴,还要听吩咐"秀&quo ...