web组件的使用
1 概述
相信大家都遇到过这样的场景,有时候我们点击应用的页面,会跳转到一个类似浏览器加载的页面,加载完成后,才显示这个页面的具体内容,这个加载和显示网页的过程通常都是浏览器的任务。
ArkUI为我们提供了Web组件来加载网页,借助它我们就相当于在自己的应用程序里嵌入一个浏览器,从而非常轻松地展示各种各样的网页。
本文将为您介绍Web组件一些常用API的使用。
2 加载网页
加载在线网页
Web组件的使用非常简单,只需要在Page目录下的ArkTS文件中创建一个Web组件,传入两个参数就可以了。其中src指定引用的网页路径,controller为组件的控制器,通过controller绑定Web组件,用于实现对Web组件的控制。
// xxx.ets @Entry @Component struct WebComponent { controller: WebController = new WebController(); build() { Column() { Web({ src: 'https://developer.harmonyos.com/', controller: this.controller }) } } }
代码运行效果图如下:
访问在线网页时您需要在module.json5文件中申明网络访问权限:ohos.permission.INTERNET。
{ "module" : { "requestPermissions":[ { "name": "ohos.permission.INTERNET" } ] } }
加载本地网页
前面实现了Web组件加载在线网页,Web组件同样也可以加载本地网页。首先在main/resources/rawfile目录下创建一个HTML文件,然后通过$rawfile引用本地网页资源,示例代码如下:
// xxx.ets @Entry @Component struct SecondPage { controller: WebController = new WebController(); build() { Column() { Web({ src: $rawfile('index.html'), controller: this.controller }) } } }
// xxx.html
代码运行效果图如下:
为了方便开发者学习,后面用到的HTML都是以文件的形式放到rawfile目录下,加载本地网页。
3 网页缩放
有的网页可能不能很好适配手机屏幕,需要对其缩放才能有更好的效果,开发者可以根据需要给Web组件设置zoomAccess属性,zoomAccess用于设置是否支持手势进行缩放,默认允许执行缩放。Web组件默认支持手势进行缩放。
Web({ src:'www.example.com', controller:this.controller }) .zoomAccess(true)
您还可以使用zoom(factor: number)方法用于设置网站的缩放比例。其中factor表示缩放倍数,下面示例,当点击一次按钮时,页面放大为原来的1.5倍。
// xxx.ets @Entry @Component struct WebComponent { controller: WebController = new WebController(); factor: number = 1.5; build() { Column() { Button('zoom') .onClick(() => { this.controller.zoom(this.factor); }) Web({ src: 'www.example.com', controller: this.controller }) } } }
需要注意的是只有网页自身支持缩放,才能在Web组件里面进行缩放。
文本缩放
如果需要对文本进行缩放,可以使用textZoomAtio(textZoomAtio: number)方法。其中textZoomAtio用于设置页面的文本缩放百分比,默认值为100,表示100%,以下示例代码将文本放大为原来的1.5倍。
Web({ src:'www.example.com', controller:this.controller }) .textZoomAtio(150)
效果图如下:
从上面的效果图可以看出使用textZoomAtio,文本会放大,但是图片不会随着文本一起放大。
4 Web组件事件
Web组件还提供了处理Javascript的对话框、网页加载进度及各种通知与请求事件的方法。例如onProgressChange可以监听网页的加载进度,onPageEnd在网页加载完成时触发该回调,且只在主frame触发,onConfirm则在网页触发confirm告警弹窗时触发回调。下面以onConfirm事件为例讲解Web组件事件的使用,更多Web组件事件可以查看事件。
Web组件处理JS confirm事件
如果您希望响应Web组件中网页的警告弹窗事件,您可以在onAlert或者onConfirm的回调方法中处理这些事件。以confirm弹窗为例,在网页触发onConfirm()告警弹窗时,显示一个AlertDialog弹窗。
// xxx.ets @Entry @Component struct WebComponent { controller:WebController = new WebController(); build() { Column() { Web({ src:$rawfile('index.html'), controller:this.controller }) .onConfirm((event) => { AlertDialog.show({ title: 'title', message: event.message, confirm: { value: 'onAlert', action: () => { event.result.handleConfirm(); } }, cancel: () => { event.result.handleCancel(); } }) return true; }) } } }
当onConfirm回调返回false时,触发默认弹窗。当回调返回true时,系统应用可以调用系统弹窗能力(包括确认和取消),并且需要根据用户的确认或取消操作调用JsResult通知Web组件。
在rawfile目录下创建如下HTML文件:
效果图如下:
5 Web和JavaScript交互
在开发专为适配Web组件的网页时,您可以实现Web组件和JavaScript代码之间的交互。Web组件可以调用JavaScript方法,JavaScript也可以调用Web组件里面的方法。
启用JavaScript
如果您希望加载的网页在Web组件中运行JavaScript,则必须为您的Web组件启用JavaScript功能,默认情况下是允许JavaScript执行的。
Web({ src:'https://www.example.com', controller:this.controller }) .javaScriptAccess(true)
Web组件调用JS方法
您可以在Web组件onPageEnd事件中添加runJavaScript方法。事件是网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本。
// xxx.ets @Entry @Component struct WebComponent { controller: WebController = new WebController(); @State webResult: string = '' build() { Column() { Text(this.webResult).fontSize(20) Web({ src: $rawfile('index.html'), controller: this.controller }) .javaScriptAccess(true) .onPageEnd(e => { this.controller.runJavaScript({ script: 'test()', callback: (result: string)=> { this.webResult = result; }}); }) } } }
当页面加载完成时,触发onPageEnd事件,调用HTML文件中的test方法并将结果返回给Web组件。
JS调用Web组件方法
您可以使用registerJavaScriptProxy将Web组件中的JavaScript对象注入到window对象中,这样网页中的JS就可以直接调用该对象了。需要注意的是,要想registerJavaScriptProxy方法生效,须调用refresh方法。下面的示例将ets文件中的对象testObj注入到了window对象中。
// xxx.ets @Entry @Component struct WebComponent{ @State dataFromHtml: string = '' controller: WebController = new WebController() testObj = { test: (data) => { this.dataFromHtml = data; return 'ArkUI Web Component'; }, toString: () => { console.log('Web Component toString'); } } build() { Column() { Text(this.dataFromHtml).fontSize(20) Row() { Button('Register JavaScript To Window').onClick(() => { this.controller.registerJavaScriptProxy({ object: this.testObj, name: 'objName', methodList: ['test', 'toString'], }); this.controller.refresh(); }) } Web({ src: $rawfile('index.html'), controller: this.controller }) .javaScriptAccess(true) } } }
其中object表示参与注册的对象,name表示注册对象的名称为objName,与window中调用的对象名一致;methodList表示参与注册的应用侧JavaScript对象的方法,包含test、toString两个方法。在HTML中使用的时候直接使用objName调用methodList里面对应的方法即可,示例如下:
// index.html 调用Web组件里面的方法
您还可以使用deleteJavaScriptRegister删除通过registerJavaScriptProxy注册到window上的指定name的应用侧JavaScript对象。
6 处理页面导航
当我们在使用浏览器浏览网页时,可以执行返回、前进、刷新等操作,Web组件同样支持这些操作。您可以使用backward()返回到上一个页面,使用forward()前进一个页面,您也可以使用refresh()刷新页面,使用clearHistory()来清除历史记录。下面通过一个简单的”浏览器”示例呈现这些功能。
// xxx.ets @Entry @Component struct Page5 { controller: WebController = new WebController(); build() { Column() { Row() { Button("前进").onClick(() => { this.controller.forward(); }) Button("后退").onClick(() => { this.controller.backward(); }) Button("刷新").onClick(() => { this.controller.refresh(); }) Button("停止").onClick(() => { this.controller.stop(); }) Button("清除历史").onClick(() => { this.controller.clearHistory(); }) } .padding(12) .backgroundColor(Color.Gray) .width('100%') Web({ src: 'https://developer.harmonyos.com/', controller: this.controller }) } .height('100%') } }
您可以使用accessBackward()来检查当前页面是否有后退来时记录,如果有则该方法返回 true。同样,您可以使用 accessForward()来检查是否存在前进历史记录。
7 调试网络应用
您可以使用onConsole获取网页输出的调试日志信息,当你在你的网页中使用console打印日志时,HarmonyOS系统都会调用相应的onConsole方法,这样你就可以获取到网页日志信息了。下面展示了如何在Web组件中使用onConsole输出网页中的日志:
// xxx.ets @Entry @Component struct WebComponent { controller: WebController = new WebController(); build() { Column() { Web({ src: $rawfile('index.html'), controller: this.controller }) .onConsole((event) => { console.log('getMessage:' + event.message.getMessage()); console.log('getMessageLevel:' + event.message.getMessageLevel()); return false; }) } } }
// index.html
event的内容为ConsoleMessage,它包括一个对象来表示正在传递的日志信息的MessageLevel类型。您可以使用getMessageLevel()查询消息级别以确定消息的严重性,然后根据自身业务采取相应的操作。上面的示例代码,会打印如下所示的 日志消息:
08-27 19:47:27.476 27869-27937/com.example.webtest D 03B00/JSApp: app Log: getMessage:info message 08-27 19:47:27.476 27869-27937/com.example.webtest D 03B00/JSApp: app Log: getMessageLevel:3 08-27 19:47:27.478 27869-27937/com.example.webtest D 03B00/JSApp: app Log: getMessage:error message 08-27 19:47:27.478 27869-27937/com.example.webtest D 03B00/JSApp: app Log: getMessageLevel:1
8 参考链接
HTTP数据请求
1 概述
日常生活中我们使用应用程序看新闻、发送消息等,都需要连接到互联网,从服务端获取数据。例如,新闻应用可以从新闻服务器中获取最新的热点新闻,从而给用户打造更加丰富、更加实用的体验。
那么要实现这样一种能实时从服务端获取数据的场景,就依赖于HTTP数据请求。
2 什么是HTTP
HTTP即超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
HTTP的工作原理正如上图所示,客户端向服务端发出一条HTTP数据请求,服务端接收请求后向客户端返回一些数据,然后客户端再对这些数据进行解析和处理。
3 如何发起HTTP请求
HTTP数据请求功能主要由http模块提供,包括发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件等。
在进行网络请求前,您需要在module.json5文件中申明网络访问权限。
{ "module" : { "requestPermissions":[ { "name": "ohos.permission.INTERNET" } ] } }
应用访问网络需要申请ohos.permission.INTERNET权限,因为HarmonyOS提供了一种访问控制机制即应用权限,用来保证这些数据或功能不会被不当或恶意使用。关于应用权限的的详细信息开发者可以参考:访问控制。
您可以按照以下步骤完成HTTP数据请求:
- 导入http模块。
import http from '@ohos.net.http';
- 创建httpRequest对象。
使用createHttp()创建一个httpRequest对象,里面包括常用的一些网络请求方法,比如request、destroy、on('headerReceive')等。
let httpRequest = http.createHttp();
需要注意的是每一个httpRequest对象对应一个http请求任务,不可复用。
- 订阅请求头(可选)。
用于订阅http响应头,此接口会比request请求先返回,可以根据业务需要订阅此消息。
httpRequest.on('headersReceive', (header) => { console.info('header: ' + JSON.stringify(header)); });
- 发起http请求。
http模块支持常用的POST和GET等方法,封装在RequestMethod中。调用request方法发起网络请求,需要传入两个参数。第一个是请求的url地址,第二个是可选参数,类型为HttpRequestOptions,用于定义可选参数的类型和取值范围,包含请求方式、连接超时时间、请求头字段等。
使用Get请求,参数内容需要拼接到URL中进行发送,如下示例中在url后面拼接了两个自定义参数,分别命名为param1和param2,值分别为value1和value2:
let url= "https://EXAMPLE_URL?param1=v1¶m2=v2"; let promise = httpRequest.request( // 请求url地址 url, { // 请求方式 method: http.RequestMethod.GET, // 可选,默认为60s connectTimeout: 60000, // 可选,默认为60s readTimeout: 60000, // 开发者根据自身业务需要添加header字段 header: { 'Content-Type': 'application/json' } });
POST请求参数需要添加到extraData里面,如下示例中在extraData里面定义添加了两个自定义参数param1和param2,值分别为value1和value2:let url = "https://EXAMPLE_URL"; let promise = httpRequest.request( // 请求url地址 url, { // 请求方式 method: http.RequestMethod.POST, // 请求的额外数据。 extraData: { "param1": "value1", "param2": "value2", }, // 可选,默认为60s connectTimeout: 60000, // 可选,默认为60s readTimeout: 60000, // 开发者根据自身业务需要添加header字段 header: { 'Content-Type': 'application/json' } });
- 处理响应结果。
data为网络请求返回的结果,err为请求异常时返回的结果。data的类型为HttpResponse。
promise.then((data) => { if (data.responseCode === http.ResponseCode.OK) { console.info('Result:' + data.result); console.info('code:' + data.responseCode); } }).catch((err) => { console.info('error:' + JSON.stringify(err)); });
其中data.responseCode为http请求返回的状态码,如果状态码为http.ResponseCode.OK(即200),则表示请求成功,更多状态码可以在ResponseCode中查看。
data.result为服务器返回的业务数据,开发者可以根据自身业务场景解析此数据。