uni-app 宽屏适配完全指南:leftWindow/rightWindow/topWindow 窗体 API 与分栏布局实战
2026/9/20 20:49:24 网站建设 项目流程

uni-app 宽屏适配完全指南:leftWindow/rightWindow/topWindow 窗体 API 与分栏布局实战

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

uni-app 以移动端为先,但从 2.9 版本起便内置了完整的 PC 宽屏适配方案,其中页面窗体级适配(leftWindow、rightWindow、topWindow)是分栏式宽屏布局的核心骨架。本文以 wide-screen-adaptation.md 的窗体 API 文档为主线,系统讲解三个窗体的配置方式、显示/隐藏/样式控制的完整 API 用法、窗体间通信机制,并结合仓库中的真实配置(src/pages.json、src/windows/)与组件级、rpx 级适配方案,给出从手机窄屏快速升级为 PC 宽屏应用的完整实战路径。

一、宽屏适配的整体架构

uni-app 宽屏适配由三部分组成:页面窗体级适配(leftWindow/rightWindow/topWindow)组件级适配(match-media / 分栏)内容缩放拉伸处理(rpx 基准控制)。本文聚焦于页面窗体级方案,即leftWindowrightWindowtopWindow三个可扩展窗体。

核心设计思想:以手机屏幕对应的页面为主窗体(mainWindow),在主窗体的左侧、右侧、上方扩展出独立的辅助窗体区域。这些区域:

  • 独立运行:各窗体拥有独立的页面文件,切换页面时可在各自的 window 内单独刷新,而不是整屏刷新;
  • 可自动显隐:通过matchMedia规则设定生效的屏幕宽度范围,宽屏出现、窄屏自动隐藏;
  • 可交互通信:窗体之间通过uni.$emit/uni.$on事件机制传递数据与状态。

兼容性限制:leftWindow、rightWindow、topWindow 以及本文所述的全部窗体 API 仅支持Web 端(H5,uni-app 4.0+),微信小程序、Android、iOS、HarmonyOS 均不支持(详见下方各 API 兼容性表格)。

适用场景

  • 需要固定布局的复杂应用(后台管理系统、文档系统);
  • 多区域协同工作的场景;
  • 新闻资讯、电商等"列表 + 详情"分栏式应用。

仓库中的 uni-app 官方示例工程(src/ 与 examples/hello-uvue)正是以leftWindow + topWindow构成"上、左、右"三栏布局的典型实现,详见 src/pages.json 中的实际配置。

二、窗体级适配 API 全解

2.1 API 总览与兼容性

| API | 功能 | 兼容性 | | :- | :- | :- | | uni.showLeftWindow(options) | 显示 leftWindow 窗体 | Web 4.0+ | | uni.showRightWindow(options) | 显示 rightWindow 窗体 | Web 4.0+ | | uni.showTopWindow(options) | 显示 topWindow 窗体 | Web 4.0+ | | uni.hideLeftWindow(options) | 隐藏 leftWindow 窗体 | Web 4.0+ | | uni.hideRightWindow(options) | 隐藏 rightWindow 窗体 | Web 4.0+ | | uni.hideTopWindow(options) | 隐藏 topWindow 窗体 | Web 4.0+ | | uni.getTopWindowStyle() | 获取 topWindow 窗体样式 | Web 4.0+ | | uni.getLeftWindowStyle() | 获取 leftWindow 窗体样式 | Web 4.0+ | | uni.getRightWindowStyle() | 获取 rightWindow 窗体样式 | Web 4.0+ | | uni.setTopWindowStyle(options) | 设置 topWindow 窗体样式 | Web 4.0+ | | uni.setLeftWindowStyle(options) | 设置 leftWindow 窗体样式 | Web 4.0+ | | uni.setRightWindowStyle(options) | 设置 rightWindow 窗体样式 | Web 4.0+ |

