zoukankan      html  css  js  c++  java
  • 自定义上传图片拼图游戏

    1. 游戏访问连接

    点击跳转

    2. 九宫格拼图原理

    1. 图例原理:

    image

    1. 上图的九宫格图例,每个格子都有一个(x,y)的坐标,假如格子9是空白格子,怎么知道6和8是它的直接相邻格子呢。这时候就体现出格子坐标(x,y)的作用了, 使用公式:|(x6 - x9)| + |(y6 - y9)| = 1,将空白格子9的坐标与格子6的坐标进行对应坐标的差值的绝对值的和等于1,就证明它们是直接相邻格子,可进行移动互换。
    2. 详细原理请点击:跳转

    3. 实现过程,代码分析

    1. flex实现九宫格布局:
    <style>
      .jigsaw {
        margin-top: 15px;
      }
      .jigsaw .ul{
        display: flex;
        flex-wrap: wrap; // 换行
      }
      
      .ul .child {
         33.3%;
        color: rgba(255, 255, 255, 0.5);
        background-repeat: no-repeat;
      }
    </style>
    <section class='jigsaw'>
        <ul class="ul">
            <li class="child" data-x='1' data-y='1' style="order:1">1</li>
            <li class="child" data-x='2' data-y='1' style="order:2">2</li>
            <li class="child" data-x='3' data-y='1' style="order:3">3</li>
            <li class="child" data-x='1' data-y='2' style="order:4">4</li>
            <li class="child" data-x='2' data-y='2' style="order:5">5</li>
            <li class="child" data-x='3' data-y='2' style="order:6">6</li>
            <li class="child" data-x='1' data-y='3' style="order:7">7</li>
            <li class="child" data-x='2' data-y='3' style="order:8">8</li>
            <li class="child" data-x='3' data-y='3' style="order:9" id='empty'>9</li>
        </ul>
    </section>

    2 . 现在的布局是这样子的:

    image

    3 . 分析:每个li代表一个格子,自定义属性data-x和data-y代表坐标(x, y);而样式order用于对格子进行移动排序;格子9添加id='empty'用于标识为空白格子。
    4 . 因为格子的宽度是通过百分比设置的,会根据不同屏幕宽度的变化而变化;而且我们需要正方形的小格子,所以格子的高度需要js动态计算:

    // 设置格子的高度、背景图片的尺寸
    setChildStyle() {
      this.childWidth = window.getComputedStyle(this.oChild[0], false).width; // 获取格子宽度
      console.log(this.childWidth);
      for (let i = 0; i < this.oChild.length; i++) {
        this.oChild[i].style.height = `${this.childWidth}`;
      }
    }

    5 . 现在变成

    image
    6 . 现在给每个格子设置背景图片的尺寸(background-size),将格子的background-size的宽度设置成格子父节点ul的宽度,高度为auto,然后通过backgound-position进行定位,用格子的背景拼凑成一张完整的图片

    setChildStyle() {
      this.childWidth = window.getComputedStyle(this.oChild[0], false).width;
      console.log(this.childWidth);
      for (let i = 0; i < this.oChild.length; i++) {
         this.oChild[i].style.height = `${this.childWidth}`;
         this.oChild[i].style.backgroundSize = `${this.ulWidth} auto`;
         this.setBgpositon(this.oChild[i]);
      }
    }

    7 . 其实每个格子的背景图片都是同一张,只不过是通过background-position 对背景图片进行定位,让每个格子只显示图片背景的九分之一,

    // 设置背景图在格子的位置
    setBgpositon(chiObj) {
      let x = chiObj.getAttribute('data-x') - 1;
      let y = chiObj.getAttribute('data-y') - 1;
      chiObj.style.backgroundPosition = `${-x*parseInt(this.childWidth)}px ${-y*parseInt(this.childWidth)}px`;
    }

    如下图视:
    image

    8 . 设置默认背景图片后:

    // 设置格子的背景图片
    setBgImg(imgUrl) {
      for (let i = 0; i < this.oChild.length - 1; i++) {
        this.oChild[i].style.backgroundImage = `url(${imgUrl})`;
      }
    }

    image

    9 . 接下来把格子撸成可移动的,与空白格子直接相邻的格子都可以与空白格子换位,一开始的order样式就起作用了。点击格子,首先比较该格子是否与空白格子直接相邻,如果是就交换格子的data-x、data-y和order值进行换位:

    childEvent() {
      let that = this;
      let oEmptyChild = document.getElementById('empty'); // 获取空白的格子对象
      this.oUl[0].addEventListener('click', function(ev){
        let target = ev.target;
        let targetX, targetY, targetOrder;
        let iEmptyX, iEmptyY, iEmptyOrder;
        if (target.className != 'child' ) return false;
        iEmptyX = oEmptyChild.getAttribute('data-x');
        iEmptyY = oEmptyChild.getAttribute('data-y');
        iEmptyOrder = window.getComputedStyle(oEmptyChild, false).order;
        targetX = target.getAttribute('data-x');
        targetY = target.getAttribute('data-y');
        targetOrder = window.getComputedStyle(target, false).order;
        if (Math.abs(targetX - iEmptyX) + Math.abs(targetY - iEmptyY) == 1) {
          // data-x data-y order 值互换
          [iEmptyX, targetX] = [targetX, iEmptyX];
          [iEmptyY, targetY] = [targetY, iEmptyY];
          [iEmptyOrder, targetOrder] = [targetOrder, iEmptyOrder];
    
          oEmptyChild.setAttribute('data-x', iEmptyX);
          oEmptyChild.setAttribute('data-y', iEmptyY);
          oEmptyChild.style.order = iEmptyOrder;
          target.setAttribute('data-x', targetX);
          target.setAttribute('data-y', targetY);
          target.style.order = targetOrder;
        }
      }, false);
    }

    10 . 接下来是把上传的img图片设置成格子背景,通过监听input type='file'的change事件来获取图片文件files:

    imgEvent() {
      let that = this;
      this.oFile.addEventListener('change', function(){
        let imgUrl = window.URL.createObjectURL(this.files[0]); // 该方法将files转换成img可访问的本地路径
        that.oImg.setAttribute('src', imgUrl);
        that.oImg.onload = function() {
          that.setBgImg(imgUrl); // 重新设置格子背景
        }
      }, false);
    }

    11 . 源码地址 点击访问

    12 . (完)

  • 相关阅读:
    Redis总结(六)Redis配置文件全解
    Thrift总结(二)创建RPC服务
    Thrift总结(一)介绍
    C#总结(三)DataGridView增加全选列
    C#总结(二)事件Event 介绍总结
    Quartz.NET总结(六)了解Jobs 和 Triggers
    C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步)
    Redis总结(五)缓存雪崩和缓存穿透等问题
    C#类和成员的修饰符
    sqlserver 修改替换text,ntext类型字段的两种方案
  • 原文地址:https://www.cnblogs.com/10manongit/p/12740254.html
Copyright © 2011-2022 走看看