- 小程序 / 网页 (H5) :
web-view默认强制全屏铺满页面,无法自定义宽高 ,只能整页跳转打开 H5;HBuilderX3.5.4+ H5 端支持fullscreen:false自定义尺寸。 - App 端 (Android/iOS/ 鸿蒙) :原生子 WebView,自由自定义宽 / 高 /top/left,支持运行时动态修改尺寸,是自定义布局核心场景。
- nvue 页面 :
web-view默认宽高 0,必须手动写样式 /flex:1赋值宽高才显示uni-app
一、静态固定宽高
1. 父容器约束 + CSS 百分比(通用,优先推荐)
利用外层 view 限定尺寸,web-view 继承父容器 100% 宽高,App/H5 有效,小程序无效。
<template>
<!-- 固定高度500px,宽度100%屏幕 -->
<view class="web-wrap" :style="{width:'100%',height:webH+'px'}">
<web-view :src="url" class="webview" :fullscreen="false"></web-view>
</view>
</template>
<script>
export default {
data(){
return {url:'https://xxx.com',webH:500}
}
}
</script>
<style>
.web-wrap{width:750rpx;margin:0 auto;}
.webview{width:100%;height:100%;}
</style>
- rpx 适配 :使用
750rpx做宽度基准,自动适配不同手机宽度uni-app。 - 全屏写法(App) :页面关闭原生导航
navigationStyle:"custom",web-wrap{height:100vh}铺满整屏。
2. App 专属 webview-styles 属性(原生样式)
仅 App-vue 生效,直接在组件标签设置原生 webview 位置尺寸:
<web-view
:src="url"
:fullscreen="false"
:webview-styles="{width:'100%',height:'calc(100vh - 88px)',top:88}"
/>
二、动态屏幕适配(按设备可视区自动计算宽高)
方案 1:根据系统信息动态计算高度(避让导航 / 状态栏 /tab)
通过uni.getSystemInfoSync()获取屏幕参数,扣除状态栏、自定义导航、底部安全区高度得到可用 webview 高度:
onLoad(){
const sys = uni.getSystemInfoSync()
// 状态栏高度
const statusH = sys.statusBarHeight
// 自定义导航高度88px、底部tab 50px
const navH = 88,tabH=50
// 可用高度 = 可视窗口 - 状态栏 -导航 -tab
this.webH = sys.windowHeight - statusH - navH - tabH
}
方案 2:获取父容器 DOM 真实尺寸(动态布局场景)
createSelectorQuery查询外层容器实际宽高,适配弹性布局:
async getWrapSize(){
return new Promise(res=>{
uni.createSelectorQuery().in(this)
.select('.web-wrap').boundingClientRect(res=>{res(res)}).exec()
})
},
async onReady(){
const rect = await this.getWrapSize()
this.webH = rect.height
// #ifdef APP-PLUS 同步修改原生webview尺寸
setTimeout(()=>{
const curWeb = this.$scope.$getAppWebview()
const wv = curWeb.children()[0]
wv.setStyle({height:this.webH+'px',width:rect.width+'px'})
},300)
// #endif
}
三、H5 内容自适应高度(H5 内容多高,webview 自动多高|最常用)
原理:H5 通过uni.postMessage把自身内容高度传给 UniApp,宿主动态修改 webview 高度,全平台兼容 (小程序 / App/H5)
① 嵌入的 H5 页面 JS(必须嵌入 H5)
<script>
// 发送页面实际内容高度
function sendWebHeight(){
// 取body真实滚动高度
const h = Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)
// 向uni宿主发消息
uni.postMessage({data:{type:'webHeight',val:h}})
}
// 页面加载、窗口缩放、图片加载完成都重新计算
window.onload = sendWebHeight
window.addEventListener('resize',sendWebHeight)
// 图片加载完重新计算
document.querySelectorAll('img').forEach(img=>{
img.onload = sendWebHeight
})
</script>
② UniApp 宿主页面代码
<template>
<view :style="{width:'100%',height:webH+'px'}">
<web-view :src="url" @message="onWebMsg" :fullscreen="false"></web-view>
</view>
</template>
<script>
export default {
data(){return {url:'xxx',webH:600}},
methods:{
onWebMsg(e){
const msg = e.detail.data[0]
if(msg.type==='webHeight'){
this.webH = msg.val + 20 // +20防内容截断留白
// #ifdef APP-PLUS 同步原生webview高度
setTimeout(()=>{
const wv = this.$scope.$getAppWebview().children()[0]
wv.setStyle({height:this.webH+'px'})
},100)
// #endif
}
}
}
}
</script>
缺点:外部不可控 H5(第三方网页如百度)无法植入 JS,不能用此方案。
四、App 端原生 API 精准控制 WebView(终极自定义,第三方 H5 也能用)
1. 获取原生 WebView 实例 + setStyle 修改宽高 / 坐标(仅 App)uni-app
// 页面onReady延时获取(webview初始化需要时间)
onReady(){
// #ifdef APP-PLUS
setTimeout(()=>{
// 获取当前页面原生webview
const pageWeb = this.$scope.$getAppWebview()
// 拿到web-view对应的子webview实例
const subWeb = pageWeb.children()[0]
// 动态设置:宽、高、距离顶部、左边距
subWeb.setStyle({
width:'100%',
height:'700px',
top:uni.getSystemInfoSync().statusBarHeight+88+'px',
left:0
})
// App原生API主动获取H5内容高度(无需H5插JS,第三方网页可用)
// const realH = subWeb.getContentHeight()
// subWeb.setStyle({height:realH+'px'})
},500)
// #endif
}
-
UniApp-X 专属:@contentheightchange 监听内容高度变化
<web-view :src="url" @contentheightchange="onContentChange"/>
五、横竖屏动态适配方案
-
全局页面横竖屏配置(pages.json)
"globalStyle":{
"pageOrientation":"auto" // auto自动旋转/portrait竖屏/landscape横屏
} -
横竖屏切换重算 WebView 尺寸 :监听窗口
onResize事件,重新计算宽高并更新 webviewonResize(){
const sys = uni.getSystemInfoSync()
this.webH = sys.windowHeight - 状态栏-导航高度
// #ifdef APP-PLUS
const wv = this.scope.getAppWebview().children()[0]
wv.setStyle({width:sys.windowWidth+'px',height:this.webH+'px'})
// #endif
}
H5 内部 viewport 适配(嵌入 H5 必加 meta 标签)
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
六、使用条件编译,H5平台时使用 iframe, 其他使用 webview
<template>
<view class="container">
<view class="cert__box" :style="{height:webHeight+'px',}">
<!-- :fullscreen="true" -->
<!-- #ifdef H5 -->
<iframe ref="refWebView" :src="preview_url" width="100%" height="100%" frameborder="0" scrolling="no" />
<!-- #endif -->
<!-- #ifndef H5 -->
<web-view ref="refWebView" :src="preview_url" :update-title="false"></web-view>
<!-- #endif -->
</view>
<view class="footer_btn"></view>
</view>
</template>
<script>
import { getScreenWH } from "@/common/index.js"
export default {
data() {
return {
preview_url: "https://www.csdn.net/",
footHeight:77
}
},
computed: {
webHeight() {
console.log(getScreenWH().height);
return getScreenWH().height
}
},
onLoad(opt) {
},
onShow() {
},
onReady() {
console.log("onReady >>>>>> ");
// #ifdef H5
if (this.$refs.refWebView) {
uni.showLoading()
this.$refs.refWebView.onload = () => {
// 加载成功
console.log("iframe loading finish >> onload ");
uni.hideLoading()
};
}
// #endif
// 获取元素高度
let _this = this
const query = uni.createSelectorQuery().in(this);
query.select('.footer_btn').boundingClientRect(data => {
console.log("footer_btn",data)
_this.footHeight = data.height
}).exec();
},
onUnload() {
},
methods: {
init() {
apiGetCollectAuthSignUrl(this.applyId, this.taskId).then(res => {
if (res && res.data) {
this.preview_url = res.data.preview_url
this.$forceUpdate()
}
}).catch(e=>{
this.$toast(e.msg)
})
},
handleNext() {
uni.switchTab({
url:"/pages/index/index"
})
}
}
}
</script>
<style>
.page {
background-color: rgba(242, 244, 245, 1) 30.77%;
}
</style>
<style scoped lang="scss">
.container {
background: linear-gradient(360deg, rgba(242, 244, 245, 1) 30.77%, #F54F3C 76.44%);
width: 750rpx;
min-height: 800px;
overflow: hidden;
.tip-container {
margin: 40rpx 30rpx;
.tip__tag {
font-weight: 500;
font-size: 36rpx;
color: #FFFFFF;
text-align: left;
}
.tip_content {
font-weight: 400;
font-size: 24rpx;
color: #FFFFFF;
line-height: 40rpx;
text-align: left;
display: block;
}
}
.cert__box {
background: #FFFFFF;
border-radius: 16rpx;
min-height: 800rpx;
margin: 30rpx;
padding: 24rpx;
}
.footer_btn {
position: fixed;
left: 0;
bottom: 0rpx;
padding-bottom: 50rpx;
width: 100%;
height: 50px;
background-color: #fff;
z-index: 9999;
.button {
height: 94rpx;
font-weight: 500;
font-size: 32rpx;
color: #FFFFFF;
line-height: 94rpx;
text-align: center;
background: linear-gradient(52deg, #FA6C4A 0%, #F34A33 100%);
border-radius: 1332rpx;
margin: 24rpx;
}
.button_disabled {
background: #EAEAEA;
color: #AAAAAA;
}
}
}
</style>