来来来,看啊看,外面的世界多好看, 效果图展示的是瀑布流布局 && 懒加载的效果 数据图片数据来源张鑫旭的网络日志 先说下我们的图片链接格式 所有的链接都是 定义瀑布流布局是一种比较流行的页面布局方式, 最早采用此布局的网站是Pinterest, 图片宽度是固定的,高度自动,产生一种参差不齐的美感。 原理原理很简单,主要分为以下几步 1、定义高度数组和列数 2、遍历元素,个数小于列数的直接 3、大于列数的,获取高度数组中最小的值,定义元素的top和left值 4、 重要一点 更新高度数组,将最小高度加上当前元素的高度 知道原理了,代码应该怎么写呢?这里用web端来示例,大概如下
上面就是实现瀑布流的主要逻辑,这里大概写了下,接下来我们看看小程序怎么实现。 实现在web页面里面我们可以直接获取、操作DOM,实现起来很方便,何况还有很多的jquery插件可以使用。我们知道小程序里面是没有DOM的,那应该怎么实现呢?我们把思路转换下就行了。 这里我们用三种方式来实现瀑布流布局。 CSS使用css3来实现是最简单的,我们先捡简单的来说, 使用 使用 wxml<view class='container'>
<image src='{{item.url}}' wx:if="{{index % 2 != 0 }}" wx:for="{{list}}" mode='widthFix' wx:key="{{index}}"></image>
<image src='{{item.url}}' wx:if="{{index % 2 == 0 }}" wx:for="{{list}}" mode='widthFix' wx:key="{{index}}"></image>
</view> wxss
js获取下数据即可,这里就不赘述了。 节点信息小程序可以通过WXML节点信息API来获取元素的信息,接下来我们来撸码。 wxml<view class="container">
<view wx:for="{{group}}" style='position:{{item.position}}; top: {{item.top}}; left:{{item.left}}; width:{{width}}rpx;' class='box box-{{index}}' wx:key="{{index}}">
<image src='http://cued.xunlei.com/demos/publ/img/P_{{item.name}}.jpg' style=' height:{{height[index]}}px' bindload='load' data-index='{{index}}' class='image'></image>
</view>
</view> wxss
js图片链接为 首先处理我们的数据
然后进行瀑布流布局,主要代码如下 load(e){ // 监听图片加载完 获取图片的高度
this.setData({
height: [...this.data.height, e.detail.height]
})
this.showImg() // 调用渲染函数
},
showImg(){
let height = this.data.height
if (height.lenth != this.data.group .legth){ // 保证所有图片加载完
return
}
setTimeout(()=>{ // 异步执行
wx.createSelectorQuery().selectAll('.box').boundingClientRect((ret) => {
let cols = 2
var group = this.data.group
var heightArr = [];
for (var i = 0; i < ret.length; i++) {
var boxHeight = height[i]
if (i < cols) {
heightArr.push(boxHeight + 25)
} else {
var minBoxHeight = Math.min.apply(null, heightArr);
var minBoxIndex = getMinBoxIndex(minBoxHeight, heightArr);
group[i].position = 'absolute'
group[i].top = `${minBoxHeight}px`
group[i].left = minBoxIndex * this.data.width / 2 + 'px'
group[i].left = minBoxIndex == 0 ? minBoxIndex * this.data.width / 2 + 'px' : minBoxIndex * this.data.width / 2 + 5 + 'px'
heightArr[minBoxIndex] += (boxHeight + 25)
}
}
this.setData({
group
})
wx.hideLoading()
}).exec()
}, 200)
} 可以看到实现的逻辑和上面的大概类似,只不过这里我们修改的是数据,毕竟小程序是数据驱动的嘛。 这里主要我们监听 后端处理数据上面我们说到在小程序内部获取图片的高度是个费力不讨好的事,我们使用node来获取图片高度,然后包装下再给小程序使用。
这里主要说下碰到的问题 1、request模块的请求默认返回来的是个String类型的字符串,使用image-size模块传入的必须是Buffer,怎么破呢?在request请求中设置 2、我们这里爬取了100张图片,怎么保证都已经爬取完了呢?可以这样写
3、如果请求了几次,发现有的图片获取不到了,报错了,怎么回事呢,人家毕竟做了防爬的,恭喜你中奖了,换个ip再试吧(可以把代码放在服务器上面,或者换个Wi-Fi),其实我们只需要爬一次就行,生成完文件还爬干嘛啊。 完整代码请戳 github 我们回到小程序,此时接口返回的数据如下 可以看到每个图片都有高度了,接下来我们实现瀑布流布局,等下,我们搞下瀑布流布局的懒加载,关于小程序的懒加载,猛戳了解更多。 怎么实现呢?主要分为两步 1、将元素瀑布流布局 2、创建IntersectionObserver,进行懒加载 先开始我们的布局吧 wxml<view class='container'>
<view class='pic pic-{{index}}' wx:for="{{list}}" style="height:{{item.height}}px;left:{{item.left}}; top:{{item.top}}; position:{{item.position}}" wx:key="{{item.index}}">
<image src='{{item.url}}' wx:if="{{item.show}}"></image>
<view class='default' wx:if="{{!item.show}}"></view>
</view>
</view> 上面我们使用 使用一个 js我们使用两个for循环,先来进行布局
布局完后,创建IntersectionObserver,动态判断image节点的显示 for (let i in list) {
wx.createIntersectionObserver().relativeToViewport({ bottom: 20 }).observe('.pic-' + i, (ret) => {
if (ret.intersectionRatio > 0) {
list[i].show = true
}
this.setData({
list
})
})
} |
小程序之图片瀑布流(最全实现方式,额外加送懒加载)
本文转载:CSDN博客