uni-app 中 web-view 的使用与 App 端全屏问题处理

uni-app 中 web-view 的使用与 App 端全屏问题处理

web-view 是 uni-app 中用于承载网页内容的组件,常见场景包括嵌入 H5 页面、PDF 预览、外部系统页面、报表页面等。

它看起来像普通组件,但在 App 端,尤其是 Android 环境下,web-view 的表现和普通 viewimagescroll-view 很不一样。

一、web-view 是什么

web-view 本质上是一个网页容器,可以加载一个 URL。

简单用法:

html 复制代码
<web-view :src="url"></web-view>

例如:

html 复制代码
<web-view
  src="https://example.com"
  style="width: 100%; height: 100%;"
/>

它适合用来:

  • 嵌入已有 H5 页面
  • 打开第三方网页
  • 展示 PDF.js 页面
  • 展示报表、可视化页面
  • 承载需要独立运行的 Web 应用

二、H5 端和 App 端的差异

在 H5 端,web-view 通常会被编译成类似 iframe 的结构,CSS 对它的控制比较直观。

但在 App 端,尤其是 App-vue 模式下,web-view 是原生 WebView 子窗口。

这意味着:

  • 它不是普通 DOM 节点
  • CSS 不一定能完全控制它
  • 层级通常高于普通页面元素
  • Android 上可能默认铺满页面
  • 普通 z-index 对它不一定有效

这也是很多人遇到的问题:

html 复制代码
<view style="width: 300px; height: 400px;">
  <web-view :src="url" />
</view>

在 H5 看起来正常,但在 Android App 端可能仍然全屏。

三、为什么 Android 上 web-view 会全屏

原因在于 App 端的 web-view 是原生层组件。

普通页面里的 viewtextimage 等是 uni-app 渲染层内容,而 web-view 在 App 端会创建一个原生 WebView 窗口。

所以这类 CSS:

css 复制代码
.webview-box {
  width: 500px;
  height: 300px;
  overflow: hidden;
}

不一定能限制 Android 原生 WebView 的实际尺寸。

即使你写了:

html 复制代码
<web-view
  :src="url"
  style="width: 100%; height: 100%;"
  :fullscreen="false"
/>

在某些 App-vue / Android 场景下,也可能仍然全屏。

四、fullscreen=false 是否一定有效

不一定。

fullscreen 属性在部分平台有效,但不能把它当成 Android App-vue 端的稳定解决方案。

例如:

html 复制代码
<web-view
  :src="url"
  :fullscreen="false"
/>

这个写法可以保留,但如果 Android 端仍然全屏,就需要进一步通过原生 WebView 设置尺寸。

五、推荐写法:容器 + webview-styles + 原生 setStyle

页面结构可以这样写:

html 复制代码
<view class="webview-wrapper">
  <web-view
    :src="url"
    :fullscreen="false"
    class="inner-webview"
    :webview-styles="{
      width: '100%',
      height: '100%'
    }"
  />
</view>

CSS:

css 复制代码
.webview-wrapper {
  width: 100%;
  height: 500px;
  position: relative;
}

.inner-webview {
  width: 100%;
  height: 100%;
}

但在 Android App 端,如果仍然全屏,还需要同步原生 WebView 的实际位置和大小。

六、Android App 端强制限制 web-view 尺寸

核心思路:

  1. createSelectorQuery() 获取页面中容器的真实坐标。
  2. 获取当前页面的 App WebView。
  3. 获取 web-view 对应的原生子 WebView。
  4. 调用 setStyle() 设置 topleftwidthheight

示例:

js 复制代码
const adjustAppWebview = () => {
  // #ifdef APP-PLUS
  uni
    .createSelectorQuery()
    .select('.webview-wrapper')
    .boundingClientRect((rect) => {
      if (!rect || !rect.width || !rect.height) return;

      const pages = getCurrentPages();
      const currentPage = pages[pages.length - 1];

      const currentWebview =
        currentPage?.$getAppWebview?.() ||
        currentPage?.$vm?.$scope?.$getAppWebview?.();

      const childWebview = currentWebview?.children?.()?.[0];

      if (!childWebview || typeof childWebview.setStyle !== 'function') {
        return;
      }

      childWebview.setStyle({
        top: Math.round(rect.top),
        left: Math.round(rect.left),
        width: Math.round(rect.width),
        height: Math.round(rect.height)
      });
    })
    .exec();
  // #endif
};

然后在页面生命周期里调用:

js 复制代码
import { nextTick } from 'vue';
import { onReady, onShow } from '@dcloudio/uni-app';

onReady(() => {
  nextTick(() => {
    adjustAppWebview();
  });
});

onShow(() => {
  nextTick(() => {
    adjustAppWebview();
  });
});

如果 WebView 创建有延迟,可以加重试:

