关于微信小程序简单瀑布流的制作

        应业务需要,制作了简单的瀑布流,应用于购物平台。

        首先是单个内容组件。考虑到后台计算的消耗,因而将内容里的图片高度采用直接输入。到时传入数据时需注意。

<!--components/showitems/showitems.wxml-->
<!--展示商品通用框架-->
<view class="showitems-outerbox">
  <navigator class="showitems-nav" hover-class="none" url="{{goods.url}}">
    <image class="showitems-img" style="height:{{goods.picheight}}px;" lazy-load="{{true}}"></image>
    <view class="showitems-text-box">
      <view class="showitems-goods-detail">{{goods.detail}}</view>
      <view class="showitems-text-bottom">
        <view class="showitems-goods-price">¥{{goods.price}}</view>
        <view class="showitems-pay-number">{{convertpayers}}人付款</view>
      </view>
    </view>
  </navigator>
</view>
/* components/showitems/showitems.wxss */
/*外框架*/
.showitems-outerbox{
  width: 100%;
  border-radius: 6px;
  overflow: hidden;
  background-color: white;
  position: relative;
}
/*视图链接*/
.showitems-nav{
  width: 100%;
  display: block;
}
/*图片*/
.showitems-img{
  width: 100%;
  display: block;
}
/*文本域*/
.showitems-text-box{
  width: 100%;
  height: 70px;        /*文本域默认高度为70px,可调整*/
}
/*商品描述*/
.showitems-goods-detail{
  height: 35px;
  width: calc(100% - 20px);
  font-size: 12px;
  overflow: hidden;
  padding: 5px 10px;
}
/*文本域底部*/
.showitems-text-bottom{
  height: 20px;
  width: calc(100% - 10px);
  padding: 0 5px;
  display: flex;
  align-items: flex-end;
}
/*商品价格*/
.showitems-goods-price{
  font-size: 13px;
  color: orangered;
  padding: 0 5px 0 0;
}
/*付款人数*/
.showitems-pay-number{
  font-size: 10px;
  color: gray;
}
// components/showitems/showitems.js
Component({
  //属性
  properties: {
    goods:{    //商品信息
      type:Object,
      value:{
        itemsurl:String,   //商品链接
        picheight:{     //图像高度,默认140px
          type:Number,
          value:140
        },
        detail:String,    //商品描述
        price:Number,     //价格
        payers:Number,    //付款人数
        id:Number        //商品id
      }
    },

  },

  //私有数据
  data: {
    convertpayers:0,  //转化后的购买人数
  },

  //组件生命周期
  lifetimes:{
    attached:function(){
      var mypayers=this.properties.goods.payers
      this.setData({
        convertpayers:mypayers>9999?(Math.floor(mypayers/10000)+'万+'):mypayers
      })
    }
  },
  
  //方法
  methods: {

  }
})

       接下来是瀑布流组件,注意与外部页面联动。加载的数据需在外部页面JSON化后传入。初始加载20个项目,且每次触底都加载20个项目,但总数尽量不要超过200个,否则可能会卡顿。可简单实现删除一个项目后从外部传入新数据并重新排布序列。组件宽度默认屏幕宽度,可按需嵌套在容器中。最后,在该组件的JSON文件中需引用上述的项目组件,这两个组件有关联。

<!--components/waterfall/waterfall.wxml-->
<!--瀑布流布局-->
<view class="waterfall-outer">
  <view class="waterfall-left">
    <block wx:for="{{itemsleft}}" wx:key="index">
      <view class="waterfall-itemsbox" catchlongpress="_showmask" data-id="{{item.id}}">
        <showitems goods="{{item}}"></showitems>
        <view class="waterfall-threedots" catchtap="_showmask" data-id="{{item.id}}">...</view>
        <view class="waterfall-mask" wx:if="{{item.id==maskid && isshowmask}}" catchtap="_hidemask">
          <view class="waterfall-mask-unlike" catchtap="_unlike">不喜欢</view>
        </view>
      </view>
    </block>
  </view>
  <view class="waterfall-right">
    <block wx:for="{{itemsright}}" wx:key="index">
      <view class="waterfall-itemsbox" catchlongpress="_showmask" data-id="{{item.id}}">
        <showitems goods="{{item}}"></showitems>
        <view class="waterfall-threedots" catchtap="_showmask" data-id="{{item.id}}">...</view>
        <view class="waterfall-mask" wx:if="{{item.id==maskid && isshowmask}}" catchtap="_hidemask">
          <view class="waterfall-mask-unlike" catchtap="_unlike">不喜欢</view>
        </view>
      </view>
    </block>
  </view>
