鸿蒙Web组件的生命周期是什么(新手必看)
我们可以使用 Web 组件加载本地或者在线网页。Web 组件提供了丰富的组件生命周期回调接口,通过这些回调接口,开发者可以感知 Web 组件的生命周期状态变化,并进行相关的业务处理。
Web 组件的状态主要包括:将 Controller(控制器)绑定到 Web 组件、网页加载开始、网页加载进度、网页加载结束、页面即将可见等。Web 组件的生命周期示意图如下图所示:

图 1 Web组件的生命周期示意图
在回调中,可以使用如 loadUrl、getWebId 等与网页本身无关的接口。然而,由于此时网页尚未加载完成,因此无法在回调中使用涉及网页操作的接口,如 zoomIn、zoomOut 等。
在多 frame 页面中,多个 frame 有可能同时开始加载,因此有可能出现主 frame 已经加载完成而子 frame 才开始加载或者仍在加载的情况。此外,同一页面的导航(如片段导航、历史状态切换等),或者在提交前失败、被取消的导航等,也不会触发该回调。
需要注意的是,收到该回调并不能保证 Web 绘制的下一帧将反映此时 DOM 的状态。
具体来说,在加载 LoadUrl 和 iframe 时,onLoadIntercept 事件会正常回调,但 onOverrideUrlLoading 事件在加载 LoadUrl 时不会触发,在 iframe 加载 HTTP(s) 协议或 about:blank 时也不会触发。
下面通过一个示例,来更好地认识 ArkWeb 组件的回调函数,示例代码如下:

图 2 ArkWeb 组件事件回调演示
Web 组件提供了如下接口来进行通知:
Web 组件的状态主要包括:将 Controller(控制器)绑定到 Web 组件、网页加载开始、网页加载进度、网页加载结束、页面即将可见等。Web 组件的生命周期示意图如下图所示:

