相信大家都遇到过这样的场景,有时候我们点击应用的页面,会跳转到一个类似浏览器加载的页面,加载完成后,才显示这个页面的具体内容,这个加载和显示网页的过程通常都是浏览器的任务。
ArkUI为我们提供了Web组件来加载网页,借助它我们就相当于在自己的应用程序里嵌入一个浏览器,从而非常轻松地展示各种各样的网页。
加载在线网页
Web组件的使用非常简单,只需要在Page目录下的ArkTS文件中创建一个Web组件,传入两个参数就可以了。其中src指定引用的网页路径,controller为组件的控制器,通过controller绑定Web组件,用于实现对Web组件的控制。
// xxx.ets
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
struct SecondPage {
controller: WebController = new WebController();
build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
}
}
}
// xxx.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<img src="pad.jpg">
</body>
</html>
代码运行效果图如下:
为了方便开发者学习,后面用到的HTML都是以文件的形式放到rawfile目录下,加载本地网页。
有的网页可能不能很好适配手机屏幕,需要对其缩放才能有更好的效果,开发者可以根据需要给Web组件设置zoomAccess属性,zoomAccess用于设置是否支持手势进行缩放,默认允许执行缩放。Web组件默认支持手势进行缩放。
Web({ src:'www.example.com', controller:this.controller })
.zoomAccess(true)
您还可以使用zoom(factor: number)方法用于设置网站的缩放比例。其中factor表示缩放倍数,下面示例,当点击一次按钮时,页面放大为原来的1.5倍。
// xxx.ets
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,文本会放大,但是图片不会随着文本一起放大。
Web组件还提供了处理Javascript的对话框、网页加载进度及各种通知与请求事件的方法。例如onProgressChange可以监听网页的加载进度,onPageEnd在网页加载完成时触发该回调,且只在主frame触发,onConfirm则在网页触发confirm告警弹窗时触发回调。下面以onConfirm事件为例讲解Web组件事件的使用,更多Web组件事件可以查看事件。
如果您希望响应Web组件中网页的警告弹窗事件,您可以在onAlert或者onConfirm的回调方法中处理这些事件。以confirm弹窗为例,在网页触发onConfirm()告警弹窗时,显示一个AlertDialog弹窗。
// xxx.ets
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文件:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
</body>
<script type="text/javascript">
confirm("confirm message from html")
</script>
</html>
效果图如下:
在开发专为适配Web组件的网页时,您可以实现Web组件和JavaScript代码之间的交互。Web组件可以调用JavaScript方法,JavaScript也可以调用Web组件里面的方法。
如果您希望加载的网页在Web组件中运行JavaScript,则必须为您的Web组件启用JavaScript功能,默认情况下是允许JavaScript执行的。
Web({ src:'https://www.example.com', controller:this.controller })
.javaScriptAccess(true)
您可以在Web组件onPageEnd事件中添加runJavaScript方法。事件是网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本。
// xxx.ets
struct WebComponent {
controller: WebController = new WebController();
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;
}});
})
}
}
}
<!-- index.html -->
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
</body>
<script type="text/javascript">
function test() {
return "This value is from index.html"
}
</script>
</html>
当页面加载完成时,触发onPageEnd事件,调用HTML文件中的test方法并将结果返回给Web组件。
您可以使用registerJavaScriptProxy将Web组件中的JavaScript对象注入daowindow对象中,这样网页中的JS就可以直接调用该对象了。需要注意的是,要想registerJavaScriptProxy方法生效,须调用refresh方法。下面的示例将ets文件中的对象testObj注入到了window对象中。
// xxx.ets
struct WebComponent{
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
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<button onclick="htmlTest()">调用Web组件里面的方法</button>
</body>
<script type="text/javascript">
function htmlTest() {
str = objName.test("param from Html");
}
</script>
</html>
您还可以使用deleteJavaScriptRegister删除通过registerJavaScriptProxy注册到window上的指定name的应用侧JavaScript对象。
当我们在使用浏览器浏览网页时,可以执行返回、前进、刷新等操作,Web组件同样支持这些操作。您可以使用backward()返回到上一个页面,使用forward()前进一个页面,您也可以使用refresh()刷新页面,使用clearHistory()来清除历史记录。下面通过一个简单的”浏览器”示例呈现这些功能。
// xxx.ets
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()来检查是否存在前进历史记录。
您可以使用onConsole获取网页输出的调试日志信息,当你在你的网页中使用console打印日志时,HarmonyOS系统都会调用相应的onConsole方法,这样你就可以获取到网页日志信息了。下面展示了如何在Web组件中使用onConsole输出网页中的日志:
// xxx.ets
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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
</body>
<script type="text/javascript">
console.info('info message');
console.error('error message');
</script>
</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