六个 show/hide 系列 API 与六个 get/set 系列 API 的兼容性完全一致:仅 Web 4.0 支持,微信小程序 / Android / iOS / HarmonyOS 均为 x(不支持)。所有带 options 参数的接口,其 options 类型均为 UniNamespace.CommonOptions,带样式操作的接口(set 系列)的 options 类型为string(合法值为Partial<CSSStyleDeclaration>string.CSSURIString)。

2.2 show / hide 系列:窗体的显示与隐藏

2.2.1uni.showLeftWindow(options)@showleftwindow

显示 leftWindow 窗体。

兼容性

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | 4.0 | x | x | x | x |

参数

| 名称 | 类型 | 必填 | 兼容性 | | :- | :- | :- | :-: | | options | UniNamespace.CommonOptions | 是 | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x |

options 属性描述

| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | success | (result: any) => void | 否 | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 接口调用成功的回调函数 | | fail | (result: any) => void | 否 | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 接口调用失败的回调函数 | | complete | (result: any) => void | 否 | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 接口调用结束的回调函数(调用成功、失败都会执行) |

2.2.2uni.showRightWindow(options)@showrightwindow

显示 rightWindow 窗体。参数结构与兼容性同showLeftWindow,options 为UniNamespace.CommonOptions,回调success/fail/complete均为可选。

2.2.3uni.showTopWindow(options)@showtopwindow

显示 topWindow 窗体。参数结构与兼容性同前两者。

2.2.4uni.hideLeftWindow(options)@hideleftwindow

隐藏 leftWindow 窗体。options 为UniNamespace.CommonOptions(必填),回调可选。

2.2.5uni.hideRightWindow(options)@hiderightwindow

隐藏 rightWindow 窗体。参数结构同hideLeftWindow

2.2.6uni.hideTopWindow(options)@hidetopwindow

隐藏 topWindow 窗体。参数结构同hideLeftWindow

2.2.7 实战示例:根据屏幕宽度动态显示 / 隐藏窗体
// 显示右侧窗体,并在成功/失败时输出结果 uni.showRightWindow({ success: (result) => { console.log('rightWindow 显示成功', result) }, fail: (result) => { console.error('rightWindow 显示失败', result) }, complete: () => { console.log('showRightWindow 调用结束') } }) // 隐藏左侧窗体 uni.hideLeftWindow({ success: (result) => { console.log('leftWindow 已隐藏', result) } })

2.3 get 系列:获取窗体样式

三个 get 接口均无参数、返回类型为any,用于读取当前窗体运行时样式(通常为 CSSStyleDeclaration 形式的样式对象)。

2.3.1uni.getTopWindowStyle()@gettopwindowstyle

获取 topWindow 窗体样式。

| 类型 | | :- | | any |

2.3.2uni.getLeftWindowStyle()@getleftwindowstyle

获取 leftWindow 窗体样式。

| 类型 | | :- | | any |

2.3.3uni.getRightWindowStyle()@getrightwindowstyle

获取 rightWindow 窗体样式。

| 类型 | | :- | | any |

实战示例

const style = uni.getLeftWindowStyle() console.log('当前 leftWindow 样式:', style) // 可在拿到样式对象后继续读取/判断 width、height、backgroundColor 等属性

2.4 set 系列:动态设置窗体样式

set 系列接口的 options 类型为string,合法值有两种:

| 合法值 | 兼容性 | | :- | :-: | | Partial<CSSStyleDeclaration> | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | | string.CSSURIString | 微信小程序: x; Android: x; iOS: x; HarmonyOS: x |

即支持传入一个 CSS 样式声明对象(部分属性),也支持传入 CSS URI 字符串(如url(...)背景资源)。

2.4.1uni.setTopWindowStyle(options)@settopwindowstyle

设置 topWindow 窗体样式。options 类型为string,必填。

2.4.2uni.setLeftWindowStyle(options)@setleftwindowstyle

