本次需求新更~
总能有些奇奇怪怪的需求,这次需求这样定义的:
打开app后台管理系统如果配置了图片,就自适应显示在首页;
配置多张,点击关闭,下一张打开,以此类推
首先想到的问题:
没有定义弹框的宽高,而是根据图片的宽高,去自适应每个图片的大小,那么我们一张配置1000, 一张配置500, 一张配置250,那显示的每张图片关闭后的效果大小图片都是不一样的~
主要更改说明:
弹框控制逻辑:
添加了 currentPopupIndex 来控制当前显示的弹框
通过 v-if 控制弹框的显示和隐藏
添加了 handleClose 方法来处理弹框的关闭和切换
样式适配:
使用 position: fixed 创建全屏遮罩
弹框内容区域使用 max-width 和 max-height 控制最大尺寸
图片使用 max-width: 100% 和 max-height: 90vh 确保在容器内自适应显示
添加了关闭按钮样式
图片自适应:
使用 object-fit: contain 确保图片保持原比例并完整显示
通过 max-width 和 max-height 控制图片不会超出屏幕范围
这样实现后:
弹框会根据图片尺寸自动调整大小
图片会保持原比例显示
点击关闭按钮会显示下一个弹框
所有弹框显示完后会完全关闭
弹框不会超出屏幕范围
适配各种屏幕尺寸
你可以根据需要调整样式中的具体数值,比如间距、最大宽高比例等。
中途遇到一个问题,设置了宽100%,显示的话却是90%;
使用 Teleport 将弹框组件传送到 body 元素下,避免被其他容器样式影响
使用 inset: 0 替代分别设置位置
使用 vw 和 vh 单位确保真正占满视口
添加 margin: 0 和 padding: 0 确保没有额外的间距
<template>
<Teleport to="body">
<div
v-if="
currentPopupIndex !== -1 &&
diaData[$global.AD_POSITION_HOME_POPUP]?.[currentPopupIndex]
"
class="popup-container"
>
<div class="popup-content">
<img
:src="diaData[$global.AD_POSITION_HOME_POPUP][currentPopupIndex].pic"
@click="$adRouter(diaData[$global.AD_POSITION_HOME_POPUP][currentPopupIndex])"
/>
<div class="close-btn" @click="handleClose">×</div>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue';
import { getAdList } from "@/api/base";
const { proxy } = getCurrentInstance();
const diaData = ref({});
const currentPopupIndex = ref(0); // 控制当前显示的弹框索引
const handleClose = () => {
if (currentPopupIndex.value < diaData.value[proxy.$global.AD_POSITION_HOME_POPUP].length - 1) {
// 如果还有下一个弹框,显示下一个
currentPopupIndex.value++;
} else {
// 所有弹框都显示完了,设置为-1表示全部关闭
currentPopupIndex.value = -1;
}
};
getAdList({
regionType: [proxy.$global.AD_POSITION_HOME_POPUP],
}).then((res) => {
console.log("首页弹框的数据", res);
diaData.value = res.data || {};
});
</script>
<style lang="scss" scoped>
.popup-container {
position: fixed;
inset: 0; // 使用 inset 替代分别设置 top, right, bottom, left
width: 100vw; // 使用 vw 单位
height: 100vh; // 使用 vh 单位
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
margin: 0; // 确保没有外边距
padding: 0; // 确保没有内边距
}
.popup-content {
position: relative;
max-width: 90vw;
max-height: 90vh;
img {
max-width: 100%;
max-height: 90vh;
object-fit: contain;
}
}
.close-btn {
position: absolute;
top: -40px;
right: -40px;
width: 30px;
height: 30px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 20px;
color: #333;
&:hover {
background: #fff;
}
}
</style>
完成, diaData.value[proxy.$global.AD_POSITION_HOME_POPUP]这里面就是个数组对象,大家可以去模拟
之后我这边的参考路径: src\views\home\components\HomeDialog.vue (fzh5)
11.27需求又迭代更新~
这次需求变更: 前景就是,弹框配置太多张图片,他们显示的太多了,导致太烦, 后台管理系统增加了一个配置的数值,限制次数显示弹框弹出的数量的
<script setup>
import { ref, getCurrentInstance, onMounted } from "vue";
import { getAdList, getConfing } from "@/api/base";
const { proxy } = getCurrentInstance();
const diaData = ref({});
const currentPopupIndex = ref(-1); // 默认设为-1,表示不显示
const maxShowCount = ref(0); // 存储最大显示次数
// 获取今天已经显示的次数
const getTodayShowCount = () => {
const today = new Date().toDateString();
const storageKey = 'popupShowCount_' + today;
return parseInt(localStorage.getItem(storageKey) || '0');
};
// 增加显示次数
const incrementShowCount = () => {
const today = new Date().toDateString();
const storageKey = 'popupShowCount_' + today;
const currentCount = getTodayShowCount();
localStorage.setItem(storageKey, (currentCount + 1).toString());
};
// 检查是否可以显示弹框
const checkCanShow = () => {
const currentCount = getTodayShowCount();
return currentCount < maxShowCount.value;
};
const handleClose = () => {
if (
currentPopupIndex.value <
diaData.value[proxy.$global.AD_POSITION_HOME_POPUP].length - 1
) {
currentPopupIndex.value++;
} else {
currentPopupIndex.value = -1;
}
// 每次关闭时增加计数
incrementShowCount();
};
onMounted(async () => {
// 先获取配置的最大显示次数
const configRes = await getConfing({ key: proxy.$global.ImageDialogCount });
maxShowCount.value = parseInt(configRes.data[0].configValue || '0');
// 检查是否可以显示
if (checkCanShow()) {
// 获取广告数据
const adRes = await getAdList({
regionType: [proxy.$global.AD_POSITION_HOME_POPUP],
});
diaData.value = adRes.data || {};
// 如果有广告数据,则显示第一个
if (diaData.value[proxy.$global.AD_POSITION_HOME_POPUP]?.length > 0) {
currentPopupIndex.value = 0;
}
}
});
</script>
主要改动说明:
添加了 maxShowCount 来存储配置的最大显示次数
添加了三个辅助函数:
getTodayShowCount: 获取今天已经显示的次数
incrementShowCount: 增加显示次数
checkCanShow: 检查是否可以显示弹框
使用 localStorage 来存储显示次数,key 中包含日期,这样每天重置计数
修改了 onMounted 的逻辑:
先获取配置的最大显示次数
检查是否可以显示
如果可以显示,再获取广告数据并显示
这样实现后:
每天都会重新计数
当达到配置的最大次数后,不会再显示弹框
显示次数会持久化保存在本地存储中
每次关闭弹框时增加计数
至于这样设置键的存储值
const today = new Date().toDateString();
const storageKey = "popupShowCount_" + today;
const currentCount = getTodayShowCount();
localStorage.setItem(storageKey, (currentCount + 1).toString());
是因为如果配置最大显示10次,用户今天看了5次,第二天来时,会重新从0开始计数
每天都可以看到10次,如果你想要弹框永久限制显示次数
localStorage.setItem(“随便键”, (currentCount + 1).toString());就ok了~
完成
测试测出一个问题,后台管理系统设置弹出次数,可能多弹一次或者两次的问题:
主要改动:
在显示新弹框前先检查次数
在 handleClose 中先增加计数,再决定是否显示下一个
const handleClose = () => {
// 先增加计数
incrementShowCount();
// 检查是否还可以继续显示
if (!checkCanShow()) {
currentPopupIndex.value = -1;
return;
}
// 如果还可以显示,则显示下一个
if (currentPopupIndex.value < diaData.value[proxy.$global.AD_POSITION_HOME_POPUP].length - 1) {
currentPopupIndex.value++;
} else {
currentPopupIndex.value = -1;
}
};