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();
});