js 复制代码
const adjustAppWebview = (attempt = 0) => {
  // #ifdef APP-PLUS
  nextTick(() => {
    setTimeout(() => {
      uni
        .createSelectorQuery()
        .select('.webview-wrapper')
        .boundingClientRect((rect) => {
          if (!rect || !rect.width || !rect.height) {
            if (attempt < 8) adjustAppWebview(attempt + 1);
            return;
          }

          const pages = getCurrentPages();
          const currentPage = pages[pages.length - 1];

          const currentWebview =
            currentPage?.$getAppWebview?.() ||
            currentPage?.$vm?.$scope?.$getAppWebview?.();

          const childWebview = currentWebview?.children?.()?.[0];

          if (!childWebview || typeof childWebview.setStyle !== 'function') {
            if (attempt < 8) adjustAppWebview(attempt + 1);
            return;
          }

          childWebview.setStyle({
            top: Math.round(rect.top),
            left: Math.round(rect.left),
            width: Math.round(rect.width),
            height: Math.round(rect.height)
          });
        })
        .exec();
    }, attempt === 0 ? 300 : 200);
  });
  // #endif
};

七、资源中心 PDF 预览的处理方式

例如资源中心 PDF 预览页面:

html 复制代码
<view class="app-pdf-preview">
  <web-view
    :src="getPdfViewerUrl"
    class="pdf-webview"
    :fullscreen="false"
    style="width: 100%; height: 100%; border: 0"
    :webview-styles="{
      width: '100%',
      height: '100%',
      progress: { color: '#16a5fb' }
    }"
  />
</view>

然后在 App 端执行:

js 复制代码
const adjustAppPdfWebview = () => {
  // #ifdef APP-PLUS
  uni
    .createSelectorQuery()
    .select('.app-pdf-preview')
    .boundingClientRect((rect) => {
      if (!rect) return;

      const pages = getCurrentPages();
      const currentPage = pages[pages.length - 1];
      const currentWebview = currentPage?.$getAppWebview?.();
      const childWebview = currentWebview?.children?.()?.[0];

      childWebview?.setStyle?.({
        top: Math.round(rect.top),
        left: Math.round(rect.left),
        width: Math.round(rect.width),
        height: Math.round(rect.height)
      });
    })
    .exec();
  // #endif
};

这样可以避免 Android 上 PDF 的 web-view 覆盖整个页面。

八、注意事项

web-view 在 App 端层级高,不建议在它上面覆盖普通 view 做按钮、弹窗或遮罩。

如果必须覆盖,优先考虑:

  • 原生子窗体
  • subNVue
  • App 原生插件
  • 页面外部控制按钮

不要依赖普通 CSS 的 z-index

另外,如果一个页面里有多个 web-view,不能简单使用:

js 复制代码
currentWebview.children()[0]

因为第一个子 WebView 不一定就是目标 WebView。

这种情况下需要:

  • 控制页面只存在一个 web-view
  • 或根据子 WebView 的 URL 判断
  • 或封装专门的 WebView 页面

九、最佳实践

对于 uni-app 中的 web-view,建议遵循以下原则:

  1. H5 端可以按普通 iframe 思路处理。
  2. App 端要把它当成原生窗口处理。
  3. Android 上不要只依赖 CSS 控制尺寸。
  4. 非全屏需求要配合 setStyle()
  5. 页面复杂时,尽量只保留一个 web-view
  6. PDF 预览推荐使用 PDF.js 页面作为 src
  7. Office 文件预览优先考虑系统应用、X5 插件或后端转 PDF。

十、总结

web-view 是 uni-app 中非常实用的组件,但它不是普通组件。

在 H5 中,它像 iframe;在 App 中,它更像一个原生 WebView 窗口。

所以当 Android 上出现 web-view 全屏、遮挡页面、CSS 不生效等问题时,不能只改样式,而要通过 App 端原生 WebView 的 setStyle() 设置真实位置和尺寸。

一句话总结:

H5 用 CSS 控制,App 端用原生 WebView 样式控制。

相关推荐
闲坐含香咀翠1 小时前
Electron 加载原生模块总崩溃?搞懂这两行配置就够了
前端·electron·客户端
拉拉肥_King1 小时前
pc端视频压缩:FFmpeg.wasm 实战指南
前端
0x861 小时前
基于 Dio 实现 SSE 流式通信
前端
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_40:(DOMImplementation 接口完全解析)
前端·ui·html·媒体
之歆1 小时前
DAY_17深度博客:CSS 响应式布局 · BFC · JavaScript 完全指南(上)
javascript·js
Highcharts.js2 小时前
Highcharts 纯 JavaScript 图表库深度使用评测
开发语言·前端·javascript·功能测试·ecmascript·highcharts·技术评测
码码哈哈0.02 小时前
基于 RSA 非对称加密与挑战码机制的前端登录安全方案
前端·安全·状态模式
ZC跨境爬虫2 小时前
跟着 MDN 学 HTML day_39:(DOMException 异常接口完全解析)
前端·javascript·html·媒体