一、项目描述
- 使用框架
uniapp
,需要兼容微信小程序
、H5
- 实现功能相册
瀑布流
及多选-全选功能
实现效果:
实现思路
1.函数说明:传入一个数组,循环获取图片高度,会根据把原数组拆分成两个数组,放在两列,
1.计算单列累计高度,对比高度值的大小,实现瀑布流的布局,
1.由于获取图片高度需要一定的时间,所以使用async await 阻塞for 循环的进程,
1.每获取到一个图片的高度就赋值渲染到页面上,实现加载出一个图片就先渲染上去,达成图片懒加载的效果
代码实现
1.封装waterFall页面组件
HTML:
//通过使用scroll-view实现
<scroll-view
style="height: 490px; overflow: hidden;"
scroll-y="true"
class="scroll-Y"
@scrolltolower="loadMoreImages"
>
// 内容主体
<view class="main">
//相册左半部
<div class="view Left">
<div class="content" v-for="(item, index) in firstList" :key="index">
<div class="img-content">
<image v-if="item.small_img" :src="item.small_img" class="image"
mode="widthFix" :data-index="index" data-type="1"/>
<div v-if="select"
:class="['select-ele',{ selected: selectList.includes(item) },]"
@click="selected(item)"
>
<div class="checkbox iconfont"></div>
</div>
</div>
</div>
</div>
//相册右侧
<div class="view Right">
<div
class="content"
v-for="(item, index) in secondList"
:key="index"
>
<div class="img-content">
<image
v-if="item.small_img"
:src="item.small_img"
class="image"
mode="widthFix"
:data-index="index"
data-type="2"
/>
<div
v-if="select"
:class="['select-ele',{ selected: selectList.includes(item) },]"
@click="selected(item)"
>
<div class="checkbox iconfont"></div>
</div>
</div>
</div>
</div>
<div class="footer" v-if="select">
<div class="all-check" @click="selectAll">
<div:class="['checkbox iconfont',{ selected: allSelected },]"></div>
<span>全选</span>
</div>
<div class="func-btn" @click="cancel">取消</div>
<div class="func-btn confirm" @click="confirm">确认</div>
</div>
</view>
</scroll-view>
- 2.多选/全选实现思路
- 1.通过设置
Css样式动态绑定
点击相册的每一项 - 1.调用
@click="selected(item)"
方法获取点击相册数据 - 2.调用
@click="selectAll"
方法获取相册全部数据
- 1.通过设置
Js:
<script>
import { myPhotos } from "@/api/api";
export default {
props: {
select: {
type: Boolean,
default: false,
},
},
data() {
return {
showImg: false,
dataList: [], // 数据源
firstList: [], // 第一列数组
secondList: [], // 第二列数组
windowWidth: 0, // 页面视图宽度
windowHeight: 0, // 视图高度
imgMargin: 0, // 图片边距: 单位px
imgWidth: 0, // 图片宽度: 单位px
pageSize: 8,
scrollHeight: "0",
last: false,
page: 1,
like: true,
i: 0,
photoParams: {
type: 4, // 1购买 2打赏 3点赞 4有我的图片
page: 1,
size: 10,
},
selectList: [],
};
},
mounted() {
// 我是在组件中获取数据,逻辑需求不同,可以选择传进
this.getGoodthingList();
},
created() {
// 后期获取滚动条的长度-小伙伴们可以删除
this.init();
this.initScrollHeight();
},
//通过计算获取所有图片数据
computed: {
allSelected: {
get() {
return this.selectList.length >= this.dataList.length;
},
set(val) {
if (val) {
console.log(val);
this.selectList = [...this.dataList];
} else {
this.selectList = [];
}
},
},
},
methods: {
//获取多选数据
selected(item) {
const index = this.selectList.findIndex(
(i) => i.id === item.id
);
if (index >= 0) {
this.selectList.splice(index, 1);
this.selectList = [...this.selectList];
} else {
this.selectList.push(item);
}
},
selectAll() {
this.allSelected = !this.allSelected;
},
cancel() {
this.selectList = [];
this.$emit("parentBtnSelect", false);
this.$emit("cancel");
},
confirm() {
if (!this.selectList.length) {
uni.showToast({ title: "请选择图片", icon: "none" });
return;
}
console.log(this.selectList, "this.selectList");
this.$emit("confirm", this.selectList);
this.selectList = [];
this.$emit("parentBtnSelect", false);
},
init() {
this.dataList = [];
this.firstList = [];
this.secondList = [];
this.last = false;
this.imgMargin = 0; // 图片边距: 单位px
this.pageSize = 8;
this.page = 1;
this.i = 0;
// debugger
},
initScrollHeight() {
let _self = this;
uni.getSystemInfo({
success: function(res) {
_self.scrollHeight = res.windowHeight + "px" / 2;
},
});
},
// 获取数据
getGoodthingList() {
myPhotos(this.photoParams).then((res) => {
if (res.data.code == 1) {
if (res.data.result.pics == null) {
return uni.showToast({
title: "非常抱歉没有找到相关信息",
icon: "none",
});
}
this.photoParams.page++;
uni.hideLoading();
this.last = res.data.success || false;
//拼接获取数据
this.dataList = [
...this.dataList,
...res.data.result.pics,
];
this.setDataList(res.data.result.pics,"small_img");
}
});
},
//计算图片的长宽
async setDataList(
arr = data,
attributeName,
otherHeight = 100,
minHeight = 10,
maxHeight = 1000
) {
var arr1 = [],
arr2 = [],
imgMargin = 0, //图片边距
height1 = 0, //第一组图片累计高度
height2 = 0; //第二组图片累计高度
// var getSystemInfo = await wx.getSystemInfo()
for (let i = 0; i < arr.length; i++) {
try {
let heightData = await uni.getImageInfo({src: "https:" + arr[i][attributeName],
});
let ImgHeight =
heightData.length == 1? minHeight: heightData[1].height;
//如果长度等于1,就是图片有问题,这时候设置一个默认高度,如果长度等于 2,下标1就有图片高度
let imgWidth =
heightData.length == 1? minHeight: heightData[1].width; //如果长度等于1,就是图片有问题,
let height = ImgHeight;
if (height < minHeight) height = minHeight;
if (height > maxHeight) height = maxHeight;
if (height1 <= height2) {
height1 += height;
this.firstList.push(arr[i]);
} else {
height2 += height;
this.secondList.push(arr[i]);
}
// console.log('arr2',height1,height2,arr1,arr2);
} catch (err) {
console.log("getImageInfo-err", err);
}
}
},
// 加载更多图片
loadMoreImages: function() {
if (!this.last) {
uni.showLoading({
title: "加载中...",
});
this.getGoodthingList();
} else {
this.getGoodthingList();
}
uni.hideLoading();
},
},
};
</script>
CSS
<style scoped lang="scss">
.page {
width: 100%;
}
.main {
width: 100%;
.view {
width: 50%;
display: inline-block !important;
position: relative;
vertical-align: top;
padding: 5rpx;
box-sizing: border-box;
.content {
border-radius: 4px;
margin-bottom: 6rpx;
box-sizing: border-box;
.img-content {
position: relative;
.image {
width: 100%;
height: 100%;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
box-sizing: border-box;
display: block;
}
}
}
.select-ele {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
&.selected {
background-color: rgba(255, 255, 255, 0.3);
.checkbox {
display: flex;
align-items: center;
justify-content: center;
background-color: #2147f1;
border-color: #2147f1;
&::before {
content: "\e62d";
font-size: 20rpx;
color: #fff;
}
}
}
.checkbox {
position: absolute;
right: 18rpx;
top: 18rpx;
width: 36rpx;
height: 36rpx;
border-radius: 4rpx;
border: 2rpx solid #ffffff;
}
}
}
.footer {
position: fixed;
left: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
height: 100rpx;
background-color: #fff;
z-index: 22;
.all-check {
position: absolute;
left: 30rpx;
display: flex;
align-items: center;
font-size: 26rpx;
font-weight: 400;
color: #666666;
line-height: 39rpx;
.checkbox {
width: 36rpx;
height: 36rpx;
margin-right: 14rpx;
border-radius: 4rpx;
border: 2rpx solid #bababa;
&.selected {
display: flex;
align-items: center;
justify-content: center;
background-color: #2147f1;
border-color: #2147f1;
&::before {
content: "\e62d";
font-size: 20rpx;
color: #fff;
}
}
}
}
.func-btn {
width: 220rpx;
height: 70rpx;
margin-right: 30rpx;
font-size: 30rpx;
font-weight: 500;
color: #666666;
line-height: 70rpx;
text-align: center;
background: #ececec;
border-radius: 35rpx;
&.confirm {
color: #fff;
background: #dd4e4e;
}
}
}
}
</style>