响应式卡片布局 保持外部容器和内部图片高宽比例不变 父容器card包裹子容器 子容器有多个图片情况下
方案一 网格布局grid-template-columns: repeat(auto-fit, minmax(200px, 0.7fr)); + 背景图 padding法
父card 外部wrapper容器
:deep(.dataset-list-card-scroll) {
display: grid;
// 每行card自适应铺满 最小宽度为200px 最大为0.7倍剩余空间
grid-template-columns: repeat(auto-fit, minmax(200px, 0.7fr));
// gap: 10px;
justify-content: center;
.listcard {
padding: 10px;
}
}
子组件card内部 图片需要为背景图
<div class="banner-img" :style="`background:url( ${getPcImgUrl()})`">
.banner-img-full{
width: 100%;
height: 0;
padding-bottom: 67%;
//覆盖全尺寸 超出部分被裁剪
background-size: cover !important;
//覆盖全尺寸 拉伸长宽适应容器 图片会变形 等于img标签属性 object-fit:fill
background-size: cover !important;
}
方案二: window.addEventListener('resize',()=>{}) 配合背景图或者img标签
创建窗口监听hook useFlowLayout.js 通过监听窗口变化 window.addEventListener('resize',()=>{})
import { reactive, onMounted, toRefs } from 'vue';
/**
* 动态计算卡片宽高和间距
*
* @param className 卡片可视区域父节点元素类名
* @param extraHeight 卡片文字部分 或者其他部分 固定的额外高度 大小不会随着窗口变化改变
* @param beReducedWidth 基于非异步加载的父容器 需要减掉的两边padding值
*/
export function useFlowLayout(className: string, extraHeight = 0, beReducedWidth = 30) {
const listCardCss = reactive<{
// 卡片动态宽度
cardWidth: string;
// 卡片动态高度
cardHeight: string;
// 卡片之间动态padding
paddingX: string;
// 可调节宽度进度条 card 最大宽度 保持和父级dom宽度一致,最多放大到每行一个卡片
maxSliderWidth: number;
// 卡片区域高度 (未添加extraHeight)
cardHeightPure: string;
}>({
cardWidth: '100px',
cardHeight: '100px',
cardHeightPure: '100px',
paddingX: '10px',
maxSliderWidth: 900,
});
// 页面设置卡片大小进度条改变时触发回调给宽度重新赋值
const changeWidth = (sliderValue: number) => {
if (sliderValue <= 200) {
sliderValue = 200;
}
listCardCss.cardWidth = sliderValue + 'px';
listCardCss.cardHeight = sliderValue / 1.5 + extraHeight + 'px';
};
const getCssConfig = (contenWidthNum: number) => {
if (contenWidthNum <= 200) {
contenWidthNum = 200;
}
// const tagnum = Math.floor(contenWidthNum / 300);
const tagnum = Math.ceil(contenWidthNum / 300);
listCardCss.maxSliderWidth = contenWidthNum;
const cardWidth = Math.floor(contenWidthNum / tagnum);
listCardCss.cardWidth = cardWidth + 'px';
listCardCss.cardHeight = Math.floor(contenWidthNum / tagnum) / 1.5 + extraHeight + 'px';
listCardCss.cardHeightPure = Math.floor(contenWidthNum / tagnum) / 1.5 + 'px';
};
// 重置页面卡片宽度
const resetWidth = () => {
getCssConfig(listCardCss.maxSliderWidth);
};
const { cardHeight, cardHeightPure, cardWidth, paddingX, maxSliderWidth } = toRefs(listCardCss);
onMounted(() => {
setTimeout(() => {
const box = document.getElementsByClassName(className)[0];
let wrapwidth = window.getComputedStyle(box, null)['width'];
if (!wrapwidth.includes('px')) {
const boxHeader = document.getElementsByClassName('basic-layout-multiple-header')[0];
const wrapwidthNum = parseInt(window.getComputedStyle(boxHeader, null)['width']);
wrapwidth = wrapwidthNum - 230 + 'px';
}
let contenWidthNum = Number(wrapwidth.replaceAll('px', '')) - beReducedWidth;
getCssConfig(contenWidthNum);
window.addEventListener('resize', function () {
wrapwidth = window.getComputedStyle(box, null)['width'];
contenWidthNum = Number(wrapwidth.replaceAll('px', '')) - beReducedWidth;
getCssConfig(contenWidthNum);
});
}, 0);
});
return {
cardHeight,
cardWidth,
paddingX,
changeWidth,
cardHeightPure,
resetWidth,
maxSliderWidth,
};
}
父组件使用hook
let { cardHeight, cardWidth, paddingX } = useFlowLayout('basic-datasetList-list', 105);
//样式绑定
:deep(.dataset-list-card-scroll) {
display: grid;
grid-template-columns: repeat(auto-fill, v-bind(cardWidth));
// gap: 10px;
justify-content: center;
.listcard {
padding: v-bind(paddingX);
height: v-bind(cardHeight);
}
子组件有2种处理方式
1.子组件card 中图片以背景图展示 同方案一子组件处理方式相同
2.子组件中图片以img标签展示
图片区域高宽设置百分比
如果包含额外固定高度110px
那么可以设置图片容器部分 height: calc(100% - 110px);