點擊跳轉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 . (完)