图 1 Web组件的生命周期示意图
1) onControllerAttached事件
当 Controller 成功绑定到 Web 组件时,会触发该回调,并且禁止在该事件回调之前调用与 Web 组件相关的接口,否则会抛出 js-error 异常。建议在此回调中注入 JavaScript 对象 registerJavaScriptProxy,并设置自定义用户代理 setCustomUserAgent。在回调中,可以使用如 loadUrl、getWebId 等与网页本身无关的接口。然而,由于此时网页尚未加载完成,因此无法在回调中使用涉及网页操作的接口,如 zoomIn、zoomOut 等。
2) onLoadIntercept事件
在 Web 组件加载 URL 之前触发该回调,用于判断是否阻止此次访问。默认允许加载。3) onInterceptRequest事件
在 Web 组件加载 URL 之前触发该回调,用于拦截 URL 并返回响应数据。4) onPageBegin事件
在网页开始加载时触发该回调,并且只在主 frame(框架,表示一个 HTML 元素,用于展示 HTML 页面的 HTML 元素)中触发。如果加载的是 iframe 或者 frameset(用于包含 frame 的 HTML 标签)的内容,则不会触发此回调。在多 frame 页面中,多个 frame 有可能同时开始加载,因此有可能出现主 frame 已经加载完成而子 frame 才开始加载或者仍在加载的情况。此外,同一页面的导航(如片段导航、历史状态切换等),或者在提交前失败、被取消的导航等,也不会触发该回调。
5) onProgressChange事件
用于获取当前页面加载的进度。在多 frame 页面中,子 frame 有可能还在继续加载,而主 frame 已经加载完成。因此,在触发 onPageEnd 事件后,依然有可能收到 onProgressChange 事件。6) onPageEnd事件
网页加载完成时触发该回调,且只在主 frame 上触发。多 frame 页面有可能同时开始加载,即使主 frame 已经加载结束,子 frame 也有可能才开始或者继续加载中。同一页面的导航(如片段导航、历史状态切换等),或者在提交前失败、被取消的导航等,也不会触发该回调。推荐在此回调中执行 JavaScript 脚本,如 loadUrl 等。需要注意的是,收到该回调并不能保证 Web 绘制的下一帧将反映此时 DOM 的状态。
Web组件加载的其他事件
1) aboutToAppear事件
aboutToAppear 事件在创建自定义组件的新实例后,在执行其 build 函数前执行。一般建议在此设置 WebDebug 调试模式 setWebDebuggingAccess,设置 Web 内核自定义协议 URL 的跨域请求与 fetch 请求的权限 customizeSchemes,设置 Cookie(configCookie) 等。2) onOverrideUrlLoading事件
当 URL 将要加载到当前 Web 中时,onOverrideUrlLoading 事件让宿主应用程序有机会获得控制权。回调函数返回 true 会使当前 Web 中止加载 URL,返回 false 会使 Web 继续照常加载 URL。onLoadIntercept 接口和 onOverrideUrlLoading 接口行为不一致,触发时机也不同,所以它们在应用场景上存在一定区别。具体来说,在加载 LoadUrl 和 iframe 时,onLoadIntercept 事件会正常回调,但 onOverrideUrlLoading 事件在加载 LoadUrl 时不会触发,在 iframe 加载 HTTP(s) 协议或 about:blank 时也不会触发。
3) onPageVisible事件
onPageVisible 事件是 Web 回调事件。在渲染流程中,当 HTML 响应的主体开始加载,新页面即将可见时触发该回调。此时文档加载还处于早期,因此链接的资源(比如在线 CSS、在线图片等)可能尚不可用。4) onRenderExited事件
应用渲染进程异常退出时触发该回调,在此回调中可以进行系统资源的释放、数据的保存等操作。如果应用希望进行异常恢复,则需要调用 loadUrl 接口重新加载页面。5) onDisAppear事件
onDisAppear 事件为通用事件,当组件从组件树上卸载时触发该事件。下面通过一个示例,来更好地认识 ArkWeb 组件的回调函数,示例代码如下:
<!-- demo.ets --> // 导入 ArkWeb 组件 import { webview } from '@kit.ArkWeb'; // 导入业务异常 import { BusinessError } from '@kit.BasicServicesKit'; // 导入弹出窗 import { promptAction } from '@kit.ArkUI'; @Entry @Component struct Demo0201 { /* ========= Web 相关对象 ========= */ // 创建 Web 控制器对象 controller: webview.WebviewController = new webview.WebviewController(); // 创建 Web 响应对象 responseWeb: WebResourceResponse = new WebResourceResponse(); // 创建请求消息头数组 heads: Header[] = new Array(); // 准备一段本地 HTML 内容,用于拦截请求时返回 @State webData: string = "<!DOCTYPE html>\n" + "<html>\n" + "<head>\n" + "<title>HarmonyOS 开发之路</title>\n" + "</head>\n" + "<body>\n" + "<h1>欢迎进入 HarmonyOS 开发殿堂</h1>\n" + "</body>\n" + "</html>"; /* ========= 生命周期 ========= */ aboutToAppear(): void { // 开启 Web 调试 try { webview.WebviewController.setWebDebuggingAccess(true); console.log('aboutToAppear 执行了'); } catch (error) { console.error( `错误码:${(error as BusinessError).code}, 错误信息:${(error as BusinessError).message}` ); } } /* ========= UI 构建 ========= */ build() { Column() { Web({ src: $rawfile('demo0201.html'), // 加载本地 html 文件 controller: this.controller }) // 控制器挂载完成(推荐在此 loadUrl、注入 JS 对象等) .onControllerAttached(() => { console.log('onControllerAttached 方法执行'); }) // 拦截即将加载的 URL,返回 true 阻止加载 .onLoadIntercept((event) => { if (event) { console.log('onLoadIntercept 执行了:' + event.data.getRequestUrl()); } // 返回 true 表示阻止此次加载,否则允许 return true; }) // 覆盖 URL 加载策略 .onOverrideUrlLoading((webResourceRequest: WebResourceRequest) => { if ( webResourceRequest && webResourceRequest.getRequestUrl() === 'about:blank' ) { return true; } return false; }) // 拦截资源请求(可返回自定义响应) .onInterceptRequest((event) => { if (event) { console.log('onInterceptRequest 执行了:' + event.request.getRequestUrl()); // 构造响应头 this.heads.push({ headerKey: 'Connection', headerValue: 'keep-alive' }); // 填充自定义响应 this.responseWeb.setResponseHeader(this.heads); this.responseWeb.setResponseData(this.webData); this.responseWeb.setResponseEncoding('utf-8'); this.responseWeb.setResponseMimeType('text/html'); this.responseWeb.setResponseCode(200); this.responseWeb.setReasonMessage('Ok'); // 返回响应对象;返回 null 则按默认方式加载 return this.responseWeb; } return null; }) // 页面开始加载 .onPageBegin((event) => { if (event) { console.log('onPageBegin 执行:' + event.url); } }) // 首次内容绘制完成 .onFirstContentfulPaint((event) => { if (event) { console.log('onFirstContentfulPaint 执行:' + event.firstContentfulPaintMs); } }) // 加载进度变化 .onProgressChange((event) => { if (event) { console.log('onProgressChange 执行:' + event.newProgress); } }) // 页面加载结束(推荐在此执行 JS 脚本) .onPageEnd((event) => { if (event) { console.log('onPageEnd 执行:' + event.url); } }) // 页面可见 .onPageVisible((event) => { console.log('onPageVisible 执行:' + event.url); }) // 渲染进程退出 .onRenderExited((event) => { if (event) { console.log('onRenderExited 执行'); } }) // Web 组件消失 .onDisAppear(() => { promptAction.showToast({ message: 'Web 组件隐藏啦', duration: 2000 }); }); } } } <!-- demo.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <h1>Hello, ArkWeb</h1> </body> </html>运行效果如下图所示:

图 2 ArkWeb 组件事件回调演示
Web组件性能指标
在网页加载过程中,需要关注一些重要的性能指标,例如 FCP(First Contentful Paint,首次内容绘制)、FMP(First Meaningful Paint,首次有效绘制)、LCP(Largest Contentful Paint,最大内容绘制)等。Web 组件提供了如下接口来进行通知:
- onFirstContentfulPaint 事件:网页首次内容绘制的回调函数。在首次绘制文本、图像、非空白 Canvas 或者 SVG 时触发;
- onFirstMeaningfulPaint 事件:网页首次有效绘制的回调函数。在首次绘制页面主要内容时触发;
- onLargestContentfulPaint 事件:网页绘制页面最大内容的回调函数。可视区域内容最大的可见元素开始出现在页面时触发。