这两天拿到一个小需求,小程序首页的“超值专区”版块样式全部修改,先看看最终想要的效果:

改动非常简单,每一个商品分类下,以轮播形式展示对应的商品,每一屏放3个商品,如果不足3个,有几个就正常展示几个;

看似简单的功能,1个swiper组件下有N个swiper-item每个swiper-item中有3个商品

因为公司是做SASS业务的,先看看小程序A是怎么写这个功能的:

可以看出,当时的编写者,在wxml中各种花式判断计算,其实经过这一系列折腾,html结构已经不能看了,反正我看了头疼。。。

先看看服务端返回的数据:

有N个数组,每个数组对应不同的商品信息,为了使每个swiper-item中有3个数组,所以拿到原始数据后,要将一维数组转换为二维数组,目标格式是这样的:

resultList = [
    [{name: '商品111'}, {name: '商品222'}, {name: '商品333'}],

    [{name: '商品444'}, {name: '商品555'}, {name: '商品666'}],

    [{name: '商品777'}]
];

具体处理方法如下:

/**
 * @description: 一维数组转二维数组
 * @param {Array} arr:需要进行处理的原始一维数组
 * @param {Number} targetNums:每一个二维数组中包含几个对象
 * @return {Array} 处理后的数组
 */
const arrHandle = (arr, targetNums = 3) => {
    //原始数组长度
    const _length = arr.length; 

    //计算需要循环次数
    const _splitNums = _length % targetNums === 0 ? _length % targetNums : Math.ceil(_length / targetNums);

    //定义最终输出数组
    let _resArr = [];

    //循环,使用slice方法,选择数组的一部分浅拷贝到一个新数组对象,且原始数组不会被修改
    for(let i = 0; i < _splitNums; i++){
        let _tempArr = arr.slice(i * targetNums, i * targetNums + targetNums);
        _resArr.push(_tempArr);
    }
    
    return _resArr;
};

具体使用看看最终结果:

//原数组
const _oldList = [{
        name: '商品111'
    },
    {
        name: '商品222'
    },
    {
        name: '商品333'
    },

    {
        name: '商品444'
    },
    {
        name: '商品555'
    },
    {
        name: '商品666'
    },

    {
        name: '商品777'
    },
];

const _newList = arrHandle(_oldList, 3);

console.log(_newList);

可以看到,已经成功将一维数组处理为二维数组,小程序直接渲染,就可以达到想要的效果;

其实对于这种需求,在wxml结构上做判断是不科学的,应该用js将原始数据全部处理好,wxml只负责渲染就行。


扩展:如上图,如果原始数组长度为7呢,转换后的二维数组,最后一项只有1个对象,那么从css布局样式方面来讲,如果一行排满3个,使用flex非常好布局,如果一行剩余了单独的一个元素,怎么排版更美观呢?

目前根据业务需求,元素排列从左至右依次排列,如果只有1个,那么就放在最左边,如下图:

如果使用flex布局,一般思路是使用 flex-start,从左至右排列,但这样会有一个问题,需要我们手动计算每一个元素的 margin-left具体是多少

那么使用 justify-content: space-around 呢,能达到空间自动分配,但问题是只有1个元素或2个元素时,变成下图所示的样子:

解决方案:使用JS判断数组中元素的个数,如果只有1个元素或2个元素,向数组中添加空对象,将每组的3个元素补齐

        //检测数组长度,如果数组长度小于每组的元素长度,使用空对象补齐,目的是修复flex布局
        if(_tempArr.length < 3){
          const _needNums = 3 - _tempArr.length;
          for(let i = 0; i < _needNums; i++){
            _tempArr.push({});  //循环添加空对象
          }
        }

有了空对象之后,再去wxml中渲染,那么相当于存在一个节点占位,只不过没有数据而已,完美实现  justify-content: space-around 布局方式!