css
:root {
--safe-area-inset-top: 0px;
--safe-area-inset-right: 0px;
--safe-area-inset-bottom: 0px;
--safe-area-inset-left: 0px;
--safe-area-inset-constant-top: 0px;
--safe-area-inset-constant-right: 0px;
--safe-area-inset-constant-bottom: 0px;
--safe-area-inset-constant-left: 0px;
}
@supports (top: env(safe-area-inset-top, 44px)) {
:root {
--safe-area-inset-top: env(safe-area-inset-top, 44px);
--safe-area-inset-right: env(safe-area-inset-right, 34px);
--safe-area-inset-bottom: env(safe-area-inset-bottom, 34px);
--safe-area-inset-left: env(safe-area-inset-left, 34px);
}
}
@supports (top: constant(safe-area-inset-top)) {
:root {
--safe-area-inset-constant-top: constant(safe-area-inset-top);
--safe-area-inset-constant-right: constant(safe-area-inset-right);
--safe-area-inset-constant-bottom: constant(safe-area-inset-bottom);
--safe-area-inset-constant-left: constant(safe-area-inset-left);
}
}
首先设置 css 根属性变量值,如果是 less,通过 calc 计算出增加刘海屏高度后的值,注意 calc 计算不支持不带单位的数字相加,会导致结果为 0 ,所以一定要处理不带单位的场景。
由于安卓不支持 constant css 函数,以及安卓 9 以下低版本系统不支持 env css 函数,会导致获取的结果为 0 从而导致 calc 计算结果也为 0 ,所以要在初始化写为 0px,则通过 css @supports 来判断支持 constant 和 env 函数的情况下再赋值刘海屏高度值。
js 通过与iOS 和安卓的接口获取到客户端返回的实际刘海屏的高度,当返回的高度存在时,则重新赋值 root 跟元素的变量,否则用浏览器默认的。
这样实现的目的是为了解决部分机型下,env 函数和 constant 函数都获取失败导致无法处理刘海屏高度的场景。
js vue3 代码
import { readonly, reactive, watch, ref } from 'vue'
import { setRootProperty } from '@/common/util'
export default {
install: (app) => {
const config = reactive({})
const insets = ref({ top: 0, left: 0, bottom: 0, right: 0 })
if (window.getSafeAreaInsets && typeof window.getSafeAreaInsets === 'function') {
insets.value = window.getSafeAreaInsets() // 初始化获取刘海屏值
}
const setConfigAreaInsets = () => {
config.areaInsets = insets.value
}
const updateInsets = (top, left, bottom, right) => {
insets.value = { top, left, bottom, right }
}
function applySafeInsets() {
if (!window.EVENTS.safeAreaInsetsChange) {
return false
}
setConfigAreaInsets()
;['top', 'right', 'bottom', 'left'].forEach(prop => {
setRootProperty(`--safe-area-inset-${prop}`, `${insets.value[prop]}px`)
setRootProperty(`--safe-area-inset-constant-${prop}`, `${insets.value[prop]}px`)
})
}
watch(insets, (val) => {
applySafeInsets()
})
app.mixin({
mounted() {
applySafeInsets()
if (this === this.$root) {
window.mraid.addEventListener('safeAreaInsetsChange', updateInsets)
}
},
beforeUnmount() {
if (this === this.$root) {
window.mraid.removeEventListener('safeAreaInsetsChange', updateInsets)
}
}
})
app.config.globalProperties.$config = config
app.provide('config', readonly(config))
}
}