• uniapp如何实现瀑布流布局效果
  • 发布于 2个月前
  • 2091 热度
    0 评论

前几天公司项目要修改一下,商品的布局,我看了一眼UI,发现是瀑布流的效果,之前我一直没做过这样的效果,当时脑海里就在思考,要怎么实现这个效果。瀑布流的效果和之前高度确定的效果区别就是,每个商品的高度都是不确定的,都会受到商品的标题长度或者是有无商品标签的影响,这样的话,就不能直接往响应式的数据中直接push数据。


思路:创建两个响应式数组leftArr,rightArr,用于存放商品数据,然后根据渲染好的左右两侧的商品列表的节点的高度进行比较,哪边高度小,对应后端获取的商品就加到哪边(记住是一个一个的加,即push)。


再做这前,我也去看了下插件市场中有没有瀑布流的布局,发现也有很多。下载下来看了一下,就只有一个人的代码是和我想的一样的。其他的都不合适,有些就是一个假的瀑布流效果,既然有人和我想法差不多,我就直接拷贝有用的代码,组织好后用到自己的项目中。其中有一个兼容性的问题:就是nextTick。


因为我们要获取节点对象的高度,而数据要push到leftArr或rightArr数组中,那么就需要等待页面更新以后再去计算节点的高度,经过测试 微信小程序端,支付宝小程序端,APP Android和IOS都不行,又很无奈的用延时去做。setTimeout延时0ms,微信小程序端,支付宝小程序端可以,APP Android和IOS都不行。那只能再把时间调就一点 20ms,经过多次测试,基本上没发现什么问题,这样瀑布流的效果就完成了。如果大家有更好的想法,一定要分享给我哦。


那么下一步就去做成一个组件,这样就可以在多个页面复用了,待组件写好后,进行测试,发现就微信小程序端拿不到对应的节点信息,那么对应的高度也就没有,完蛋。。。。其他端都是可以正常使用的。不知道是uniapp的bug,还是微信小程序的bug。无奈只能把逻辑代码写到一个js里,页面就不能复用了。


我就贴一下关键的代码,思路有了,也就好写的。
/* 堆代码 duidaima.com */
/* 获取元素的高度 */
  handleDomHeight(el) {
    return new Promise((resolve, reject) => {
      let dom = uni.createSelectorQuery().select('#' + el)
      dom.boundingClientRect(res => {
        resolve(res.height);
      }).exec();
    })
  }
  
/** 瀑布流赋值操作
   * @param {Object} dom1 左侧的节点id
   * @param {Object} dom2  有侧的节点id
   * @param {Object} list1 左侧的商品数据
   * @param {Object} list2 右侧的商品数据
   * @param {Object} originalList 源数据,即后端返回的数据
   */
  handleWaterfallFlowLayout(dom1, dom2, list1, list2, originalList) {
    let leftHeight = 0;
    let rightHeight = 0;
    let item = originalList.shift();
    if (!item) return;

    this.handleDomHeight(dom1).then(res => {
      leftHeight = res;
      this.handleDomHeight(dom2).then(res2 => {
        rightHeight = res2;
        // console.log(leftHeight, rightHeight);
        if (rightHeight >= leftHeight) {
          list1.push(item);
          // console.log('left');
        } else {
          list2.push(item);
          // console.log('right');
        }
        // Vue.nextTick(() => {
        // })
        // #ifndef APP-PLUS
        setTimeout(() => {
          this.handleWaterfallFlowLayout(dom1, dom2, list1, list2, originalList);
        });
        //#endif
        // #ifdef APP-PLUS
        setTimeout(() => {
          this.handleWaterfallFlowLayout(dom1, dom2, list1, list2, originalList);
        }, 20);
        /* app端 延时20ms是关键 this.nextTick无效*/
        //#endif
      })
    })
  }

下面还是让我们看看效果吧:

用户评论