vue3自适应登录界面

父组件模板

<template>
	<div class="login-container" ref="loginContainer">
		<div class="login-container-content" ref="loginContainerContent">
			<div class="login-container-content-body">
				<div>
					<div class="login-header">
						<div class="login-title">
							<img :src="logoMini" alt="logo" />
						</div>

						<div class="login-title-desc">这是登录界面的标题</div>
					</div>

					<div class="login-wrap">
						<Account />
					</div>
				</div>
			</div>
			<div class="copyright">Copyright 2021</div>
		</div>
	</div>
</template>

Account组件模板

<template>
	<div class="account-login-container">
		<el-form size="large" class="login-content-form" :rules="rules" ref="ruleFormRef" :model="ruleForm">
			<el-form-item class="login-animation1" prop="userName">
				<el-input text :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
					<template #prefix>
						<el-icon class="el-input__icon"><ele-User /></el-icon>
					</template>
				</el-input>
			</el-form-item>
			<el-form-item class="login-animation2" prop="password">
				<el-input
					:type="state.isShowPassword ? 'text' : 'password'"
					:placeholder="$t('message.account.accountPlaceholder2')"
					v-model="ruleForm.password"
					autocomplete="off"
				>
					<template #prefix>
						<el-icon class="el-input__icon"><ele-Unlock /></el-icon>
					</template>
					<template #suffix>
						<i
							class="iconfont el-input__icon login-content-password"
							:class="state.isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
							@click="state.isShowPassword = !state.isShowPassword"
						>
						</i>
					</template>
				</el-input>
			</el-form-item>
			<el-form-item class="login-animation4">
				<el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn(ruleFormRef)" :loading="state.loading.signIn">
					<span>{{ $t('message.account.accountBtnText') }}</span>
				</el-button>
			</el-form-item>
		</el-form>
	</div>
</template>

Account组件css

<style scoped lang="scss">
.login-content-form {
	border-radius: 6px;
	width: 400px;
	padding: 25px 25px 5px 25px;
	margin: 0 auto;

	.login-content-password {
		display: inline-block;
		width: 20px;
		cursor: pointer;
		&:hover {
			color: #909399;
		}
	}
	.login-content-submit {
		width: 100%;
		height: 40px;
		margin-top: 60px;
		font-size: 16px;
		color: #fff;
		background-color: #ff6a6c;
		border-color: #ff6a6c;
		border-radius: 3px;
	}
}
</style>

目标是让 loginContainerContent 自适应,
css设置让 loginContainerContent 在 loginContainer居中,
根据窗口尺寸算出缩放比例,动态调整loginContainerContent margin

css

<style scoped lang="scss">
@import './src/theme/common.module.scss';
.login-container {
	width: 100vw;
	height: 100vh;
	background: $bg-clr07;
	position: relative;
	overflow: hidden;

	.login-container-content {
		display: block;
		overflow: hidden;
		position: absolute;
		width: 1920px;
		height: 937px;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);

		.login-container-content-body {
			position: absolute;
			border-radius: 15px;
			background: hsla(0, 0%, 100%, 0.85);
			overflow: hidden;
			padding-left: 632px;
			box-shadow: 0 6px 12px 4px rgba(181, 180, 188, 0.47);
			width: 1100px;
			height: 672px;
			top: calc(50% - 336px);
			left: calc(50% - 550px);

			.login-header {
				padding: 77px 0 20px;

				.login-title {
					text-align: center;

					img {
						height: 60px;
					}
				}

				.login-title-desc {
					font-size: 24px;
					color: rgba(0, 0, 0, 0.8);
					margin-top: 25px;
					text-align: center;
					font-weight: 600;
				}
			}

			.login-form {
				border-radius: 6px;
				width: 400px;
				padding: 25px 25px 5px 25px;
				margin: 0 auto;
			}
		}

		.login-container-content-body::before {
			content: '';
			width: 632px;
			height: 100%;
			position: absolute;
			top: 0;
			left: 0;
			background: url(/src/assets/login_pic.jpg);
			background-size: 100% 100%;
		}

		.copyright {
			width: 100%;
			text-align: center;
			height: 22px;
			line-height: 22px;
			color: #999;
			font-size: 14px;
			position: absolute;
			bottom: 40px;
		}
	}
}
</style>

script,事件和方法要写在mounted里面

import logoMini from '/@/assets/hntt1.svg';

// 引入组件
const Account = defineAsyncComponent(() => import('/@/views/login/component/account.vue'));

const loginContainer = ref(null);
const loginContainerContent = ref(null);

onMounted(() => {
	const resetScreen = () => {
		const mainH = loginContainerContent.value.offsetHeight;
		const mainW = loginContainerContent.value.offsetWidth;

		const cw = loginContainer.value.offsetWidth;
		const ch = loginContainer.value.offsetHeight;

		const cB = ch / cw;
		const mainB = mainH / mainW;

		const scaleW = (cw / mainW).toFixed(3);
		const scaleH = (ch / mainH).toFixed(3);

		//容器的高宽比 大于 展示元素的高宽比时,按照宽度缩放
		if (cB > mainB) {
			loginContainerContent.value.style.marginLeft = `-${(mainW * scaleW) / 2}px`;
			loginContainerContent.value.style.marginTop = `-${(mainH * scaleW) / 2}px`;
			loginContainerContent.value.style.transform = `scale(${scaleW})`;
		} else {
			//容器的高宽比 小于 展示元素的高宽比时,按照高度缩放
			loginContainerContent.value.style.marginLeft = `-${(mainW * scaleH) / 2}px`;
			loginContainerContent.value.style.marginTop = `-${(mainH * scaleH) / 2}px`;
			loginContainerContent.value.style.transform = `scale(${scaleH})`;
		}
		loginContainerContent.value.style.transformOrigin = `0px 0px`;
	};

	window.addEventListener('resize', resetScreen);

	onUnmounted(() => {
		window.removeEventListener('resize', resetScreen);
	});
	resetScreen();
	NextLoading.done();
});
posted @ 2024-05-22 11:09  猝死的路上  阅读(289)  评论(0编辑  收藏  举报