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 相关文章推荐
js图片延迟技术一般的思路与示例
Mar 20 Javascript
jQuery学习笔记之jQuery原型属性和方法
Jun 09 Javascript
DOM基础教程之事件对象
Jan 20 Javascript
前端自动化开发之Node.js的环境搭建教程
Apr 01 Javascript
jQuery获取table下某一行某一列的值实现代码
Apr 07 jQuery
JS返回顶部实例代码
Aug 09 Javascript
jQuery实现的回车触发按钮事件功能示例
Mar 25 jQuery
vue安装遇到的5个报错及解决方法
Jun 12 Javascript
JS中封装axios来管控api的2种方式
Sep 11 Javascript
vue实现tab栏点击高亮效果
Aug 19 Javascript
js实现搜索提示框效果
Sep 05 Javascript
JavaScript 反射学习技巧
Oct 16 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面向对象的使用教程 简单数据库连接
2006/11/25 PHP
php获取mysql版本的几种方法小结
2008/03/25 PHP
PHP 页面跳转到另一个页面的多种方法方法总结
2009/07/07 PHP
PHP实现递归复制整个文件夹的类实例
2015/08/03 PHP
Laravel中Facade的加载过程与原理详解
2017/09/22 PHP
jQuery隔行变色与普通JS写法的对比
2013/04/21 Javascript
js 编码转换 gb2312 和 utf8 互转的2种方法
2013/08/07 Javascript
JsRender for object语法简介
2014/10/31 Javascript
jQuery实现“扫码阅读”功能
2015/01/21 Javascript
JavaScript数组迭代器实例分析
2015/06/09 Javascript
JS实现支持多选的遍历下拉列表代码
2015/08/20 Javascript
如何利用JS通过身份证号获取当事人的生日、年龄、性别
2016/01/22 Javascript
JS动态增删表格行的方法
2016/03/03 Javascript
详解javascript中对数据格式化的思考
2017/01/23 Javascript
vue实现购物车小案例
2019/09/27 Javascript
基于PHP pthreads实现多线程代码实例
2020/06/24 Javascript
Vue中ref和$refs的介绍以及使用方法示例
2021/01/11 Vue.js
python使用append合并两个数组的方法
2015/04/28 Python
python解决网站的反爬虫策略总结
2016/10/26 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
Numpy之reshape()使用详解
2019/12/26 Python
python中return不返回值的问题解析
2020/07/22 Python
Django vue前后端分离整合过程解析
2020/11/20 Python
英国工艺品购物网站:Minerva Crafts
2018/01/29 全球购物
微软美国官方网站:Microsoft美国
2018/05/10 全球购物
Linux面试经常问的文件系统操作命令
2015/11/05 面试题
执行总经理岗位职责
2014/02/03 职场文书
个性发展自我评价
2014/02/11 职场文书
病媒生物防治方案
2014/05/13 职场文书
员工试用期自我鉴定范文
2014/09/15 职场文书
上课睡觉万能检讨书
2015/02/17 职场文书
党员干部廉政承诺书
2015/04/28 职场文书
单位同意报考证明
2015/06/17 职场文书
新店开张宣传语
2015/07/13 职场文书
详解Python函数print用法
2021/06/18 Python
nginx配置指令之server_name的具体使用
2022/08/14 Servers