设置 leftWindow 窗体样式。options 类型为string,必填。

2.4.3uni.setRightWindowStyle(options)@setrightwindowstyle

设置 rightWindow 窗体样式。options 类型为string,必填。

实战示例

// 方式一:以样式对象设置 leftWindow 宽度与背景 uni.setLeftWindowStyle({ width: '320px', backgroundColor: '#f8f8f8' }) // 方式二:以 CSS URI 字符串设置背景图 uni.setTopWindowStyle('url(/static/banner.png)') // 读取设置后的结果 const style = uni.getRightWindowStyle()

三、通用类型说明

GeneralCallbackResult @generalcallbackresult-values

所有 show/hide 接口的 success / fail 回调均可能返回该通用结果对象:

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | errMsg | string | 是 | 错误信息 |

errMsg为接口调用结果描述,成功时为"xxx:ok"形式,失败时为对应的错误信息,可在fail回调中读取用于排查问题。

四、pages.json 窗体配置详解

窗体级适配的声明配置在pages.json的顶层进行(与globalStylepages平级),仓库官方示例 src/pages.json 的真实配置如下:

{ "leftWindow": { "path": "windows/left-window.uvue", "style": { "width": "350px" } }, "topWindow": { "path": "windows/top-window.uvue", "style": { "height": "60px" } }, "pages": [] }

4.1 各窗体的配置项列表

三个窗体(topWindow / leftWindow / rightWindow)的配置项结构完全一致,详见 pagesjson.md:

| 属性 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :- | :- | | path | string | 否 | Web: 4.0; 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 配置页面路径 | | style | object | 否 | Web: 4.0; 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 配置页面窗口表现 | | matchMedia | matchMedia 配置项列表 | 否 | Web: 4.0; 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 配置显示该窗口的规则 |

matchMedia 配置项列表(三个窗体相同):

| 属性 | 类型 | 默认值 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :- | :- | :- | | minWidth | number | 768 | 否 | Web: 4.0; 微信小程序: x; Android: x; iOS: x; HarmonyOS: x | 当设备可见区域宽度 ≥ minWidth 时,显示该 window |

4.2 页面级显隐控制与 maxWidth

除窗体自身的matchMedia外,pages.json 还支持在页面(pages数组项)与全局(globalStyle)维度控制窗体的显示:

| 属性 | 类型 | 默认值 | 描述 | | :- | :- | :- | :- | | leftWindow | boolean | true | 当存在 leftWindow 时,当前页面/全局是否显示 leftWindow | | topWindow | boolean | true | 当存在 topWindow 时,当前页面/全局是否显示 topWindow | | rightWindow | boolean | true | 当存在 rightWindow 时,当前页面/全局是否显示 rightWindow | | maxWidth | number | - | 单位 px,当浏览器可见区域宽度大于 maxWidth 时两侧留白,小于等于 maxWidth 时页面铺满;不同页面支持配置不同 maxWidth;maxWidth = leftWindow(可选) + page(页面主体) + rightWindow(可选) |

其中maxWidth用于限定内容区的最大宽度:超过该宽度后浏览器两侧留白,避免超宽屏下内容过度拉伸,非常适合内容型站点。

4.3 完整配置示例

{ "globalStyle": { "maxWidth": 1200 }, "topWindow": { "path": "responsive/top-window.vue", "style": { "height": "44px" } }, "leftWindow": { "path": "responsive/left-window.vue", "style": { "width": 300 } }, "rightWindow": { "path": "responsive/right-window.vue", "style": { "width": "calc(100vw - 400px)" }, "matchMedia": { "minWidth": 768 } } }

要点说明:

  • topWindow.style.height:顶部窗体高度,支持44px等固定值与百分比;
  • leftWindow.style.width:左侧窗体宽度,支持数字(px)或300px字符串;
  • rightWindow.style.width:右侧窗体宽度可用calc()动态计算,如calc(100vw - 400px)表示"占满视口减去左栏与主栏";
  • matchMedia.minWidth:默认值为 768,即默认在 768px 以上才显示该窗体。

