首页 > 编程语言 >微信小程序 瀑布流布局

微信小程序 瀑布流布局

时间:2022-10-23 03:00:08浏览次数:91  
标签:index const 微信 100% 布局 height width 瀑布 let

记录一下,方便以后使用...

效果

如图很显然,一般情况下我们需要的效果并不是这样的。

image

印象中的瀑布流应该是

image

以下是两种效果的实现

前提

先要有一个自动适配高度的图片组件,小程序我不知道怎么写样式让它像H5一样,所以就写了一个组件来做这样一件事。

auto-image

根据已知宽度自动适配自身高度的组件。

index.js

Component({
  properties: {
    src: {
      type: String,
      value: ''
    },
    mode: {
      type: String,
      value: 'aspectFill'
    }
  },
  data: {
    width: 'auto',
    height: 'auto',
    loaded: false
  },
  methods: {
    imageLoad(e) {
      this.createSelectorQuery().select('.in-image-content').boundingClientRect().exec(([{ width: conWidth }]) => {
        // 获取图片的源宽度/高度
        let { width, height } = e.detail
        // 获取比例
        let scale = width / conWidth
        // 宽度赋值
        width = conWidth;
        // 高度比例缩放
        height /= scale
        // 高度取整
        height = Math.round(height)
        this.setData({ width: `${width}px`, height: `${height}px`, loaded: true })
        this.triggerEvent('loaded', { width, height })
      })
    }
  }
})

index.wxml

<view class="in-image-content {{loaded?'show':''}}">
  <image class="in-image-content__image" src="{{src}}" mode="{{mode}}" style="width: {{width}};height: {{height}};" bindload="imageLoad"></image>
  <view class="in-image-content__slot" hidden="{{!loaded}}">
    <slot></slot>
  </view>
</view>

index.wxss

:host {
  width: 100%;
}

.in-image-content {
  width: 100%;
  position: relative;
  break-inside: avoid;
  opacity: 0;
  transition: opacity .5s ease-in;
}

.in-image-content__image {
  display: block;
}

