您现在的位置是:网站首页> 小程序设计
宽屏适配指南
- 小程序设计
- 2021-05-16
- 1135人已阅读
1. 页面窗体级适配方案:leftWindow、rightWindow、topWindow
以目前手机屏幕为主window,在左右上,可新扩展 leftWindow、rightWindow、topWindow,这些区域可设定在一定屏幕宽度范围自动出现或消失。这些区域各自独立,切换页面支持在各自的window内刷新,而不是整屏刷新。
各个window之间可以交互通信。
rightWindow
对应的页面不需要重写一遍新闻详情的页面逻辑,只需要引入之前的详情页面组件(详情页面/pages/detail/detail
可自动转化为pages-detail-detail
组件使用)。
<!--responsive/right-window.vue--><template> <view> <!-- 这里将 /pages/detail/detail.nvue 页面作为一个组件使用 --> <!-- 路径 “/pages/detail/detail” 转为 “pages-detail-detail” 组件 --> <pages-detail-detail ref="detailPage"></pages-detail-detail> </view></template><script> export default { created(e) { //监听自定义事件,该事件由详情页列表的点击触发 uni.$on('updateDetail', (e) => { // 执行 detailPage组件,即:/pages/detail/detail.nvue 页面的load方法 this.$refs.detailPage.load(e.detail); }) }, onLoad() {}, methods: {} }</script>
然后在新闻列表页面,处理点击列表后与rightWindow交互通信的逻辑。
// pages/news/news-page.nvuegoDetail(detail) { if (this._isWidescreen) { //若为宽屏,则触发右侧详情页的自定义事件,通知右侧窗体刷新新闻详情 uni.$emit('updateDetail', { detail: encodeURIComponent(JSON.stringify(detail)) }) } else { // 若为窄屏,则打开新窗体,在新窗体打开详情页面 uni.navigateTo({ url: '/pages/detail/detail?query=' + encodeURIComponent(JSON.stringify(detail)) }); }},
可以看到,无需太多工作量,就可以快速把一个为手机窄屏开发的应用,快速适配为PC宽屏应用。并且以后的代码维护,仍然是同一套,当业务迭代时不需要多处升级。
rightWindow适用于分栏式应用,那leftWindow一般用于什么场景?
leftWindow比较适合放置导航页面。如果你的应用首页有很多tab和宫格导航,那么可以把它们重组,放在leftWindow作为导航。之前在手机竖屏上依靠多级tab和宫格导航的场景,可以在leftWindow里通过tree或折叠面板方式导航。
leftWindow除了适用于手机应用适配大屏,也适用于重新开发的PC应用,尤其是PC Admin管理控制台。
目前的leftWindow、rightWindow、topWindow 只支持web端。计划后续在Pad App上实现该配置。小程序无法支持该配置
2. 组件级适配方案:match-media组件
leftWindow等方案是页面窗体级适配方案。适于独立的页面。那么在同一个页面中,是否可以适配不同屏宽?当然可以,此时可以使用组件级适配方案。
uni-app提供了 match-media组件 和配套的 uni.createMediaQueryObserver 方法。
这是一个媒体查询适配组件,可以更简单的用于动态屏幕适配。
在match-media
组件中放置内容,并为组件指定一组 media query 媒体查询规则,如屏幕宽度。运行时,如屏幕宽度满足查询条件,这个组件就会被展示,反之则隐藏。
match-media
组件的优势包括:
- 开发者能够更方便、显式地使用 Media Query 能力,而不是耦合在 CSS 文件中,难以复用。
- 能够在模板中结合数据绑定动态地使用,不仅能做到组件的显示或隐藏,在过程式 API 中可塑性更高,例如能够根据尺寸变化动态地添加 class 类名,改变样式。
- 能够嵌套式地使用 Media Query 组件,即能够满足局部组件布局样式的改变。
- 组件化之后,封装性更强,能够隔离样式、模版以及绑定在模版上的交互事件,还能够提供更高的可复用性。
match-media
media query 匹配检测节点。
类似于网页开发中使用媒体查询来适配大屏小屏,match-media是一个可适配不同屏幕的基本视图组件。可以指定一组 media query 媒体查询规则,满足查询条件时,这个组件才会被展示。
例如在match-media组件中放置一个侧边栏,媒体查询规则设置为宽屏才显示,就可以实现在PC宽屏显示该侧边栏,而在手机窄屏中不显示侧边栏的效果。
注意:支付宝小程序、qq小程序、百度小程序、字节小程序,暂不支持监听屏幕动态改变,即只执行一次媒体查询。
属性说明
属性名 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
min-width | number | 否 | 页面最小宽度( px 为单位) | |
max-width | number | 否 | 页面最大宽度( px 为单位) | |
width | number | 否 | 页面宽度( px 为单位) | |
min-height | number | 否 | 页面最小高度( px 为单位) | |
max-height | number | 否 | 页面最大高度( px 为单位) | |
height | number | 否 | 页面高度( px 为单位) | |
orientation | string | 否 | 屏幕方向( landscape 或 portrait ) |
match-media 示例
以下示例代码,推荐使用HBuilderX,新建uni-app项目,可直接体验完整示例。
<template> <view> <match-media :min-width="375" :max-width="800" > <view>当页面最小宽度 375px, 页面宽度最大 800px 时显示</view> </match-media> <match-media :min-height="400" :orientation="landscape"> <view>当页面高度不小于 400px 且屏幕方向为横向时展示这里</view> </match-media> </view></template>
MediaQueryObserver 对象,用于监听页面 media query 状态的变化,如界面的宽高是不是在某个指定的范围内。
uni.createMediaQueryObserver([this])
创建并返回一个 MediaQueryObserver
对象实例。
this说明:
自定义组件实例。小程序端不支持此参数,传入仅为抹平写法差异
平台兼容性
app | 微信小程序 | 支付宝小程序 | qq小程序 | 百度小程序 | 字节小程序 | 360小程序 | 快应用 |
---|---|---|---|---|---|---|---|
2.8.12+,app-vue | 基础库 2.11.1+ | √ | √ | √ | √ | √ | X |
注意:支付宝小程序、qq小程序、百度小程序、字节小程序,暂不支持监听屏幕动态改变,即只执行一次媒体查询。
MediaQueryObserver 对象的方法列表
tips: 和 UI 相关的 api 在组件 mountd 后执行
方法 | 说明 |
---|---|
MediaQueryObserver.observe(Object descriptor, function callback) | 开始监听页面 media query 变化情况 |
MediaQueryObserver.disconnect() | 停止监听,回调函数将不再触发 |
Object descriptor
属性名 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
min-width | number | 否 | 页面最小宽度( px 为单位) | |
max-width | number | 否 | 页面最大宽度( px 为单位) | |
width | number | 否 | 页面宽度( px 为单位) | |
min-height | number | 否 | 页面最小高度( px 为单位) | |
max-height | number | 否 | 页面最大高度( px 为单位) | |
height | number | 否 | 页面高度( px 为单位) | |
orientation | string | 否 | 屏幕方向( landscape 或 portrait ) |
observe 回调函数包含一个参数
参数 | 类型 | 说明 |
---|---|---|
matches | boolean | 页面的当前状态是否满足所指定的 media query |
代码示例
以下示例代码,推荐使用HBuilderX,新建uni-app项目,可直接体验完整示例。
<template>
<view class="content">
<view class="">
要求页面最小宽度 375px, 且页面宽度最大 500px,是否匹配: {{matches}} </view>
<view>
要求屏幕方向为纵向,是否匹配: {{landscape}} </view>
</view></template><script>
let landscapeOb export default {
data() {
return {
matches: false,
landscape: false,
mediaQueryOb: null
}
},
onLoad() {
},
// 和 UI 相关的 api 在组件 mountd 后执行
mounted() {
this.testMediaQueryObserver()
this.landscapeObserver()
},
methods: {
testMediaQueryObserver() {
this.mediaQueryOb = uni.createMediaQueryObserver(this)
this.mediaQueryOb.observe({
minWidth: 375, //页面最小宽度 375px
maxWidth: 500 //页面宽度最大 500px
}, matches => {
this.matches = matches;
})
},
landscapeObserver() {
landscapeOb = uni.createMediaQueryObserver(this)
landscapeOb.observe({
orientation: 'landscape' //屏幕方向为纵向
}, matches => {
this.landscape = matches })
},
destroyed () {
this.mediaQueryOb.disconnect() //组件销毁时停止监听
landscapeOb.disconnect()
}
}
}</script><style>
.content {
text-align: center;
height: 400upx;
}</style>
3. 内容缩放拉伸的处理
除了根据屏宽动态显示和隐藏内容,其实还有一大类屏幕适配需求,即:内容不会根据屏宽动态显示隐藏,而是缩放或拉伸。
具体来说,内容适应又有两种细分策略:
- 局部拉伸:页面内容划分为固定区域和长宽动态适配区域,固定区域使用固定的px单位约定宽高,长宽适配区域则使用flex自动适配。当屏幕大小变化时,固定区域不变,而长宽适配区域跟着变化
- 等比缩放:根据页面屏幕宽度缩放。rpx其实属于这种类型。在宽屏上,rpx变大,窄屏上rpx变小。
举个实际的例子,比如一个列表页面,左边有一个图标,右边是2行文字。
- 如果使用策略1,即局部拉伸,那么左边的图标部分固定一个宽高,右边的2行文字的大小也固定,但2行文字的宽度自适应,占满屏幕右侧的空间。也就是屏宽宽度变化后,只有2行文字的宽度在变化,其他一切不变。
- 如果使用策略2,即等比缩放,那么整个列表均使用rpx,在宽屏上,图标变大、右边的2行文字变大,列表项行高变大。而在窄屏上,一切又都变小。
策略2省事,设计师按750px屏宽出图,程序员直接按rpx写代码即可。但策略2的实际效果不如策略1好。程序员使用策略1,分析下界面,设定好局部拉伸区域,这样可以有更好的用户体验。
这里需要对rpx的使用特别强调一下。
在移动设备上也有很多屏幕宽度,设计师一般只会按照750px屏幕宽度出图。此时使用rpx的好处在于,各种移动设备的屏幕宽度差异不是很大,相对于750px微调缩放后的效果,尽可能的还原了设计师的设计。
但是,一旦脱离移动设备,在pc屏幕,或者pad横屏状态下,因为屏幕宽度远大于750了。此时rpx根据屏幕宽度变化的结果就严重脱离了预期,大的惨不忍睹。
为此,在uni-app 2.9+起,新增了 rpx 按750px做基准屏宽的生效范围控制,并且将 rpx 的默认最大适配宽度设为了 960 px。
也就是设计师按750px出具的设计图,可适配的最大屏幕宽度为960px,在这个范围内,rpx可以根据屏幕宽度缩放。一旦超过960,rpx再根据屏幕宽度缩放就变的没有意义了。按如下配置,在超过960宽的屏幕上,会按375px作为基准宽度,这是最大程度上保持界面不失真的策略。
当然这些配置您都可以自己定义调整,在 pages.json 的 globeStyle 里配置 rpx 的如下参数。
{ "globalStyle": { "rpxCalcMaxDeviceWidth": 960, // rpx 计算所支持的最大设备宽度,单位 px,默认值为 960 "rpxCalcBaseDeviceWidth": 375, // rpx 计算使用的基准设备宽度,设备实际宽度超出 rpx 计算所支持的最大设备宽度时将按基准宽度计算,单位 px,默认值为 375 "rpxCalcIncludeWidth": 750 // rpx 计算特殊处理的值,始终按实际的设备宽度计算,单位 rpx,默认值为 750 },}
通过上述配置中的前2个,即rpxCalcMaxDeviceWidth和rpxCalcBaseDeviceWidth,即可有效解决使用了rpx后,在宽屏下界面变的奇大无比的问题。如果你不需要特别定义这2个参数的数值,则无需在pages.json
中配置它们,保持默认的960和375即可。
但是,rpx的最大适配宽度被限定后,会带来一个新问题:如果您的代码中把750rpx当做100%来使用(官方强烈不推荐这种写法,即便是nvue不支持百分比,也应该使用flex来解决撑满问题),此时不管屏幕宽度为多少,哪怕超过了960px,您的预期仍然是要占满整个屏幕宽度,但如果按rpxCalcBaseDeviceWidth的375px的策略执行将不再占满屏宽。
此时您有两种解决方案,一种是修改代码,将里面把rpx当做百分比的代码改掉;另一种是配置rpxCalcIncludeWidth,设置某个特定数值不受rpxCalcMaxDeviceWidth约束。如上述例子中的"rpxCalcIncludeWidth": 750,代表着如果写了 750rpx,始终将按屏幕宽度百分百占满来计算。
- 关于 rpx 转 px
不少开发者之前对rpx的使用过于没有节制,后来为了适配宽屏,想要改用“局部拉伸:页面内容划分为固定区域和长宽动态适配区域”的策略,此时将回归px。
比如DCloud社区的宽屏适配示例和新闻模板都没有使用rpx。
如果想把rpx转px,可以在源码里正则替换,也可以使用三方已经写好的单位转换库。下面介绍下三方库的用法。
项目根目录新增文件 postcss.config.js
,内容如下。则在编译时,编译器会自动转换rpx单位为px。
** 注意:将rpx作为百分比的用法需要手动处理
// postcss.config.jsconst path = require('path')module.exports = { parser: 'postcss-comment', plugins: { 'postcss-import': { resolve(id, basedir, importOptions) { if (id.startsWith('~@/')) { return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) } else if (id.startsWith('@/')) { return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) } else if (id.startsWith('/') && !id.startsWith('//')) { return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) } return id } }, 'autoprefixer': { overrideBrowserslist: ["Android >= 4", "ios >= 8"], remove: process.env.UNI_PLATFORM !== 'h5' }, // 借助postcss-px-to-viewport插件,实现rpx转px,文档:https://github.com/evrone/postcss-px-to-viewport/blob/master/README_CN.md // 以下配置,可以将rpx转换为1/2的px,如20rpx=10px,如果要调整比例,可以调整 viewportWidth 来实现 'postcss-px-to-viewport': { unitToConvert: 'rpx', viewportWidth: 200, unitPrecision: 5, propList: ['*'], viewportUnit: 'px', fontViewportUnit: 'px', selectorBlackList: [], minPixelValue: 1, mediaQuery: false, replace: true, exclude: undefined, include: undefined, landscape: false }, '@dcloudio/vue-cli-plugin-uni/packages/postcss': {} }}
一个让手机版网页临时可用于pc浏览器的方案
如果你的h5版已经开发完毕,还没来得及适配pc,但想在pc上先用起来。那么可以在pc网页里使用iframe,约定好宽度,在里面套用uni-app的窄屏版。
响应式布局组件:uni-row
流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。
该插件将屏幕分为五个档位:<768px
、>=768px
、>=992px
、>=1200px
、>=1920px
。
对应的可以使用xs
、sm
、md
、lg
、xl
来控制在不同分辨率下的显示效果。详情可在插件市场查看。
插件地址:https://ext.dcloud.net.cn/plugin?id=3958
基本用法
使用单一分栏创建基础的栅格布局
<uni-row class="demo-uni-row"> <uni-col> <view class="demo-uni-col dark_deep"></view> </uni-col></uni-row><uni-row class="demo-uni-row"> <uni-col :span="12"> <view class="demo-uni-col dark"></view> </uni-col> <uni-col :span="12"> <view class="demo-uni-col light"></view> </uni-col></uni-row>
分栏偏移
支持偏移指定的栏数
<uni-row class="demo-uni-row"> <uni-col :span="8"> <view class="demo-uni-col dark"></view> </uni-col> <uni-col :span="8" :offset="6"> <view class="demo-uni-col dark"></view> </uni-col></uni-row><uni-row class="demo-uni-row"> <uni-col :span="12" :pull="6"> <view class="demo-uni-col dark"></view> </uni-col></uni-row><uni-row class="demo-uni-row"> <uni-col :span="12" :push="6"> <view class="demo-uni-col dark"></view> </uni-col></uni-row>
响应式布局
共五个响应尺寸:xs、sm、md、lg 和 xl
<uni-row class="demo-uni-row"> <uni-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"> <view class="demo-uni-col dark"></view> </uni-col> <uni-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"> <view class="demo-uni-col light"></view> </uni-col> <uni-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"> <view class="demo-uni-col dark"></view> </uni-col> <uni-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"> <view class="demo-uni-col light"></view> </uni-col></uni-row>
平台差异说明
uni-row
属性名 | App(nvue) | App(vue) | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | QQ 小程序 |
---|---|---|---|---|---|---|---|---|
gutter | - | √ | √ | √ | √ | √ | √ | √ |
uni-col
属性名 | App(nvue) | App(vue) | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | QQ 小程序 |
---|---|---|---|---|---|---|---|---|
span | √ | √ | √ | √ | √ | √ | √ | √ |
offset | √ | √ | √ | √ | √ | √ | √ | √ |
push | √ | √ | √ | √ | √ | √ | √ | √ |
pull | √ | √ | √ | √ | √ | √ | √ | √ |
xs | - | √ | √ | √ | √ | √ | √ | √ |
sm | - | √ | √ | √ | √ | √ | √ | √ |
md | - | √ | √ | √ | √ | √ | √ | √ |
lg | - | √ | √ | √ | √ | √ | √ | √ |
xl | - | √ | √ | √ | √ | √ | √ | √ |
API
Row Props
其他平台
属性名 | 类型 | 可选值 | 默认值 | 必填 | 说明 |
---|---|---|---|---|---|
gutter | Number | - | 0 | 否 | 栅格间隔 |
nvue平台
属性名 | 类型 | 可选值 | 默认值 | 必填 | 说明 |
---|---|---|---|---|---|
width | Number/String | - | 750rpx | 否 | nvue 中无百分比 width,使用 span 等属性时,需配置此项rpx值 。此项不会影响其他平台展示效果 |
Col Props
属性名 | 类型 | 可选值 | 默认值 | 必填 | 说明 |
---|---|---|---|---|---|
span | Number | - | 24 | 否 | 栅格占据的列数 |
offset | Number | - | - | 否 | 栅格左侧间隔格数 |
push | Number | - | - | 否 | 栅格向右偏移格数 |
pull | Number | - | - | 否 | 栅格向左偏移格数 |
xs | Number/object | - | - | 否 | 屏幕宽度<768px 时,要显示的栅格规则,如::xs="8" 或:xs="{span: 8, pull: 4}" |
sm | Number/object | - | - | 否 | 屏幕宽度≥768px 时,要显示的栅格规则 |
md | Number/object | - | - | 否 | 屏幕宽度≥992px 时,要显示的栅格规则 |
lg | Number/object | - | - | 否 | 屏幕宽度≥1200px 时,要显示的栅格规则 |
xl | Number/object | - | - | 否 | 屏幕宽度≥1920px 时,要显示的栅格规则 |
组件示例
点击查看:https://hellouniapp.dcloud.net.cn/pages/extUI/row/row
上一篇:uniapp编译相关
下一篇:uniapp 布局及插件使用