五、窗体页面实现与通信实战

5.1 窗体页面文件:以仓库官方实现为例

仓库官方示例中,leftWindow 与 topWindow 的页面文件位于 src/windows/:

  • left-window.uvue:左侧导航窗体,宽度 350px,内部通过<component :is="active">动态挂载 tab 页作为二级导航;
  • top-window.uvue:顶部窗体,高度 60px。

从 left-window.uvue 可以看到,官方在窗体内部同样使用uni.createMediaQueryObserver(this).observe({ minWidth: 768 }, matched => ...)来感知宽屏状态,这说明:

  • 窗体 API 与matchMedia媒体查询机制在宽屏适配中协同工作;
  • 窗体页面是独立运行的 Vue/uvue 组件实例,可持有自己的 data、computed、watch 与生命周期。

5.2 窗体间通信:事件总线

窗体与主页面之间通过uni.$emit/uni.$on事件总线通信。经典"列表 + 详情"分栏场景:

<!-- responsive/right-window.vue:右侧详情窗体 --> <template> <view> <!-- 将原详情页面 /pages/detail/detail 作为组件复用 --> <pages-detail-detail ref="detailPage"></pages-detail-detail> </view> </template> <script setup> import { onUnmounted, ref } from 'vue' const detailPage = ref(null) // 监听列表页点击触发的自定义事件,刷新详情 const updateDetail = (e) => { detailPage.value?.load(e.detail) } uni.$on('updateDetail', updateDetail) onUnmounted(() => { uni.$off('updateDetail', updateDetail) }) </script>
// 主窗体列表页:宽屏时通知右侧窗体刷新,窄屏时跳转新页面 const goDetail = (detail) => { if (instance?.proxy?._isWidescreen) { // 宽屏:触发右侧窗体事件 uni.$emit('updateDetail', { detail: encodeURIComponent(JSON.stringify(detail)) }) } else { // 窄屏:navigateTo 打开详情页 uni.navigateTo({ url: '/pages/detail/detail?query=' + encodeURIComponent(JSON.stringify(detail)) }) } }

关键点:

  • 页面复用/pages/detail/detail页面可自动转化为pages-detail-detail组件在窗体中直接引用,无需重写详情逻辑;
  • 同一套代码维护:宽屏分栏、窄屏跳转共用一套业务代码,迭代时无需多处升级;
  • 事件配对:务必在onUnmounteduni.$off注销监听,避免窗体销毁后事件泄漏。

5.3 leftWindow 适合做什么

  • 导航重组:把手机竖屏上依赖的多级 tab、宫格导航,重组为 leftWindow 中的 tree / 折叠面板导航;
  • PC Admin 管理控制台:leftWindow 天然适合左侧菜单栏 + 右侧内容区的后台布局,官方基于 uni-app PC 版还推出了 unicloud Admin 供参考。

六、向宽屏升级的实战路径

6.1 思路:现有小屏内容放哪个 window?

已有为小屏设计的 uni-app 应用,适配大屏时先理清:现有小屏内容放在哪个 window 里?

  • 首页是列表、二级页是详情 → 把列表作为主 window,右侧扩展rightWindow放详情(新闻资讯类模板的经典做法);
  • 首页有很多 tab / 宫格 → 重组进leftWindow作为导航;
  • 需要在所有页面上方展示全局信息条 / 工具条 → 使用topWindow

6.2 第一步:声明窗体

按 第四节 在 pages.json 中配置窗体路径、样式与 matchMedia。

6.3 第二步:复用详情页面为窗体组件

窗体页面不需要重写详情逻辑,直接把原详情页当组件引入(路径/pages/detail/detail转为组件名pages-detail-detail)。

6.4 第三步:主窗体按宽窄屏分流交互

