perf: 优化移动端布局

This commit is contained in:
kuaifan 2025-04-09 23:09:37 +08:00
parent bc417b9eea
commit 841ed4e682
15 changed files with 122 additions and 53 deletions

View File

@ -1,9 +1,16 @@
<template>
<div id="app" class="app-view" :style="appStyle">
<div id="app" class="app-view">
<!--顶部状态栏-->
<div class="child-status-bar"></div>
<!--主路由视图-->
<keep-alive>
<router-view class="child-view" :style="childStyle" @hook:mounted.once="onRouterViewMounted"></router-view>
<router-view class="child-view" @hook:mounted.once="onRouterViewMounted"/>
</keep-alive>
<!--底部导航栏-->
<div class="child-navigation-bar"></div>
<!--任务操作-->
<TaskOperation/>
@ -25,9 +32,6 @@
<!--身份提示-->
<AuthException/>
<!--网络提示-->
<NetworkException v-if="windowLandscape"/>
<!--引导页-->
<GuidePage/>
@ -36,6 +40,9 @@
<!--移动端通知-->
<MobileNotification/>
<!--网络提示-->
<NetworkException v-if="windowLandscape"/>
</div>
</template>
@ -47,15 +54,27 @@
left: 0;
right: 0;
bottom: 0;
}
.child-view {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
will-change: transform;
transition: all .3s cubic-bezier(.55, 0, .1, 1);
display: flex;
flex-direction: column;
.child-status-bar {
flex-shrink: 0;
height: var(--status-bar-height);
background-color: var(--status-bar-color);
}
.child-navigation-bar {
flex-shrink: 0;
height: var(--navigation-bar-height);
background-color: var(--navigation-bar-color);
}
.child-view {
flex: 1;
height: 0;
will-change: transform;
transition: all .3s cubic-bezier(.55, 0, .1, 1);
}
}
</style>
<script>
@ -78,7 +97,8 @@ export default {
mixins: [ctrlPressed],
components: {
MobileBack, MobileNotification,
MobileBack,
MobileNotification,
AuthException,
MeetingManager,
DropdownMenu,
@ -93,7 +113,6 @@ export default {
data() {
return {
appInter: null,
appBackgroundColor: "#f8f8f8",
countDown: Math.min(30, 60 - $A.daytz().second()),
lastCheckUpgradeYmd: $A.daytz().format('YYYY-MM-DD'),
}
@ -115,18 +134,31 @@ export default {
},
computed: {
...mapState(['ws', 'themeConf', 'windowOrientation', 'safeAreaSize']),
...mapState(['ws', 'themeConf', 'windowOrientation', 'safeAreaSize', 'mobileTabbar']),
appStyle({appBackgroundColor}) {
return {
backgroundColor: appBackgroundColor,
statusColor({routeName}) {
if (!routeName) {
return null
}
if (['manage-messenger', 'manage-project'].includes(routeName)) {
return '#f8f8f8'
}
if (routeName.startsWith('manage-setting')) {
return '#f8f8f8'
}
return null
},
childStyle({safeAreaSize}) {
navigationColor({statusColor, mobileTabbar}) {
return statusColor || (mobileTabbar ? '#f8f8f8' : null)
},
rootStyle() {
return {
top: `${safeAreaSize.top}px`,
bottom: `${safeAreaSize.bottom}px`,
'--status-bar-height': `${this.safeAreaSize.top}px`,
'--status-bar-color': this.statusColor || '#ffffff',
'--navigation-bar-height': `${this.safeAreaSize.bottom}px`,
'--navigation-bar-color': this.navigationColor || '#ffffff',
}
},
},
@ -183,6 +215,15 @@ export default {
immediate: true
},
rootStyle: {
handler(style) {
for (const key in style) {
document.documentElement.style.setProperty(key, style[key])
}
},
immediate: true
},
windowTouch: {
handler(support) {
if (support) {
@ -625,9 +666,9 @@ export default {
if (!$A.isJson(event)) {
return;
}
this.$store.state.keyboardType = event.keyboardType;
this.$store.state.keyboardShow = event.keyboardType === 'show';
this.$store.state.keyboardHeight = event.keyboardHeight;
$A.eeuiAppShakeToEditEnabled(this.$store.state.keyboardType === 'show')
$A.eeuiAppShakeToEditEnabled(this.$store.state.keyboardShow)
}
//
window.__onNotificationPermissionStatus = (ret) => {

View File

@ -338,14 +338,17 @@ const $preload = async () => {
}
return
}
$A.eeuiAppGetSafeAreaInsets().then(data => {
const proportion = data.height / window.outerHeight
store.state.safeAreaSize = {
top: Math.round(data.top / proportion * 100) / 100,
bottom: Math.round(data.bottom / proportion * 100) / 100,
data
}
}).catch(console.warn)
const pageInfo = $A.eeuiAppGetPageInfo() || {};
if (pageInfo.pageName === 'firstPage') {
$A.eeuiAppGetSafeAreaInsets().then(data => {
const proportion = data.height / window.outerHeight
store.state.safeAreaSize = {
top: Math.round(data.top / proportion * 100) / 100,
bottom: Math.round(data.bottom / proportion * 100) / 100,
data
}
}).catch(console.warn)
}
}
await store.dispatch("preload");

View File

@ -85,7 +85,9 @@ export default {
const pageX = event.type === 'touchmove' ? event.targetTouches[0].pageX : event.pageX;
const pageY = event.type === 'touchmove' ? event.targetTouches[0].pageY : event.pageY;
if (typeof this.isScrolling === 'undefined') {
this.isScrolling = !!(this.isScrolling || Math.abs(pageY - this.touchesStart.y) > Math.abs(pageX - this.touchesStart.x));
const verticalMove = Math.abs(pageY - this.touchesStart.y);
const horizontalMove = Math.abs(pageX - this.touchesStart.x) * 1.5; //
this.isScrolling = verticalMove > horizontalMove;
}
if (this.isScrolling) {
this.isTouched = false;

View File

@ -15,6 +15,7 @@
<script>
import emitter from "../../store/events";
import {mapState} from "vuex";
export default {
name: "MobileNotification",
@ -44,9 +45,11 @@ export default {
},
computed: {
notifyStyle() {
...mapState(['safeAreaSize']),
notifyStyle({windowScrollY, safeAreaSize}) {
return {
marginTop: this.$store.state.windowScrollY + 'px',
marginTop: (windowScrollY + safeAreaSize.top) + 'px',
};
},
},
@ -64,7 +67,7 @@ export default {
this.show = true;
this.timer && clearTimeout(this.timer);
if (this.duration > 0) {
this.timer = setTimeout(this.close, this.duration)
// this.timer = setTimeout(this.close, this.duration)
}
$A.eeuiAppSendMessage({
action: 'setVibrate',

View File

@ -143,7 +143,7 @@ export default {
computed: {
...mapState([
'themeName',
'keyboardType'
'keyboardShow'
]),
isFullscreen({windowWidth}) {
@ -248,7 +248,7 @@ export default {
},
onTouchstart() {
if (this.keyboardType === "show") {
if (this.keyboardShow) {
$A.eeuiAppKeyboardHide();
}
},

View File

@ -61,7 +61,7 @@
// 获取页面信息
eeuiAppGetPageInfo(pageName) {
return this.eeuiModule()?.getPageInfo(pageName);
return this.eeuiModule()?.getPageInfo(pageName || "");
},
// 打开app新页面

View File

@ -559,9 +559,10 @@ export default {
'cacheTranscriptionLanguage',
'cacheKeyboard',
'keyboardType',
'keyboardShow',
'keyboardHeight',
'isModKey',
'safeAreaSize',
]),
...mapGetters(['getDialogDraft', 'getDialogQuote']),
@ -613,8 +614,8 @@ export default {
},
recordConvertFooterStyle() {
const {recordConvertFocus, keyboardType, keyboardHeight} = this;
return (recordConvertFocus && keyboardType === 'show' && keyboardHeight > 120) ? {
const {recordConvertFocus, keyboardShow, keyboardHeight} = this;
return (recordConvertFocus && keyboardShow && keyboardHeight > 120) ? {
alignItems: 'flex-start',
transform: 'translateY(12px)'
} : {}
@ -719,10 +720,12 @@ export default {
return this.getDialogQuote(this.dialogId)?.type === 'update'
},
chatInputBoxStyle({iOSDevices, fullInput, viewportHeight}) {
chatInputBoxStyle({iOSDevices, fullInput, keyboardShow, viewportHeight, safeAreaSize}) {
const style = {}
if (iOSDevices && fullInput && viewportHeight > 0) {
style.height = Math.max(100, viewportHeight - 70) + 'px'
if (iOSDevices && fullInput && keyboardShow && viewportHeight > 0) {
style.height = Math.max(100, viewportHeight - 70 - safeAreaSize.top) + 'px'
} else {
style.paddingBottom = `${safeAreaSize.bottom}px`
}
return style
}

View File

@ -36,8 +36,8 @@ export default {
},
// 键盘状态仅iOS
keyboardType: null, // show|hide
keyboardHeight: 0, // 键盘高度
keyboardShow: false, // 键盘可见
keyboardHeight: 0, // 键盘高度
// 是否按下Ctrl/Command键
isModKey: false,

View File

@ -1,4 +1,5 @@
@import "var";
@import "root";
@import "fileicon";
@import "element";
@import "fonts-ft";

View File

@ -6,7 +6,8 @@
max-width: none;
.ivu-modal-content {
margin-top: 46px;
margin-top: calc(var(--status-bar-height) + 46px);
margin-bottom: 0;
border-top-left-radius: 18px !important;
border-top-right-radius: 18px !important;
@ -16,6 +17,7 @@
.search-list {
max-height: none;
padding-bottom: var(--navigation-bar-height);
}
}
}

View File

@ -455,7 +455,8 @@
max-width: none;
.ivu-modal-content {
margin-top: 46px;
margin-top: calc(var(--status-bar-height) + 46px);
margin-bottom: 0;
border-top-left-radius: 18px !important;
border-top-right-radius: 18px !important;
}
@ -477,7 +478,7 @@
max-height: none;
ul {
padding-bottom: 0;
padding-bottom: var(--navigation-bar-height);
> li {
&:last-child {

View File

@ -279,6 +279,10 @@ body {
.ivu-modal {
top: 100px;
padding-bottom: 100px;
@media (max-width: 768px) {
top: 60px;
padding-bottom: 60px;
}
@media (max-height: 900px) {
top: 35px;
padding-bottom: 35px;
@ -364,6 +368,8 @@ body {
.ivu-modal-content {
border-radius: 18px;
margin-top: var(--status-bar-height);
margin-bottom: var(--navigation-bar-height);
.ivu-modal-close {
.ivu-icon-ios-close {

View File

@ -988,7 +988,8 @@
.chat-input-full-input {
.ivu-modal {
.ivu-modal-content {
margin-top: 46px;
margin-top: calc(var(--status-bar-height) + 46px) !important;
margin-bottom: 0 !important;
border-top-left-radius: 18px !important;
border-top-right-radius: 18px !important;
.ivu-modal-body {

View File

@ -71,7 +71,7 @@ body.window-portrait {
}
}
.calendar-box {
padding: 0 24px 5px;
padding: 0;
}
}
}

6
resources/assets/sass/root.scss vendored Normal file
View File

@ -0,0 +1,6 @@
:root {
--status-bar-height: 0px;
--status-bar-color: #ffffff;
--navigation-bar-height: 0px;
--navigation-bar-color: #ffffff;
}