uni-app:踩坑路---关于使用了transform导致fixed定位不生效的问题

前言:

        继续记录,在上篇文章中,弹出框遮罩层在ios上没有正确的铺盖全屏,是因为机型的原因,也和我们的代码结构有相关的问题。今天再来展示另外一个奇葩的问题。

这次我使用了在本篇博客中的弹出框组件CustomDialog.vue。记录uni-app横屏项目:自定义弹出框-CSDN博客

以及在这篇博客中的CustomItem.vue组件。

uni-app:踩坑路---scroll-view内使用fixed定位,无效的问题-CSDN博客

CustomDialog.vue

<template>
	<view class="dialog-overlay" v-if="visible" :style="{ zIndex: zIndex }" @tap="closeMask">
		<view class="dialog" v-if="dialogVisible" :style="[getStyle]" :class="[showAnimate ? 'bounce-enter-active' : 'bounce-leave-active']" @tap.stop>
			<view class="close" v-if="showClose" @tap="close">
				<view class="iconfont icon-guanbi"></view>
			</view>
			<slot></slot>
		</view>
	</view>
</template>

<script>
export default {
	name: 'CustomDialog',
	props: {
		visible: {
			type: Boolean,
			default: false
		},
		width: {
			type: String,
			default: 'auto'
		},
		height: {
			type: String,
			default: 'auto'
		},
		radius: {
			type: String,
			default: '16rpx'
		},
		bgColor: {
			type: String,
			default: '#fff'
		},
		customStyle: {
			type: Object,
			default: () => ({})
		},
		/* 是否展示右上角关闭按钮 */
		showClose: {
			type: Boolean,
			default: true
		},
		/* 是否点击遮罩层可以关闭弹出框 */
		maskCloseAble: {
			type: Boolean,
			default: true
		},
		/* 弹出框层级 */
		zIndex: {
			type: Number,
			default: 999
		}
	},
	data() {
		return {
			dialogVisible: this.visible,
			showAnimate: this.visible,
			timer: null
		};
	},
	beforeDestroy() {
		this.clearTimeout();
	},
	watch: {
		visible: {
			handler(val) {
				setTimeout(() => {
					this.dialogVisible = val;
					this.showAnimate = val;
				}, 50);
			},
			immediate: true
		}
	},
	computed: {
		getStyle() {
			return {
				width: this.width,
				height: this.height,
				background: this.bgColor,
				borderRadius: this.radius,
				...this.customStyle
			};
		}
	},
	methods: {
		clearTimeout() {
			if (this.timer) {
				clearTimeout(this.timer);
				this.timer = null;
			}
		},

		closeMask() {
			if (!this.maskCloseAble) return;
			this.close();
		},

		close() {
			this.closeAnimate();
			this.timer = setTimeout(() => {
				this.$emit('close');
				this.$emit('update:visible', false);
			}, 500);
		},

		closeAnimate() {
			this.showAnimate = false;
			this.clearTimeout();
		}
	}
};
</script>

