「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。
前言
前几天写了一篇 “ vue 中 v-for 动态生成盒子换行排列布局效果 ” 的文章来大概讲解了一下多个大小不同的盒子的动态生成。当时留下了一点问题,就是在动态生成每个 ul
的时候,之前是把每个 ul
中的 li
的个数定死了,这几天想了一下优化的方法,具体想了两种,大概粗略的实现了这个需求
问题所在
按理来说,每个ul当中的li的个数应该是不确定的,根据数组中不同的组合方案,生成的li数量应该也要是不同的,就像下图的两个ul。
很明显能看出,第一个ul是刚好的8个li,但是第二个ul就只有7个li,这显然要上一篇里的算法页面就会出现问题,接下去就说一下,我现在用了什么样的办法来解决这个需求。
解决方法
第一个
首先今天想到的第一个方法是:直接建立一个map表去匹配每一种情况,比方说碰到三个1*1的盒子就进行换行,或者一个1*2加上一个1*1换行。当然这种方法需要在map当中添加很多的数据,因为三种盒子动态生成将会有很多不同的情况,但是如果能够保证,盒子动态生成,但是它生成的组合排列一定是正确的,不会出现一行之中有放不下的盒子跳到下一行去的情况:
在这个前提下,这个匹配表就能减少很多的数据
itemSegmentation(items) {
let lineFeedTable = new Map([
["smallsmallsmall", 1],
["smallmedium", 1],
["mediumsmall", 1],
['smallsmalllarge',2],
['largesmallsmall',2],
]);
let temporaryArray = '';
let splitItem = [];
let line = 0;
let idx = 0;
items.forEach((item, index) => {
temporaryArray += item.size;
if(lineFeedTable.get(temporaryArray) == 1){
line++
temporaryArray = '';
}else if(lineFeedTable.get(temporaryArray) == 2){
line += 2;
temporaryArray = '';
}
if (!splitItem[idx]) splitItem[idx] = [];
splitItem[idx].push(item);
if(line == 4){
idx ++
line = 0;
}
});
return splitItem;
},
复制代码
上面可以看到我将盒子的大小定位 small ,medium 和 large ,用一个字符串记录出现过的盒子,当字符串串接起来满足 map 表中的某一项的时候,自动转化为需要增加的行数,当行数满4行就换一个ul
并且重新计算行数。
第二个
第二种方法就提供一个思路,我们可以通过一个循环判断,当循环碰到了1*2的盒子,就先去找它前面有没有1*1,没有的话就去找后面,再没有的话,就说明这个1*2是自己单独一行,以此类推,2*2因为没办法和1*2放在同一行,使用也是前后去找1*1的盒子,然后两种找到了或者没找到,都要在行数上对应的加1或加2,再者就是定一个数判断1*1出现的个数,当它连续三次出现的时候,行数加一,计数器清零。
比方说下面这个 array 如果是我们传进来的 item ,然后对他进行 foreach
循环,当你循环到1*1时计数器加一然后下一个,循环到了1*2就去判断前面有没有1*1,有的话就把他们两一起拿出来,没有就去判断后面有没有1*1,同理,有的话就拿出来。
-
先判断前面有没有小盒子,有的话就将他们两个拿出来,没有就去判断后面,有的话就拿出来,前后都没有,就单独把2拿出来,然后
line
加一,计数器清零。 -
2和3同理,计数器加一跳过,因为没有到三,所以不做操作。
- 到大盒子的时候也是先去判断前面有没有小盒子,因为小盒子的计数器只能是1或者2(3就直接换行清零了)所有大盒子只要判断前面还有没有小盒子就可以,不用在意小盒子是一个或者两个,反正都是放得下的。之后再来判断后面有没有小盒子。
- 比方说前面没有小盒子,先去判断后一位是小盒子的话,再去判断后二位是不是小盒子,然后取出。
总结
上面总结了我自己今天想的两种解决上次遗留下来的问题的方法,具体使用会不会因为奇怪的数据出现 bug 暂时还没有去尝试,如果发现这些方法不对的地方,欢迎提出,有更好的解法也可以一起讨论。