前言
过了这么久,想起自己还有个博客,更点内容吧!
来,上需求!
最近在做个前端界面,要求在一行中展示一些图片,展示的图片数量随着窗口宽度大小进行变化,除此之外还有以下要求:
- 图片要均匀分布;
- 所有图片要完整的填充一整行;
- 图片的大小随着窗口宽度变化自适应调整。
不说了,不说了,上个最终实现效果图。
实现
基本思路
最开始是打算主要依靠 CSS 的布局来实现,几乎把自己了解的布局方式都想了一遍了,最后默默的给自己找了个借口:刚开始学,不要为难自己!不要为难自己!
最终思路:
- 每张图片设定一个最小宽度;
- 当JS监测到窗口宽度变化后获取窗口宽度;
- 计算在当前窗口宽度,使用最小宽度图片的情况下一行中可以容纳的最多图片数量;
- 计算出一行中剩余的空间,然后平均分配给所有图片,得到最终的图片宽度;
- 最后通过 CSS 调整图片大小。
代码实现
测试环境:vite + vue3 + ts + sass
<!--
* @Author : KK
* @Date : 2022-02-19 12:30:41
* @LastEditTime : 2022-02-19 13:58:02
-->
<script setup lang="ts">
import { reactive, onMounted, onUnmounted } from 'vue'
// 计算中心 content 的可视宽度 viewpoint-width,content 占据一行的85%宽度
const vw = () => document.body.clientWidth * 0.85;
const minBoxCnt = 3; // 最少可显示的盒子数量
const maxBoxCnt = 8; // 最多可显示的盒子数量
const boxInfo = reactive({
w: 160, // 盒子的宽度
mw: 160, // 盒子的最小宽度
ratio: 1.45,// 高宽比
gap: 20, // 盒子间的 gap 大小
cnt: 3, // 可显示的盒子数量
})
// 计算中心区域可以容纳的盒子数量并设定盒子的宽度
const cal_box_cnt = () => {
let c = Math.floor(vw() / boxInfo.mw);
c = Math.min(c, maxBoxCnt);
const cal_lave_space = (c: number) => {
return vw() - boxInfo.mw * c - boxInfo.gap * (c - 1);
}
let lave_space = 0;
let width = 0;
if ((lave_space = cal_lave_space(c)) > 0) {
width = boxInfo.mw + lave_space / c;
} else {
c--;
width = boxInfo.mw + cal_lave_space(c) / c;
}
// console.log(lave_space, c, vw());
boxInfo.w = width;
if (c < minBoxCnt) {
boxInfo.w = boxInfo.mw;
}
// console.log(boxInfo.w);
return Math.max(c, minBoxCnt);
}
boxInfo.cnt = cal_box_cnt()
onMounted(() => window.onresize = () => boxInfo.cnt = cal_box_cnt());
onUnmounted(() => window.onresize = null);
</script>
<template>
<div class="outer">
<div class="inner" v-for="item in boxInfo.cnt">
<img src="./assets/bg.jpg" alt="background" />
</div>
</div>
</template>
<style lang="scss">
body {
background-color: darkcyan;
}
#app {
width: 85%;
min-width: 520px; // 160 * 3 + 2 * 20
margin: 100px auto;
background-color: #fff;
}
.outer {
display: flex;
flex-wrap: nowrap;
transition: all 0.5s;
.inner {
img {
width: 100%;
height: 100%;
}
}
.inner:nth-child(n) {
width: v-bind('boxInfo.w + "px"');
height: v-bind('boxInfo.w * boxInfo.ratio + "px"');
margin-right: v-bind('boxInfo.gap + "px"');
}
.inner:last-child {
margin-right: 0;
}
}
</style>