The getPageHeight API can obtain the actual height of the current web page content. You can select a proper method as required.
The height obtained during web page loading may be inaccurate, especially when the rendering is not complete. The value will be updated after dynamic content is loaded. The web page content may take a long time to load. To optimize the first-load speed, websites currently use dynamic web page loading techniques. When you see the first frame of a web page, the page resources are still being loaded dynamically, especially for pages that contain images and dynamic content.
For a non-static web page, you are advised to not obtain the web page content height in the onPageEnd, onPageVisible, onFirstContentfulPaint, and onFirstMeaningfulPaint events, which are Web component lifecycle callbacks and Web performance metric callbacks. Instead, based on the characteristics of the current web page, obtain the actual height of the web page content in a specific frontend callback notification through JSBridge or a delayed approach.
For a common static web page, you can obtain the page content height through getPageHeight() in the Web component lifecycle callback (such as onPageEnd) and web performance metric callback.
Code on the application side:
@Component
struct Scene1Static {
controller: webview.WebviewController = new webview.WebviewController();
@State heightText: ResourceStr = $r('app.string.waiting_for_height');
build() {
Column() {
Text('getPageHeight: ' + this.heightText)
.width('100%')
.padding(12)
.fontSize(16)
.backgroundColor('#f5f5f5')
.textAlign(TextAlign.Center)
Web({ src: $rawfile('scene1_index.html'), controller: this.controller })
.layoutWeight(1)
.onPageEnd(() => {
this.heightText = $r('app.string.scene1_on_page_end');
setTimeout(() => {
try {
const h: number = this.controller.getPageHeight();
console.info(`page height: onPageEnd: ${h}`);
this.heightText = String(h) + ' px';
} catch (err) {
console.error(`page height: onPageEnd error: ${JSON.stringify(err)}`);
this.heightText = $r('app.string.get_height_failed');
}
}, 300)
})
}
.width('100%')
.height('100%')
}
} The dynamic web page can pass a specific callback through JSBridge to notify the application side to call it.
Code on the application side:
@Component
struct Scene2JsBridge {
controller: webview.WebviewController = new webview.WebviewController();
@State heightText: ResourceStr = $r('app.string.waiting_for_height');
@State jsbObj: TestClass = new TestClass(this.controller);
aboutToAppear(): void {
this.jsbObj.onGetHeight = (h: string) => {
this.heightText = h + ' px';
};
}
build() {
Column() {
Text('getPageHeight: ' + this.heightText)
.width('100%')
.padding(12)
.fontSize(16)
.backgroundColor('#f5f5f5')
.textAlign(TextAlign.Center)
Web({ src: $rawfile('scene2_index.html'), controller: this.controller })
.layoutWeight(1)
.javaScriptAccess(true)
.javaScriptProxy({
object: this.jsbObj,
name: "jsbObj",
methodList: ["notifyToGet"],
controller: this.controller
})
}
.width('100%')
.height('100%')
}
} For a common web page, you can trigger height measurement via the load event once all resources have finished loading.
Frontend code:
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
window.addEventListener("load", function() {
if (typeof jsbObj !== 'undefined') {
jsbObj.notifyToGet();
} else {
console.info("jsbObj is undefined");
}
})
</script>
</body>
</html> When a web page contains large images, use the image loading completion callback to trigger the height measurement.
In the frontend code, replace the sample image path with the actual image resource.
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="example.jpg" id="largeImage" alt="Large Image">
<script>
var img = document.getElementById('largeImage');
img.addEventListener('load', function() {
if (typeof jsbObj !== 'undefined') {
jsbObj.notifyToGet();
} else {
console.info("jsbObj is error");
}
});
</script>
</body>
</html> When a web page contains a large number of images, trigger the height measurement after all images are loaded.
Replace the image in the frontend code with a real image.
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="example1.jpg" >
<img src="example2.jpg" >
<script>
function waitForImages() {
const images = Array.from(document.images);
const promises = images.map(img => {
if (img.complete) return Promise.resolve();
return new Promise(resolve => {
img.onload = img.onerror = resolve;
});
});
return Promise.all(promises).then(() => {
if (typeof jsbObj !== 'undefined') {
jsbObj.notifyToGet();
} else {
console.info("jsbObj is error");
}
})
}
document.addEventListener("DOMContentLoaded", waitForImages);
</script>
</body>
</html> If JSBridge is unavailable, you can add functions such as setTimeout to delay the height measurement of the current page. You can determine the specific delay time based on the complexity of the web page.
Code on the application side:
@Component
struct Scene3SetTimeout {
controller: webview.WebviewController = new webview.WebviewController();
@State heightText: ResourceStr = $r('app.string.waiting_for_height');
build() {
Column() {
Text('getPageHeight: ' + this.heightText)
.width('100%')
.padding(12)
.fontSize(16)
.backgroundColor('#f5f5f5')
.textAlign(TextAlign.Center)
Web({ src: $rawfile('scene3_index.html'), controller: this.controller })
.layoutWeight(1)
.onPageEnd(() => {
this.heightText = $r('app.string.scene3_on_page_end');
setTimeout(() => {
try {
const h: number = this.controller.getPageHeight();
console.info(`page height: onPageEnd: setTimeout: ${h}`);
this.heightText = String(h) + ' px';
} catch (err) {
console.error(`page height: onPageEnd setTimeout error: ${JSON.stringify(err)}`);
this.heightText = $r('app.string.get_height_failed');
}
}, 2000)
})
}
.width('100%')
.height('100%')
}
}