如果您想要综合使用javascript中canvas、原生拖拽、本地存储等多种技术完成一个有趣的项目,那么这篇文章将非常适合您
1 简介和源码
该项目中的拼图小游戏使用javascript原创,相比于网站上类似的功能,它使用到的技术点更先进丰富,功能更强大,还包含程序开发中更多先进的思想理念,从该项目中您将能学到:
FileReader、Image对象的配合canvas对图片进行压缩,切割的技巧。
学习小游戏开发中最常用的碰撞检测、状态监控、刷新保持状态的处理方法。
深入了解拖拽交换元素的细节,学习到动态元素绑定事件、回调函数的处理方式。
项目源码-github
下面是游戏界面的示例图:
2 实现思路
根据游戏界面图我们可以将完成这么一个小游戏分为以下几步来实现:
1.拖拽图片到指定区域,使用FileReader对象读取到图片的base64内容,然后添加到Image对象中
2.当Image对象加载完成后,使用canvas对图片进行等比缩放,然后取到缩略图的base64内容,添加到另外一个缩略图Image对象中,并将该缩略图base64的内容保存到本地存储(localStorage)中
3.当缩略图Image对象加载完成后,再次使用canvas对缩略图进行切割,该游戏中将缩略图切割成3*4一共12等份,使用本地存储保存每份切割缩略图base64内容,将缩略图顺序打乱,使用img标签显示在web页面上
4.当缩略图切片都添加到web界面上以后,为每一份缩略图切片添加注册拖拽事件,使得缩略图切片可以相互交换,在这个过程当中,添加对缩略图切片顺序状态的监控,一旦完成拼图,就直接展示完整的缩略图,完成游戏
从以上对小游戏制作过程的分析来看,第4步是程序功能实现的重点和难点,在以上的每个步骤中都有很多小细节需要注意和探讨,下面我就详细分析一下每个步骤的实现细节,说的不好的地方,欢迎大家留言指正。
3 开发细节详解
3.1 图片内容读取和加载
在游戏开发第1步中,我们将图片拖拽到指定区域后,程序是怎样得到图片内容信息的呢?fileReader对象又是怎样将图片信息转化为base64字符串内容的?Image对象拿到图片的base64内容之后,又是怎样初始化加载的?带着这些疑问,我们来研究一下实现项目中实现了第一步的关键代码。
var droptarget = document.getElementById("droptarget"), output = document.getElementById("ul1"), thumbImg = document.getElementById("thumbimg"); //此处省略相关代码........ function handleEvent(event) { var info = "", reader = new FileReader(), files, i, len; EventUtil.preventDefault(event); localStorage.clear(); if (event.type == "drop") { files = event.dataTransfer.files; len = files.length; if (!/image/.test(files[0].type)) { alert('请上传图片类型的文件'); } if (len > 1) { alert('上传图片数量不能大于1'); } var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var img = new Image(), //原图 thumbimg = new Image(); //等比缩放后的缩略图 reader.readAsDataURL(files[0]); reader.onload = function (e) { img.src = e.target.result; } //图片对象加载完毕后,对图片进行等比缩放处理。缩放后最大宽度为三百像素 img.onload = function () { var targetWidth, targetHeight; targetWidth = this.width > 300 ? 300 : this.width; targetHeight = targetWidth / this.width * this.height; canvas.width = targetWidth; canvas.height = targetHeight; context.clearRect(0, 0, targetWidth, targetHeight); context.drawImage(img, 0, 0, targetWidth, targetHeight); var tmpSrc = canvas.toDataURL("image/jpeg"); //在本地存储完整的缩略图源 localStorage.setItem('FullImage', tmpSrc); thumbimg.src = tmpSrc; } //此处省略相关代码...... EventUtil.addHandler(droptarget, "dragenter", handleEvent); EventUtil.addHandler(droptarget, "dragover", handleEvent); EventUtil.addHandler(droptarget, "drop", handleEvent); }
这段代码的思路就是首先获得拖拽区域目标对象droptarget,为droptarget注册拖拽监听事件。代码中用到的EventUtil是我封装的一个对元素添加事件、事件对象的兼容处理等常用功能的简单对象,下面是其添加注册事件的简单简单代码,其中还有很多其他的封装,读者可自行查阅,功能比较简单。
var EventUtil = { addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type, handler, false); } else if (element.attachEvent){ element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, //此处省略代...... }
当用户将图片文件拖放到区域目标对象droptarget时,droptarget的事件对象通过event.dataTransfer.files获取到文件信息,对文件进行过滤(限制只能为图片内容,并且最多只能有一张图片)。拿到文件内容以后,使用FileReader对象reader读取文件内容,使用其readAsDataURL方法读取到图片的base64内容,赋值给Image对象img的src属性,就可以等到img对象初始化加载完毕,使canvas对img进行下一步的处理了。这里有一个重点的地方需要说明:一定要等img加载完成后,再使用canvas进行下一步的处理,不然可能会出现图片损坏的情况。原因是:当img的src属性读取图片文件的base64内容时,可能还没有将内容加载到内存中时,canvas就开始处理图片(此时的图片是不完整的)。所以我们可以看到canvas对图片的处理是放在img.onload方法中进行的,程序后边还会有这种情况,之后就不再赘述了。
3.2 图片等比缩放和本地存储
在第一步中我们完成了对拖拽文件的内容读取,并将其成功加载到了Image对象img中。接下来我们使用canvas对图片进行等比缩放,对图片进行等比缩放,我们采取的策略是限制图片的最大宽度为300像素,我们再来看一下这部分代码吧:
img.onload = function () { var targetWidth, targetHeight; targetWidth = this.width > 300 ? 300 : this.width; targetHeight = targetWidth / this.width * this.height; canvas.width = targetWidth; canvas.height = targetHeight; context.clearRect(0, 0, targetWidth, targetHeight); context.drawImage(img, 0, 0, targetWidth, targetHeight); var tmpSrc = canvas.toDataURL("image/jpeg"); //在本地存储完整的缩略图源 localStorage.setItem('FullImage', tmpSrc); thumbimg.src = tmpSrc; }
确定了缩放后的宽度targetWidth和高度targetHeight之后,我们使用canvas的drawImage方法对图像进行压缩,在这之前我们最好先使用画布的clearRect对画布进行一次清理。对图片等比缩放以后,使用canvas的toDataURL方法,获取到缩放图的base64内容,赋给新的缩放图Image对象thumbimg的src属性,待缩放图加载完毕,进行下一步的切割处理。缩放图的base64内容使用localStorage存储,键名为"FullImage"。浏览器的本地存储localStorage是硬存储,在浏览器刷新之后内容不会丢失,这样我们就可以在游戏过程中保持数据状态,这点稍后再详细讲解,我们需要知道的是localStorage是有大小限制的,最大为5M。这也是为什么我们先对图片进行