解决IOS中弹出键盘后fixed样式失效问题

811 阅读1分钟

解决方案:通过 absolute 代替 fixed 实现固定在键盘顶部

第一步:外层元素禁止滚动,内层元素滚动 + 获取可视区高度
第二步:用 absolute 替代 fixed 实现

以下示例代码使用的是 Vue3

index.vue

<template>
  <div class="wrapper" :style="{ height: height + 'px' }">
    <!-- 这里 -50 就是减去固定在底部的元素高度 -->
    <div class="body" :style="{ height: height - 50 + 'px' }">
      <input v-model="value" />
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
      <p>内容</p>
    </div>
    <div class="fixed-bottom">固定在底部</div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import useVisualViewport from "@/use/useVisualViewport";
const { height } = useVisualViewport();

const value = ref("");

// 此处解决 ios 向上滑动出现和键盘一样高度的白色衬底区域
onMounted(() => {
  window.onscroll = () => {
    document.documentElement.scrollTop = 0;
  };
});

onUnmounted(() => {
  window.onscroll = null;
});
</script>

<style lang="scss" scoped>
.wrapper {
  position: relative;
  overflow: hidden;

  .body {
    padding: 20px;
    overflow: auto;
  }

  .fixed-bottom {
    border-top: 1px solid #ccc;
    text-align: center;
    line-height: 50px;
    width: 100%;
    height: 50px;
    position: absolute;
    bottom: 0;
    left: 0;
  }
}
</style>

window.visualViewport 此 api 只兼容 ios 13 以上

useVisualViewport

import { ref, onMounted, onUnmounted } from "vue";

export default function useVisualViewport() {
  let width = ref(window.innerWidth);
  let height = ref(window.innerHeight);

  const handler = () => {
    // 只兼容 ios13 以上
    if (window.visualViewport) {
      width.value = window.visualViewport.width;
      height.value = window.visualViewport.height;
    } else {
      width.value = window.innerWidth;
      height.value = window.innerHeight;
    }
  };

  onMounted(() => {
    window.visualViewport.addEventListener("resize", handler);
    window.visualViewport.addEventListener("scroll", handler);
  });

  onUnmounted(() => {
    window.visualViewport.removeEventListener("resize", handler);
    window.visualViewport.removeEventListener("scroll", handler);
  });

  return { width, height };
}

最终效果

e6c8ecb0674bfb324254267dda10b12f.jpg

注意

注意:此方案只兼容 ios 13 以上, ios 13以下的系统普及率较低了

企业微信截图_16612268411099.png