Skip to content

Commit

Permalink
wip(uni-app-x web): 支持safeAreaInset css变量
Browse files Browse the repository at this point in the history
  • Loading branch information
Wangyaqi committed Jan 21, 2025
1 parent 9ff211b commit 76c7ac4
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 41 deletions.
41 changes: 39 additions & 2 deletions packages/uni-h5/src/framework/components/page/pageBody.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Ref, ref, renderSlot, watch } from 'vue'
import { type Ref, onMounted, onUnmounted, ref, renderSlot, watch } from 'vue'

import { defineSystemComponent } from '@dcloudio/uni-components'

Expand All @@ -7,6 +7,7 @@ import { usePageMeta } from '../../setup/provide'
import PageRefresh from './page-refresh/component.vue'

import { usePageRefresh } from './page-refresh'
import { getSafeAreaInsets } from '../../../helpers/safeArea'

export default /*#__PURE__*/ defineSystemComponent({
name: 'PageBody',
Expand All @@ -17,6 +18,8 @@ export default /*#__PURE__*/ defineSystemComponent({
const refreshRef = (__UNI_FEATURE_PULL_DOWN_REFRESH__ &&
ref(null)) as Ref<null>

const wrapperRef = ref<HTMLElement | null>(null)

const _pageRefresh =
!__NODE_JS__ &&
__UNI_FEATURE_PULL_DOWN_REFRESH__ &&
Expand All @@ -36,14 +39,48 @@ export default /*#__PURE__*/ defineSystemComponent({
}
)

if (__X__ && !__NODE_JS__) {
// TODO 兼容低版本浏览器
let observer: ResizeObserver | null = null

onMounted(() => {
if (typeof ResizeObserver === 'undefined') {
return
}
observer = new ResizeObserver((entries) => {
const { top, left, right, bottom } = getSafeAreaInsets(
wrapperRef.value!
)
// TODO dialogPage
const vars = {
'--uni-safe-area-inset-top': `${top}px`,
'--uni-safe-area-inset-left': `${left}px`,
'--uni-safe-area-inset-right': `${right}px`,
'--uni-safe-area-inset-bottom': `${bottom}px`,
}
for (const key in vars) {
wrapperRef.value!.style.setProperty(key, vars[key])
}
})
observer.observe(document.querySelector('uni-page-wrapper')!)
})

onUnmounted(() => {
if (!observer) {
return
}
observer.disconnect()
})
}

return () => {
const pageRefreshTsx =
__UNI_FEATURE_PULL_DOWN_REFRESH__ &&
createPageRefreshTsx(refreshRef, pageMeta)
return (
<>
{pageRefreshTsx}
<uni-page-wrapper {...pageRefresh.value}>
<uni-page-wrapper ref={wrapperRef} {...pageRefresh.value}>
<uni-page-body>{renderSlot(ctx.slots, 'default')}</uni-page-body>
</uni-page-wrapper>
</>
Expand Down
39 changes: 39 additions & 0 deletions packages/uni-h5/src/helpers/safeArea.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import safeAreaInsets from 'safe-area-insets'
export function getPageWrapperInfo(pageBody?: HTMLElement) {
const pageWrapper =
pageBody || (document.querySelector('uni-page-wrapper') as HTMLElement)
const pageWrapperRect = pageWrapper.getBoundingClientRect()

const bodyRect = document.body.getBoundingClientRect()
return {
top: pageWrapperRect.top,
left: pageWrapperRect.left,
right: bodyRect.right - pageWrapperRect.right,
bottom: bodyRect.bottom - pageWrapperRect.bottom,
width: pageWrapperRect.width,
height: pageWrapperRect.height,
}
}

export const getSystemSafeAreaInsets = function () {
return {
top: safeAreaInsets.top,
right: safeAreaInsets.right,
bottom: safeAreaInsets.bottom,
left: safeAreaInsets.left,
}
}

/**
* 注意web端页面安全区域较为特殊,如下四个值主要为满足fixed定位时能避开系统安全区域及页面top-window、left-window、nav-bar、tab-bar等的边界
*/
export function getSafeAreaInsets(pageBody?: HTMLElement) {
const pageWrapperEdge = getPageWrapperInfo(pageBody)
const systemSafeAreaInsets = getSystemSafeAreaInsets()
return {
top: Math.max(pageWrapperEdge.top, systemSafeAreaInsets.top),
left: Math.max(pageWrapperEdge.left, systemSafeAreaInsets.left),
right: Math.max(pageWrapperEdge.right, systemSafeAreaInsets.right),
bottom: Math.max(pageWrapperEdge.bottom, systemSafeAreaInsets.bottom),
}
}
47 changes: 8 additions & 39 deletions packages/uni-h5/src/x/framework/setup/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import type {
} from '@dcloudio/uni-app-x/types/page'
//#if !_NODE_JS_
import { closeDialogPage } from '../../service/api/route/closeDialogPage'
import safeAreaInsets from 'safe-area-insets'
import {
getPageWrapperInfo,
getSafeAreaInsets,
} from '../../../helpers/safeArea'
//#endif
import {
currentPagesMap,
Expand All @@ -24,17 +27,6 @@ import { isDialogPageInstance } from '../helpers/utils'
import type { UniSafeAreaInsets } from '@dcloudio/uni-app-x/types/native/UniSafeAreaInsets'
import type { UniPageBody } from '@dcloudio/uni-app-x/types/UniPage'

//#if !_NODE_JS_
const getSystemSafeAreaInsets = function () {
return {
top: safeAreaInsets.top,
right: safeAreaInsets.right,
bottom: safeAreaInsets.bottom,
left: safeAreaInsets.left,
}
}
//#endif

let escBackPageNum = 0
type PageStyle = {
navigationBarBackgroundColor?: string
Expand All @@ -50,21 +42,6 @@ type PageStyle = {
export const homeDialogPages: UniDialogPage[] = []
export const homeSystemDialogPages: UniDialogPage[] = []

function getPageWrapperInfo(container: Document | Element) {
const pageWrapper = container.querySelector('uni-page-wrapper') as HTMLElement
const pageWrapperRect = pageWrapper.getBoundingClientRect()

const bodyRect = document.body.getBoundingClientRect()
return {
top: pageWrapperRect.top,
left: pageWrapperRect.left,
right: bodyRect.right - pageWrapperRect.right,
bottom: bodyRect.bottom - pageWrapperRect.bottom,
width: pageWrapperRect.width,
height: pageWrapperRect.height,
}
}

function isDialogPageImpl(page: UniPage): boolean {
return page instanceof UniDialogPageImpl
}
Expand All @@ -91,7 +68,8 @@ class UniPageImpl implements UniPage {
} else if (this !== currentPage) {
throw new Error("Can't get pageBody of other page")
}
const pageWrapperInfo = getPageWrapperInfo(container)
const pageBody = container.querySelector('uni-page-wrapper') as HTMLElement
const pageWrapperInfo = getPageWrapperInfo(pageBody)
return {
top: pageWrapperInfo.top,
left: pageWrapperInfo.left,
Expand All @@ -118,17 +96,8 @@ class UniPageImpl implements UniPage {
} else if (this !== currentPage) {
throw new Error("Can't get safeAreaInsets of other page")
}
const pageWrapperEdge = getPageWrapperInfo(container)
const systemSafeAreaInsets = getSystemSafeAreaInsets()
/**
* 注意web端页面安全区域较为特殊,如下四个值主要为满足fixed定位时能避开系统安全区域及页面top-window、left-window、nav-bar、tab-bar等的边界
*/
return {
top: Math.max(pageWrapperEdge.top, systemSafeAreaInsets.top),
left: Math.max(pageWrapperEdge.left, systemSafeAreaInsets.left),
right: Math.max(pageWrapperEdge.right, systemSafeAreaInsets.right),
bottom: Math.max(pageWrapperEdge.bottom, systemSafeAreaInsets.bottom),
}
const pageBody = container.querySelector('uni-page-wrapper') as HTMLElement
return getSafeAreaInsets(pageBody)
}
getPageStyle(): UTSJSONObject {
const pageMeta = this.vm?.$basePage.meta
Expand Down

0 comments on commit 76c7ac4

Please sign in to comment.