</view>

<view class="waterfall-bottom" hidden="{{!istobottom}}">到底了~</view>
/* components/waterfall/waterfall.wxss */
/*瀑布流框架*/
.waterfall-outer{
  width: 100%;
  display: flex;
  justify-content: space-between;
}
/*左侧、右侧*/
.waterfall-left , .waterfall-right{
  width: calc(50% - 4px);  /*中间留8px*/
}

/*项目盒子*/
.waterfall-itemsbox{
  width: 100%;
  position: relative;
  margin-bottom: 8px;   /*底部空余8px*/
}
/*三点*/
.waterfall-threedots{
  font-size: 16px;
  color: gray;
  position: absolute;
  right: 8px;
  bottom: 8px;
  height: 18px;
  width: 14px;
}
/*蒙层*/
.waterfall-mask{
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.7);
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
/*不喜欢*/
.waterfall-mask-unlike{
  width: 80px;
  height: 20px;
  font-size: 14px;
  position: absolute;
  margin-bottom: 10px;
  background-color: white;
  text-align: center;
  border-radius: 5px;
  color: gray;
}
/*瀑布流底部*/
.waterfall-bottom{
  height: 30px;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  color: gray;
}
// components/waterfall/waterfall.js
Component({
  //组件属性
  properties: {
    msg:{     //商品相关信息,在页面JSON化后传入
      type:Array,
      value:[{
        itemsurl:String,   //商品链接
        picheight:{     //图像高度,默认140px
          type:Number,
          value:140
        },
        detail:String,    //商品描述
        price:Number,     //价格
        payers:Number,    //付款人数
        id:Number        //商品id
      }]
    },
    loadmore:{    //滚动条触底加载更多,作为页面接口,配合cancelloadmore函数
      type:Boolean,
      value:false
    },
    isshowmask:{    //是否显示图片蒙层,作为页面接口,点击空白取消蒙层
      type:Boolean,
      value:false
    },
    convey:{     //页面接口,若数据更新完毕传入新的msg序列,则将其设置为true
      type:Boolean,
      value:false
    }

  },

  //组件内部数据
  data: {
    leftheight:0,    //左侧高度
    rightheight:0,   //右侧高度
    itemsleft:[],   //左侧数据集
    itemsright:[],    //右侧数据集
    pageorder:0,   //加载页数
    istobottom:false,   //是否页面到底
    maskid:null,    //蒙层id
    msgarray:[],   //动态渲染信息列表
    absposition:0,   //信息在瀑布流中的绝对位置
  },

  //生命周期
  lifetimes:{
    attached:function(){
      var leftheight=0
      var rightheight=0
      var itemsleft=[]
      var itemsright=[]
      
      for(let i=0;i<(this.properties.msg.length<=20?this.properties.msg.length:20);i++){    //初始渲染20张图片,不到20张则渲染全部
        if(leftheight<=rightheight){
          itemsleft.push(this.properties.msg[i])
          leftheight += this.properties.msg[i].picheight+70+8   //加上70px文本域高度h和8px边距
        }
        else{
          itemsright.push(this.properties.msg[i])
          rightheight += this.properties.msg[i].picheight+70+8
        }
      }

      this.setData({
        leftheight:leftheight,
        rightheight:rightheight,
        itemsleft:itemsleft,
        itemsright:itemsright,
        pageorder:this.data.pageorder+1,
        msgarray:this.properties.msg.slice(0,20)    //设置初始渲染列表
      })
    },
  },

  //页面生命周期
  pageLifetimes:{
    hide:function(){
      this._hidemask()
    }
  },

  //数据监听
  observers:{
    'loadmore':function(newval){
      if(newval){  //产生加载请求
        let leftheight=this.data.leftheight
        let rightheight=this.data.rightheight
        let itemsleft=this.data.itemsleft
        let itemsright=this.data.itemsright
        let pageorder=this.data.pageorder

        if(this._pagerelation()!=0){  //未到最后一页
          for(let i=0;i<this._remainitems();i++){
            if(leftheight<=rightheight){
              itemsleft.push(this.properties.msg[i+pageorder*20])
              leftheight += this.properties.msg[i+pageorder*20].picheight+70+8
            }
            else{
              itemsright.push(this.properties.msg[i+pageorder*20])
              rightheight += this.properties.msg[i+pageorder*20].picheight+70+8
            }
          }
  
          this.setData({
            leftheight:leftheight,
            rightheight:rightheight,
            itemsleft:itemsleft,
            itemsright:itemsright,
            pageorder:pageorder+1,
            msgarray:this.properties.msg.slice(0,this.data.msgarray.length+this._remainitems())     //更新动态渲染信息列表
          })
        }
        else{     //到最后一页
          this.setData({
            istobottom:true
          })
        }

        this._cancelloadmore()  //取消加载更多标记
      }
    },
    'convey':function(newval){
      if(newval){  //重置瀑布流
        let leftheight=0
        let rightheight=0
        let itemsleft=[]
        let itemsright=[]

        this.data.msgarray=this.properties.msg.slice(0,this.data.msgarray.length)
        for(let i=0;i<this.data.msgarray.length;i++){
          if(leftheight<=rightheight){
            itemsleft.push(this.data.msgarray[i])
            leftheight += this.data.msgarray[i].picheight+70+8
          }
          else{
            itemsright.push(this.data.msgarray[i])
            rightheight += this.data.msgarray[i].picheight+70+8
          }
        }
        this.setData({
          itemsleft:itemsleft,
          itemsright:itemsright,
          leftheight:leftheight,
          rightheight:rightheight
        })
        this._cancelconvey()    //取消数据传送完毕标记
      }
    }
  },

  //组件方法
  methods: {
    _totalpagenum(){   //20张一页,共几页
      var msglength=this.properties.msg.length
      return msglength%20==0?Math.floor(msglength/20):Math.floor(msglength/20+1)
    },
    _pagerelation(){    //判断页数情况
      var totalpage=this._totalpagenum()
      var curpage=this.data.pageorder
      return (totalpage-curpage==0)?0:((totalpage-curpage==1)?1:2)
    },
    _remainitems(){    //剩余项目
      switch(this._pagerelation()){
        case 0: return 0;
        case 1: return this.properties.msg.length-this.data.pageorder*20;
        case 2: return 20;
        default: return 0;
      }
    },
    _cancelloadmore(){   //发送取消加载更多标记的请求,关联loadmore接口
      this.triggerEvent('cancelloadmore')
    },

    _showmask(e){     //显示蒙层
      this.setData({
        maskid:e.currentTarget.dataset.id,
        isshowmask:true
      })
    },
    _hidemask(){     //取消蒙层
      this.setData({
        isshowmask:false
      })
    },
    _unlike(){      //点击不喜欢按钮
      for(let i=0;i<this.data.msgarray.length;i++){
        if(this.data.msgarray[i].id==this.data.maskid){    //按钮id和蒙层id相同
          this.setData({
            absposition:i
          })
          break
        }
      }
      this.triggerEvent('needonemsg',{position:this.data.absposition})    //发送请求通知页面更新消息列表,关联convey接口
    },
    _cancelconvey(){    //发送清除convey标识的请求,关联convey接口
      this.triggerEvent('cancelconvey')
    },
  }
})

