前言
最近在研究九宫格一直往上兼容到n宫格的时候发现一个很有意思的问题,就是如果使用flex布局实现多宫格布局的话,不处理的话,进行生成的时候展示的dom节点顺序是Z型布局:
这和九宫格抽奖转动的顺序不能说是完全相反,但是可以说是毫不沾边。
理想状态的布局顺序应该是圈式布局,也就是多宫格高亮块的移动顺序和输入数据的顺序应该是完全一致的:
也就是移动顺序应该是从“宇宙战将1”→ “白起2”→“太阳系级宇宙战舰3”→“小破木船4”→“地球级宇宙战将5”→“月球级蘸酱6”→“太阳级蘸酱7”→“大西洋级蘸酱8”→“宇宙战将1”→……
那么同样都是输入:
['宇宙战将1','白起2','太阳系级宇宙战舰3','大西洋级蘸酱8','小破木船4','太阳级蘸酱7','月球级蘸酱6','地球级宇宙战将5']
到底应该怎么样处理才能实现圈式分布呢?
首先明确基调,为了生成多宫格布局,使用的是flex布局,所以就得把输入的
[1,2,3,4,5,6,7,8]
调整转化为:(为了方便用数字来表示初始顺序)
[1,2,3,8,4,7,6,5]
而且这个转化方式还得兼容3*3,4*4,5*5……n*n等多级多宫格的顺序改变。
我们可以将3*3,4*4,5*5先并列列出来感受一下他们的顺序:
规律探究
1. 3x3,八宫格
可以看出:
Z型布局:[1,2,3,4,5,6,7,8]
圈型布局:[1,2,3,8,4,7,6,5]
2. 4x4,十二宫格
可以看出:
Z型布局:[1,2,3,4,5,6,7,8,9,10,11,12]
圈型布局:[1,2,3,4,12,5,11,6,10,9,8,7]
3. 5x5,十六宫格
可以看出:
Z型布局:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
圈型布局:[1,2,3,4,5,16,6,15,7,14,8,13,12,11,10,9]
当我们将这些数据排列出来:
规律总结:
经过将以上结果比较,发现了一个规律:(以3*3为例)
就3*3而言,将最后一个数移动到三和四之间,然后截取后三位,进行顺序反转后再重新接回,这样就得到了圈型布局的顺序。
4*4:
5*5:
之前我们也知道了,当n*n布局时,应该会有4n-4个元素,根据前面规律我们就可以大胆推测,n*n的Z型布局到圈型布局的变化方法应该是,从尾部截取n个数据,分别对应插到 数组的第n下标,第n+2下标,n+4,……一直到截取的数据插入完成,然后再取尾部的n个数据,进行翻转处理,最后组合起来就得到了能在flex布局下形成圈式布局的元素排列。
对应代码:
/**
* function, 将顺序从Z型布局变成圈型布局
* @param arr Array, 待改变顺序的数组
* @param level Number, 所希望生成的多宫格的层级
* @return 改变顺序后的数组
* */
function nineGridOrder(arr,level){
if(Array.isArray(arr) && arr.length==(4*level-4)){
// 对数据进行浅拷贝
let list = [...arr];
// 在当前层级下期望的元素总个数
const expectCount = 4*level - 4;
// 取要进行对应插入的尾部
let tailArr = list.splice(expectCount-level+2,expectCount).reverse();
// 取要进行翻转处理的尾部
let otherTail = list.splice(expectCount-2*level+2,expectCount).reverse();
// 进行对应插入
for (let i = 0; i < tailArr.length; i++) {
list.splice(level+2*i, 0, tailArr[i])
}
// 重新组合后输出
return list.concat(otherTail)
}else{
throw('层级与数据对应不正确,请检查输入层级后重试')
}
}
结果验证:
为保证正确,我们取该程序验证6*6,二十宫格情况下的排列是否正确。
运行程序我们可以得到:
如果用图形验证:
由上图可以看出,
Z型布局:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
圈型布局:[1,2,3,4,5,6,20,7,19,8,18,9,17,10,16,15,14,13,12,11]
与运算结果一致。
实际应用:
当用到九宫格及其拓展上时候,效果如下:
我们可以看出,不管咋样增加层级,奖品的排列顺序始终是抽奖的顺序。