原理很简单,计算图片的宽高,再计算每列的使用高度,然后再将当前图片放置在列高最小的一列。其实这种方式使用什么方式布局都无所谓,我使用的是flexd布局。Flex的使用在这里就不讲解了,网上的教程一大堆。这里讲解使用VUE3实现,并封装成可以使用的组件。
话不多说,上效果
代码已开源,可参考源码图片资源加载部分。
github地址:https://github.com/jiwaiwai-loading/h5-editor
开源项目说明查看上一篇文章:耗时半年,开源了我精心开发的html5编辑器,可通过拖拉拽生成漂亮的HTML页面。
以下是这部分的核心代码。
template
<template>
<div :id=\\\"fluidId\\\" v-infinite-scroll=\\\"loadMore\\\" :infinite-scroll-distance=\\\"20\\\" :infinite-scroll-immediate=\\\"false\\\" class=\\\"uabs uof-x uof-y-s\\\">
<div v-if=\\\"imgList.length > 0\\\" class=\\\"ub ub-f1 upad-rl06\\\">
<div v-for=\\\"i in col\\\" :key=\\\"i\\\" class=\\\"ub ub-f1 ub-ver\\\" :style=\\\"\\\'margin-left:\\\' + (i != 1 ? gutter : 0) + \\\'px\\\'\\\">
<el-image v-for=\\\"img, idx in imgList[i - 1]\\\" @click=\\\"emit(\\\'getData\\\', img)\\\" @dragstart=\\\"emit(\\\'dragstart\\\', img)\\\" @dragend=\\\"emit(\\\'dragend\\\', img)\\\" :key=\\\"idx\\\" :src=\\\"img.url || img.thumbnailUrl\\\" loading=\\\"lazy\\\" fit=\\\"scale-down\\\" class=\\\"img-hover uba ushadow\\\" :style=\\\"\\\'margin-top:\\\' + gutter + \\\'px\\\'\\\">
<template #error>
<el-icon class=\\\"ub ub-ac ub-pc ub-fv ub-fh uc-font-gray2 uf-s2\\\" style=\\\"height: 50px;\\\">
<Picture />
</el-icon>
</template>
</el-image>
</div>
<div class=\\\"uhide\\\">
<el-image v-for=\\\"img, idx in data\\\" :key=\\\"idx\\\" :src=\\\"img.url || img.thumbnailUrl\\\" @load=\\\"load(img)\\\" @error=\\\"error(img)\\\" fit=\\\"scale-down\\\"></el-image>
</div>
</div>
<el-empty v-if=\\\"data.length==0 && isReturn\\\" :image-size=\\\"100\\\"></el-empty>
<div v-else class=\\\"ub ub-ac ub-pc upad-t1\\\">
<el-button v-if=\\\"hasMore\\\" type=\\\"info\\\" link :loading=\\\"!loadOver\\\" @click=\\\"loadMore\\\">
{{ loadOver ? \\\'more\\\' : \\\'loading\\\' }}
<el-icon v-show=\\\"loadOver\\\">
<ArrowDownBold />
</el-icon>
</el-button>
<el-divider v-else><span class=\\\"uf-s06 uc-font-gray1\\\">No more</span></el-divider>
</div>
</div>
</template>
以上代码的主要部分是隐藏图片加载,计算当前图片的宽高。
javascript
<script setup>
import {
ref,
onMounted
} from \\\'vue\\\';
import { ArrowDownBold } from \\\'@element-plus/icons-vue\\\';
const emit = defineEmits([\\\'loadMore\\\', \\\'getData\\\', \\\'dragstart\\\']);
const props = defineProps({
col: {
type: Number,
default: 2
},
gutter: {
type: Number,
default: 10
},
data: {
type: Array,
default: []
},
hasMore: {
type: Boolean,
default: false
},
isReturn: {
type: Boolean,
default: false
}
});
const fluidId = ref(new Date().getTime());
let colWidth = 0;
let imgTotalHeight = [];
const imgList = ref([]);
let loadCount = 0;
const loadOver = ref(false);
const load = (img) => {
if (colWidth == 0) {
const dom = document.getElementById(fluidId.value);
colWidth = (dom.clientWidth / props.col) - (props.col - 1) * props.gutter;
}
const temImg = new Image();
temImg.src = img.url || img.thumbnailUrl;
temImg.onload = function () {
const width = temImg.width;
const height = temImg.height;
const minTotalHeight = Math.min(...imgTotalHeight);
const colIdx = imgTotalHeight.indexOf(minTotalHeight);
img.width = width;
img.height = height;
imgTotalHeight[colIdx] += (height * colWidth) / width;
imgList.value[colIdx].push(img);
loadCount++
if (loadCount == props.data.length) {
loadOver.value = true;
}
}
}
const error = (img) => {
const height = 50;
const minTotalHeight = Math.min(...imgTotalHeight);
const colIdx = imgTotalHeight.indexOf(minTotalHeight);
imgTotalHeight[colIdx] += height;
imgList.value[colIdx].push(img);
loadCount++;
if (loadCount == props.data.length) {
loadOver.value = true;
}
}
const loadMore = () => {
if (props.hasMore) {
loadOver.value = false;
emit(\\\'loadMore\\\', true);
}
}
const init = () => {
loadCount = 0;
loadOver.value = false;
imgTotalHeight = [];
imgList.value = [];
for (let i = 0; i < props.col; i++) {
imgTotalHeight.push(0);
imgList.value.push([]);
}
}
defineExpose({ init });
onMounted(() => {
init();
})
</script>
以上代码核心代码为load方法,计算图片的宽高,再计算每列的高度,将图片放置在较矮的那一列。
接收的Props
col:展示的列数
gutter: 每列之前的距离,单位px
data: 图片列表,如:[{url:url1},{url:url2}]
hasMore: 是否有更多,为true向下滚动可自动加载
isReturn:展示loading用
暴露的方法
loadMore:加载更多
getData:点击当前图片
dragstart:拖拽当前图片
style
.ub {
position: relative;
display: -webkit-flex;
display: flex;
flex-direction: row;
}
.ub-ac {
justify-content: center;
}
.ub-pc {
align-items: center;
}
.ub-fh {
width: 100%;
}
.ub-fv {
height: 100%;
}
.fluid-img {
border-radius: 5px;
overflow: hidden;
min-height: 30px;
}
代码简单,定制化强,不妨试试。
原创文章,作者:网络技术联盟站,如若转载,请注明出处:https://www.sudun.com/ask/49756.html