点击跳转html
<style> .jigsaw { margin-top: 15px; } .jigsaw .ul{ display: flex; flex-wrap: wrap; // 换行 } .ul .child { width: 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 . 如今的布局是这样子的:git
3 . 分析:每一个li表明一个格子,自定义属性data-x和data-y表明坐标(x, y);而样式order用于对格子进行移动排序;格子9添加id='empty'用于标识为空白格子。
4 . 由于格子的宽度是经过百分比设置的,会根据不一样屏幕宽度的变化而变化;并且咱们须要正方形的小格子,因此格子的高度须要js动态计算:github
// 设置格子的高度、背景图片的尺寸 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 . 如今变成布局
6 . 如今给每一个格子设置背景图片的尺寸(background-size),将格子的background-size的宽度设置成格子父节点ul的宽度,高度为auto,而后经过backgound-position进行定位,用格子的背景拼凑成一张完整的图片flex
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 对背景图片进行定位,让每一个格子只显示图片背景的九分之一,this
// 设置背景图在格子的位置 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`; }
以下图视:url
8 . 设置默认背景图片后:spa
// 设置格子的背景图片 setBgImg(imgUrl) { for (let i = 0; i < this.oChild.length - 1; i++) { this.oChild[i].style.backgroundImage = `url(${imgUrl})`; } }
9 . 接下来把格子撸成可移动的,与空白格子直接相邻的格子均可以与空白格子换位,一开始的order样式就起做用了。点击格子,首先比较该格子是否与空白格子直接相邻,若是是就交换格子的data-x、data-y和order值进行换位:code
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:htm
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 . (完)