用法举例:

        新建一个页面,在wxml页输入

<view style="width:calc(100% - 20px);margin:10px;" bindtap="_clickspace">
  <waterfall msg="{{mymessage}}" loadmore="{{istolast}}" bind:cancelloadmore="_cancelloadmore" isshowmask="{{haveshowmask}}" convey="{{myconvey}}" bind:needonemsg="_needonemsg" bind:cancelconvey="_cancelconvey"></waterfall>
</view>

        在js页面输入

data: {
    mymessage:[{itemsurl:'',picheight:150,detail:'会地方的基础上',price:245,payers:4567,id:0},
    {itemsurl:'',picheight:130,detail:'很合适的十多个',price:356,payers:233,id:1},
    {itemsurl:'',picheight:140,detail:'电话手表编程',price:377.9,payers:12,id:2},
    {itemsurl:'',picheight:160,detail:'当回事呢购物',price:7899,payers:54761,id:3},
    {itemsurl:'',picheight:140,detail:'变成蛇的差别不大',price:245,payers:4567,id:4},
    {itemsurl:'',picheight:160,detail:'的接口处超声波产生',price:245,payers:4567,id:5},
    {itemsurl:'',picheight:150,detail:'会地方的基础上',price:245,payers:4567,id:6},
    {itemsurl:'',picheight:130,detail:'会地方的基础上',price:245,payers:4567,id:7},
    {itemsurl:'',picheight:160,detail:'会地方的基础上',price:245,payers:4567,id:8},
    {itemsurl:'',picheight:130,detail:'会地方的基础上',price:245,payers:4567,id:9},
    {itemsurl:'',picheight:150,detail:'会地方的基础上',price:245,payers:4567,id:10},
    {itemsurl:'',picheight:150,detail:'会地方的基础上',price:245,payers:4567,id:11},
    {itemsurl:'',picheight:170,detail:'会地方的基础上',price:245,payers:4567,id:12},
    {itemsurl:'',picheight:140,detail:'会地方的基础上',price:245,payers:4567,id:13},
    {itemsurl:'',picheight:160,detail:'会地方的基础上',price:245,payers:4567,id:14},
    {itemsurl:'',picheight:160,detail:'会地方的基础上',price:245,payers:4567,id:15},
    {itemsurl:'',picheight:150,detail:'会地方的基础上',price:245,payers:4567,id:16},
    {itemsurl:'',picheight:140,detail:'会地方的基础上',price:245,payers:4567,id:17},
    {itemsurl:'',picheight:150,detail:'武松要打虎',price:245,payers:4567,id:18},
    {itemsurl:'',picheight:140,detail:'会地方的基础上',price:245,payers:4567,id:19},
    {itemsurl:'',picheight:140,detail:'会地方的基础上',price:245,payers:4567,id:20},
    {itemsurl:'',picheight:160,detail:'我在河边洗澡',price:245,payers:4567,id:21}
  ],

    istolast:false,
    haveshowmask:false,
    myconvey:false,
  },

//监听页面触底
  onReachBottom:function(){
    this.setData({
      istolast:true
    })
  },
  
  //取消加载标记
  _cancelloadmore:function(){
    this.setData({
      istolast:false
    })
  },

  //取消蒙层
  _clickspace:function(){
    this.setData({
      haveshowmask:false
    })
  },

  //需要新消息
  _needonemsg:function(e){
    this.data.mymessage.splice(e.detail.position,1)
    this.data.mymessage.push({itemsurl:'',picheight:170,detail:'好像是睡觉一样的人大概是动感',price:371,payers:1356,id:22})
    
    this.setData({
      haveshowmask:false
    })
    var i=setTimeout(() => {
      this.setData({
        myconvey:true,
        mymessage:this.data.mymessage
      })
      clearTimeout(i)
    }, 1000);
  },

  //取消新消息标识位
  _cancelconvey:function(){
    this.setData({
      myconvey:false
    })
  },

        最后在JSON页面引用waterfall组件,便可看到有趣的现象。祝大家玩得愉快!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值