javascript结合Flexbox简单实现滑动拼图游戏


Posted in Javascript onFebruary 18, 2016

滑动拼图就是把一张图片分成几等份,打乱顺序(下图),然后通过滑动拼凑成一张完整的图片。

javascript结合Flexbox简单实现滑动拼图游戏

要实现一个拼图游戏,需要考虑怎样随机的打乱顺序,怎样交换两张图片的位置,等等。但是,使用了Flexbox布局以后,这都不需要你去考虑,浏览器会帮你做,Flexbox就是这么的强大。关于Flexbox的介绍可以点击这里。
这个游戏中要用的是Flexbox布局的order属性,order属性可以用来控制Flex项目的顺序。
这里我用九个canvas元素来把图片分成九等分,也可以用其他方法,比如背景图片定位:

<div class="wrap">
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
</div>

如果不仅限于九宫格,还要十六宫格等,上面的元素完全可以动态生成。
下面是生成打乱顺序的九张图代码:

var drawImage = function (url) {
  return new Promise(function (resolve, reject) {
    var img = new Image();
    img.onload = function () {
      resolve(img);
    };
    img.src = url;
  })
};

drawImage("2.jpg").then(function (img) {
  var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  var random = arr.sort(function() {return Math.random() > 0.5});
  [].forEach.call(document.querySelectorAll("canvas"), function (item, i) {
    item.width = $(".wrap").clientWidth / 3;
    item.height = $(".wrap").clientHeight / 3;
    item.style.order = random[i];
    var ctx = item.getContext("2d");
    ctx.drawImage(img, img.width * (i % 3) / 3, img.height * Math.floor(i / 3) / 3, img.width / 3, img.height / 3, 0, 0, item.width, item.height);
  });
});

上面的关键代码是:

item.style.order = random[i];

通过将数字打乱顺序,随机赋值给每个canvas元素的order属性,这样浏览器就自动帮你排序了。
关于代码的其他细节就不讲了,这里说一下怎样交换两张图片的位置,真是出乎意料的简单:

var order1 = item.style.order;
var order2 = target.style.order;

只需要交换双方的order属性值就可以了。