<style lang="scss" scoped>
.dialog-overlay {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: rgba(#000, 0.3);
}

.dialog {
	position: relative;
	border-radius: 16px;
	padding: 20rpx;
	padding-bottom: 14rpx;
	margin-left: -50rpx;
	opacity: 0;

	.close {
		position: absolute;
		width: 28rpx;
		height: 28rpx;
		border-radius: 50%;
		background-color: rgba(#000, 0.6);
		top: -10rpx;
		right: -10rpx;

		.icon {
			width: 10rpx;
			height: 10rpx;
		}
	}
}

/*  打开与关闭的类名 */
.bounce-enter-active {
	animation: bounceIn 0.5s both;
}
.bounce-leave-active {
	animation: bounceOut 0.5s both;
}

/* 定义bounceIn动画 */
@keyframes bounceIn {
	0% {
		opacity: 0;
		transform: scale(0);
	}
	50% {
		opacity: 1;
		transform: scale(1.2);
	}
	70% {
		opacity: 1;
		transform: scale(0.9);
	}
	100% {
		opacity: 1;
		transform: scale(1);
	}
}
/* 定义 bounceOut 动画 */
@keyframes bounceOut {
	0% {
		opacity: 1;
		transform: scale(1);
	}
	25% {
		opacity: 1;
		transform: scale(0.95);
	}
	50% {
		opacity: 0;
		transform: scale(1.1);
	}
	100% {
		opacity: 0;
		transform: scale(0);
	}
}

.icon-guanbi {
	color: #94ffd8;
	font-size: 16rpx;
}
</style>

CustomItem.vue

<template>
	<view class="">
		<view class="item" @click="visible = true"></view>

		<view class="mask" v-if="visible" @click="visible = false"></view>
	</view>
</template>

<script>
export default {
	name: 'CustomItem',
	data() {
		return {
			visible: false
		};
	}
};
</script>

<style lang="scss" scoped>
.item {
	width: 100rpx;
	height: 100rpx;
	background-color: #00aaff;
}
.mask {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(#000, 0.5);
}
</style>

页面使用:

<template>
	<view class="index">
		<button @click="visible = true">click</button>
		<custom-dialog :visible.sync="visible" width="500rpx" height="200rpx">
			<view class="list">
				<custom-item class="item" v-for="i in 3" :key="i"></custom-item>
			</view>
		</custom-dialog>
	</view>
</template>

<script>
import CustomDialog from '@/components/CustomDialog/index.vue';
import CustomItem from '@/components/CustomItem/index.vue';
export default {
	components: {
		CustomDialog,
		CustomItem
	},
	data() {
		return {
			visible: false
		};
	}
};
</script>

<style lang="scss" scoped>
.index {
	width: 100vw;
	height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
}
.list {
	padding: 20rpx;
	display: flex;
	align-items: center;
	.item {
		margin-right: 20rpx;
	}
}
</style>

和上篇文章中不同的是,这次可并没有使用scroll-view组件,只是在弹出框组件内使用了另一个Item组件而已,但是效果却大大出乎了意料 !

弹出框显示:一切ok

 点击蓝色方块,展示一个遮罩层:没想到这个遮罩层他又又又被截断了,没有去正确的铺满全屏。。。这次又是为什么?

经过我一层层的排出,最后得出了一个惊人的结论,居然和我的弹出框组件有关,还是最让人意想不到的css的transform属性。transform对普通元素的N多渲染影响,这篇文章就说明的相当详细。

下面我把所有关于transform都给注释掉了,然后再去尝试点击蓝色方块。

/* 定义bounceIn动画 */
@keyframes bounceIn {
	0% {
		opacity: 0;
		// transform: scale(0);
	}
	50% {
		opacity: 1;
		// transform: scale(1.2);
	}
	70% {
		opacity: 1;
		// transform: scale(0.9);
	}
	100% {
		opacity: 1;
		// transform: scale(1);
	}
}
/* 定义 bounceOut 动画 */
@keyframes bounceOut {
	0% {
		opacity: 1;
		// transform: scale(1);
	}
	25% {
		opacity: 1;
		// transform: scale(0.95);
	}
	50% {
		opacity: 0;
		// transform: scale(1.1);
	}
	100% {
		opacity: 0;
		// transform: scale(0);
	}
}

 ok,彻底告别地球了。。。

既然问题已经找到,那就看怎么解决了。。。

1.不再使用transform属性,改用其他的属性编写动画,当然结论就是会发现动画没有使用transform丝滑就是了。

2.老办法,保留transform属性,但是需要避免在其子元素上使用fixed定位,如果非要使用,那就需要考虑将fixed的元素拿出去,这点其实在VUE3中解决起来很方便。。。毕竟一个teleport就可以直接将元素指定到对应的元素上。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay丶萧邦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值