在主窗体列表页通过uni.getWindowInfo().windowWidth> 768)或uni.getDeviceInfo().deviceType'pad' || 'pc')判断宽屏,宽屏uni.$emit通知窗体,窄屏uni.navigateTo跳转,见 5.2 示例。

七、组件级适配与 rpx 补充方案

当需要跨端(pad、折叠屏)分栏、或在单页面内做响应式布局时,窗体级方案(仅 Web)不再适用,可改用以下方案:

7.1 组件级适配:分栏与 match-media

利用"vue 文件既可作页面又可作组件"的特性,在列表页中并排放置 list 组件与 detail 组件:

<template> <view style="display: flex;flex-direction: row;"> <view :class="isWide ? 'list-narrow' : 'list-wide'"> <view v-for="(item, index) in listData" :key="index"> <text @click="showDetail(item.id)">{{ item.title }}</text> </view> </view> <detail v-if="isWide" style="width: 50%;"></detail> </view> </template> <script setup> import { ref } from 'vue' import { onLoad } from '@dcloudio/uni-app' import detail from './detail' const isWide = ref(false) onLoad(() => { const deviceType = uni.getDeviceInfo().deviceType isWide.value = deviceType === 'pad' || deviceType === 'pc' }) const showDetail = (id) => { if (isWide.value) { uni.$emit('detailId', id) // 宽屏:事件通知右侧组件 } else { uni.navigateTo({ url: '/pages/detail?id=' + id }) // 窄屏:跳转 } } </script> <style> .list-wide { width: 100%; } .list-narrow { width: 50%; border-right: 1px solid #000; } </style>

配套的组件级媒体查询方案还有match-media组件(在组件内放置内容并指定 media query,条件满足时展示)与uni.createMediaQueryObserver方法(仓库官方 leftWindow 页面即使用该方法监听minWidth: 768)。组件级方案的优势是显式、可数据绑定、可嵌套、封装性强。

7.2 rpx 宽屏基准控制

uni-app 2.9+ 将 rpx 默认最大适配宽度设为 960px,防止宽屏下界面被等比放大到"惨不忍睹"。可在 pages.json 的 globalStyle 中自定义:

{ "globalStyle": { "rpxCalcMaxDeviceWidth": 960, "rpxCalcBaseDeviceWidth": 375, "rpxCalcIncludeWidth": 750 } }

| 参数 | 默认值 | 说明 | | :- | :- | :- | | rpxCalcMaxDeviceWidth | 960 | rpx 计算支持的最大设备宽度(px),超过后不再按屏宽缩放 | | rpxCalcBaseDeviceWidth | 375 | 超出最大宽度后采用的基准设备宽度(px) | | rpxCalcIncludeWidth | 750 | 特殊处理值(rpx),始终按实际设备宽度计算;如配置 750rpx 始终按 100% 屏宽计算 |

注意:以 750rpx 当 100% 使用是不推荐的写法(即使 nvue 不支持百分比,也应使用 flex 撑满)。若代码中确有此类写法,可配置rpxCalcIncludeWidth兜底,或改用postcss-px-to-viewport等工具将 rpx 转为 px 后采用"局部拉伸 + flex 自适应"策略。

八、小结

uni-app 的宽屏适配以leftWindow / rightWindow / topWindow 页面窗体级方案为核心:通过 pages.json 顶层配置声明窗体与生效宽度,通过 wide-screen-adaptation.md 中的 12 个窗体 API 在运行时控制窗体的显示、隐藏与样式,配合uni.$emit/uni.$on事件总线实现窗体间通信,即可把一套手机窄屏应用快速升级为 PC 宽屏分栏应用,且业务代码单一维护。跨端分栏需求则改用组件级方案(页面即组件 + match-media / createMediaQueryObserver),并善用 rpx 基准配置控制内容缩放。仓库官方示例配置位于 src/pages.json 与 src/windows/,可作为上手参考。

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询