完整代码

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
  <meta content="yes" name="apple-mobile-web-app-capable" />
  <meta content="black" name="apple-mobile-web-app-status-bar-style" />
  <meta content="telephone=no" name="format-detection" />
  <title></title>
  <style>
    html, body {
      height: 100%;
    }
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
    .wrap {
      display: flex;
      flex-wrap: wrap;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    .wrap canvas {
      width: 33.3333%;
      height: 33.3333%;
      border: 1px solid red;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
<div class="wrap">
  <canvas data-value="1"></canvas>
  <canvas data-value="2"></canvas>
  <canvas data-value="3"></canvas>
  <canvas data-value="4"></canvas>
  <canvas data-value="5"></canvas>
  <canvas data-value="6"></canvas>
  <canvas data-value="7"></canvas>
  <canvas data-value="8"></canvas>
  <canvas data-value="9"></canvas>
</div>
<script>
  var $ = function (el) {
    return document.querySelector(el);
  };
  var touchMove, touchEnd;
  var drawImage = function (url) {
    return new Promise(function (resolve, reject) {
      var img = new Image();
      img.onload = function () {
        resolve(img);
      };
      img.src = url;
    })
  };
  drawImage("2.jpg").then(function (img) {
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    var random = arr.sort(function() {return Math.random() > 0.5});
    [].forEach.call(document.querySelectorAll("canvas"), function (item, i) {
      item.width = $(".wrap").clientWidth / 3;
      item.height = $(".wrap").clientHeight / 3;
      item.style.order = random[i];
      var ctx = item.getContext("2d");
      ctx.drawImage(img, img.width * (i % 3) / 3, img.height * Math.floor(i / 3) / 3, img.width / 3, img.height / 3, 0, 0, item.width, item.height);
    });
  });
  document.addEventListener("touchstart", function (e) {
    var target = e.target;
    if (e.target.tagName.toLowerCase() !== "canvas") {
      return;
    }
    var ctx = target.getContext("2d");
    var image = ctx.getImageData(0, 0, target.width, target.height);
    var obj = target.cloneNode(true);
    obj.getContext("2d").putImageData(image, 0, 0);
    var top = target.getBoundingClientRect().top, left = target.getBoundingClientRect().left;
    obj.style.cssText = "position: absolute; top: " + top + "px; left: " + left + "px";
    document.body.appendChild(obj);
    var point = {"x": e.touches[0].pageX, "y": e.touches[0].pageY};
    document.addEventListener("touchmove", touchMove = function (e) {
      obj.style.cssText = "position: absolute; top:" + (e.touches[0].pageY - point.y + top) + "px; left: " + (e.touches[0].pageX - point.x + left) + "px";
    });
    document.addEventListener("touchend", touchEnd = function (e) {
      var pos = {"x": e.changedTouches[0].pageX, "y": e.changedTouches[0].pageY};
      [].forEach.call(document.querySelectorAll(".wrap canvas"), function (item, i) {
        var offset = item.getBoundingClientRect();
        if (pos.x > offset.left && pos.x < (offset.left + item.width) && pos.y > offset.top && pos.y < (offset.top + item.height)) {
          var order1 = item.style.order;
          var order2 = target.style.order;
          if (obj.parentNode) {
            document.body.removeChild(obj);
          }
          item.style.order = order2;
          target.style.order = order1;
        }
      });
      document.removeEventListener("touchmove", touchMove);
      document.removeEventListener("touchend", touchEnd);
    })
  })
</script>
</body>
</html>

大家做测试的时候,最好用谷歌模拟器或者手机打开,因为只支持移动端触摸事件。

代码中只实现了基本功能,并没有实现完整功能。

Javascript 相关文章推荐
Jsonp 跨域的原理以及Jquery的解决方案
Jun 27 Javascript
处理及遍历XML文档DOM元素属性及方法整理
Aug 23 Javascript
window.location 对象所包含的属性
Oct 10 Javascript
JS实现DIV容器赋值的方法
Dec 14 Javascript
基于socket.io+express实现多房间聊天
Mar 17 Javascript
JavaScript禁止用户多次提交的两种方法
Jul 24 Javascript
XMLHttpRequest Level 2 使用指南
Aug 26 Javascript
详解Html a标签中href和onclick用法、区别、优先级别
Jan 16 Javascript
浅谈angular4 ng-content 中隐藏的内容
Aug 18 Javascript
jQuery实现表单动态添加与删除数据操作示例
Jul 03 jQuery
基于layui table返回的值的多级嵌套的解决方法
Sep 19 Javascript
Vue中fragment.js使用方法小结
Feb 17 Javascript
Angular发布1.5正式版,专注于向Angular 2的过渡
Feb 18 #Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
Feb 18 #Javascript
javascript每日必学之条件分支
Feb 17 #Javascript
JavaScipt中栈的实现方法
Feb 17 #Javascript
Bootstrap入门书籍之(五)导航条、分页导航
Feb 17 #Javascript
Bootstrap入门书籍之(四)菜单、按钮及导航
Feb 17 #Javascript
Bootstrap入门书籍之(三)栅格系统
Feb 17 #Javascript
You might like
php面向对象全攻略 (十六) 对象的串行化
2009/09/30 PHP
提高PHP性能的编码技巧以及性能优化详细解析
2013/08/24 PHP
php安装ssh2扩展的方法【Linux平台】
2016/07/20 PHP
在PHP中输出JS语句以及乱码问题的解决方案
2019/02/13 PHP
PHP+redis实现微博的推模型案例分析
2019/07/10 PHP
JavaScript写的一个自定义弹出式对话框代码
2010/01/17 Javascript
判断对象是否Window的实现代码
2012/01/10 Javascript
Node.js开发指南中的简单实例(mysql版)
2013/09/17 Javascript
jQuery中操控hidden、disable等无值属性的方法
2014/01/06 Javascript
Windows系统下使用Sublime搭建nodejs环境
2015/04/13 NodeJs
Angularjs实现搜索关键字高亮显示效果
2017/01/17 Javascript
关于vue-resource报错450的解决方案
2017/07/24 Javascript
利用JavaScript的%做隔行换色的实例
2017/11/25 Javascript
js中的闭包实例展示
2018/11/01 Javascript
微信小程序页面缩放式侧滑效果的实现代码
2018/11/15 Javascript
Koa从零搭建到Api实现项目的搭建方法
2019/07/30 Javascript
[52:20]VP vs VG Supermajor小组赛 B组胜者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
scrapy爬虫完整实例
2018/01/25 Python
Python实现网站表单提交和模板
2019/01/15 Python
Django之无名分组和有名分组的实现
2019/04/16 Python
python写入数据到csv或xlsx文件的3种方法
2019/08/23 Python
PyTorch学习:动态图和静态图的例子
2020/01/06 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
浅谈Keras的Sequential与PyTorch的Sequential的区别
2020/06/17 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
2020/07/02 Python
HTML5 Canvas绘制文本及图片的基础教程
2016/03/14 HTML / CSS
浅析移动设备HTML5页面布局
2015/12/01 HTML / CSS
Canvas引入跨域的图片导致toDataURL()报错的问题的解决
2018/09/19 HTML / CSS
adidas澳大利亚官方网站:adidas Australia
2018/04/15 全球购物
什么是聚集索引和非聚集索引
2012/01/17 面试题
2014年父亲节活动方案
2014/03/06 职场文书
乡镇信息公开实施方案
2014/03/23 职场文书
2014入党积极分子批评与自我批评思想汇报
2014/09/20 职场文书
森马旗舰店双十一营销方案
2014/09/29 职场文书
电影建国大业观后感
2015/06/01 职场文书
python实现语音常用度量方法的代码详解
2021/05/25 Python