.in-image-content__slot {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

.show {
  opacity: 1;
}

方案一

采用css样式column-count +循环取余 (本来想的是控制排序 结果有...)

index

index.json

引入组件

{
  "usingComponents": {
    "auto-image":"/components/auto-image/index"
  },
  "navigationBarTitleText": "瀑布流"
}

index.js

const minWidth = 200;
const minHeight = 250;
const maxWidth = 400;
const maxHeight = 500;
const pageSize = 10;
function getPlacekitten() {
  const rw = minWidth + Math.round(Math.random() * (maxWidth - minWidth))
  const rh = minHeight + Math.round(Math.random() * (maxHeight - minHeight))
  return `https://placekitten.com/${rw}/${rh}`
}

Page({
  data: {
    column: 3,
    images: []
  },
  onl oad() {
    this.loadMore()
  },
  loadMore() {
    const { images } = this.data
    for (let i = 0; i < pageSize; i++) {
      images.push(getPlacekitten())
    }
    this.setData({ images })
  },
  onReachBottom() {
    this.loadMore()
  }
})

index.wxml

<view class="masonry" style="column-count:{{column}}">
  <block wx:for="{{column}}" wx:for-item="columnNum" wx:key="unique">
    <block wx:for="{{images}}" wx:key="unique">
      <view wx:if="{{index%column==columnNum}}" class="item">
        <auto-image class="auto-image" src="{{item}}" >
          <view class="count">{{index+1}}</view>
        </auto-image>
      </view>
    </block>
  </block>
</view>

index.wxss

 .masonry {
   --gap: 1px;
   column-count: 2;
   column-gap: var(--gap);
   width: 100%;
 }

 .item {
   width: 100%;
   padding-bottom: var(--gap);
   transition: all .3s ease-in-out;
 }

 .count {
   display: flex;
   height: 100%;
   width: 100%;
   font-size: 80px;
   font-weight: bold;
   align-items: center;
   justify-content: center;
 }

方案二

index2

采用position: absolute;根据元素的高、距离顶部的距离、进行排列。

index.json

引入组件

{
  "usingComponents": {
    "auto-image":"/components/auto-image/index"
  },
  "navigationBarTitleText": "瀑布流"
}

index.js

// 图片大小范围
const minWidth = 200;
const minHeight = 250;
const maxWidth = 400;
const maxHeight = 500;
// 每次加载数量
const pageSize = 20;
// 获取图片地址
function getPlacekitten() {
  const rw = minWidth + Math.round(Math.random() * (maxWidth - minWidth))
  const rh = minHeight + Math.round(Math.random() * (maxHeight - minHeight))
  return `https://placekitten.com/${rw}/${rh}`
}
// 加载图片信息
function getImageInfo(src) {
  return new Promise((resovle) => {
    wx.getImageInfo({
      src,
      success: resovle
    })
  })
}
Page({
  data: {
    column: 3, // 列数
    gap: 2, // 间距 px
    images: [], // 图片地址 string []
    masonry: [], // 存储位置
    columnList: [] // 储存数据
  },
  onl oad() {
    this.loadMore()
  },
  async loadMore() {
    const { images } = this.data
    for (let i = 0; i < pageSize; i++) {
      let src = getPlacekitten();
      // 调整加载顺序
      await getImageInfo(src)
      this.setData({ [`images[${images.length}]`]: src })
    }
  },
  onReachBottom() {
    this.loadMore()
  },
  // 图片加载完成回调
  handleAutoImageLoaded(e) {
    const { index } = e.currentTarget.dataset;
    this.handlePosition(index, e.detail)
  },
  // 处理自动位置
  handlePosition(index, rect) {
    const { column, columnList } = this.data
    // 初始化列
    if (columnList.length === 0) for (let i = 0; i < column; i++) {
      columnList[i] = []
    }
    // 求最短的
    let shortIndex = -1;
    let shortHeight = -1;
    for (let i = 0; i < columnList.length; i++) {
      let tmpColList = columnList[i];
      // 数组最后一个位置
      let tmpLast = tmpColList[tmpColList.length - 1];
      // 判断上一个位置
      let tmpHeight = (tmpLast?.top ?? 0) + (tmpLast?.height ?? 0);
      if (shortHeight > tmpHeight || shortHeight === -1) {
        shortIndex = i;
        shortHeight = tmpHeight;
      }
    }
    rect.top = shortHeight > 0 ? shortHeight + this.data.gap : shortHeight;
    rect.left = shortIndex / column
    rect.style = `top:${rect.top}px;left:${rect.left * 100}%;`;
    columnList[shortIndex].push(rect)
    this.data.columnList = columnList;
    this.setData({ [`masonry[${index}]`]: rect })
  }
})

index.wxss

 .masonry {
   --gap: 2px;
   width: calc(100% - var(--gap));
   position: relative;
   margin-left: var(--gap);
 }

 .masonry-item {
   position: absolute;
   width: calc(100% / var(--column));
   padding-right: var(--gap);
   box-sizing: border-box;
 }


 .count {
   display: flex;
   height: 100%;
   width: 100%;
   font-size: 80px;
   font-weight: bold;
   align-items: center;
   justify-content: center;
 }

index.wxml

<view class="masonry" style="--column:{{column}};--gap:{{gap}}px;">
  <block wx:for="{{images}}" wx:key="unique">
    <view class="masonry-item" style="{{masonry[index].style}}">
      <auto-image class="auto-image" src="{{item}}" bind:loaded="handleAutoImageLoaded" data-index="{{index}}">
        <view class="count">{{index+1}}</view>
      </auto-image>
    </view>
  </block>
</view>

源码

https://developers.weixin.qq.com/s/Ce2rvdm47RDn

标签:index,const,微信,100%,布局,height,width,瀑布,let
From: https://www.cnblogs.com/linyisonger/p/16817800.html

相关文章

  • 爬取古诗词,优化微信公众号的被动回复用户消息功能
    数据抓取花了小一周的空闲时间,爬取了小2千条诗人数据和2万多条古诗词数据,为自动回复使用 自动回复首次关注公众号,推送信息按照诗人朝代划分#朝代DYNASTY={......
  • 基于FastApi的微信公众号开发
    个人申请的订阅号,未认证,可用功能可在 微信公众号平台 - 接口权限 处查看使用代码开发,首先需要在 基础配置-服务器配置 中进行设置 填写服务器地址(URL)、Token和Enc......
  • Material Design基础 - 响应式布局网格
    响应式布局网格MaterialDesign的响应式布局网格可根据屏幕大小和方向进行调整,确保布局的一致性。Columns,gutters,andmargins响应式布局网格由三个元素组成:Columns,......
  • uniapp微信小程序内部跳转其他微信小程序
        uniapp小程序内点击某个按钮跳转另外一个小程序连接,具体实现步骤如下:<viewclass="home-Item"@click="goNativeindex"><imageclass="home-Item-img......
  • 二 类微信界面
    一、设计要求上次仅完成微信界面的初始化和微信界面的切换功能,这次在上次作业的基础上增加列表项的单项点击功能,实现最新的activityforresult功能。二、设计步骤1.新建一个......
  • 想到一种用json描述Qt弹性布局的方式
    规则:列表第一项描述 QHBox or QVBox 第二项描述是否可拉伸,也就是QBox or QSplitter列表可嵌套 渲染:deffun(self,ui):ifui[0]=="H":......
  • 微信开发SDK java版,支持maven;微信Java开发工具包,支持包括微信支付、开放平台、公众号
    本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/281开发微信公众号的sdk-java版名称:weixin-java-toolsgithub地址:https:......
  • #Android studio 微信页面制作(二)
    今天继续用Androidstudio实现微信页面的制作首先打开项目看看之前的进展。这里我在第一次制作的基础上,使用recycleview等控件对联系录页面进行了新的UI设计布局。本次......
  • 微信实时线报推送福利
    一时撸线报一时爽,一直撸线报一直爽。通常我们在各大线报报站薅羊毛撸现金,每次点进去之后基本上已经黄了或者改变规则,而你们获得有效的线报少之又少,大水的线报都是别人撸完......
  • Java实现微信扫码支付(NATIVE方式)[全网最简单]
    基本业务逻辑就是用户访问过来,我们去调微信支付的接口人家返给我们一个二维码我们丢给前端让用户扫码支付就行,等他支付完了微信会回调通知我们支付完了,这个回调的地址......