为有牺牲多壮志,敢教日月换新天。

HarmonyOS:基于Web组件构建网络应用(2)

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ 
➤GitHub地址:https://github.com/strengthen
➤原文地址:https://www.cnblogs.com/strengthen/p/18502207
➤如果链接不是为敢技术的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

概述

相信大家都遇到过这样的场景,有时候我们点击应用的页面,会跳转到一个类似浏览器加载的页面,加载完成后,才显示这个页面的具体内容,这个加载和显示网页的过程通常都是浏览器的任务。

ArkUI为我们提供了Web组件来加载网页,借助它我们就相当于在自己的应用程序里嵌入一个浏览器,从而非常轻松地展示各种各样的网页。

图1 web组件示例图

本文将为您介绍Web组件一些常用API的使用。

Web组件介绍

Web组件是提供具有网页显示能力的组件。Web组件依赖两个参数,分别是src资源地址、controller控制器。 其中, src资源地址既支持本地资源,也支持网络资源。controller控制器是由@ohos.web.webview提供的web控制能力。

表1 Web组件参数介绍

参数名

参数类型

必填

参数描述

src

ResourceStr

网页资源地址。如果访问本地资源文件,使用$rawfile或者resource协议。如果加载应用包外沙箱路径的本地资源文件,使用file://沙箱文件路径。

controller

WebviewController

控制器。可以控制Web组件的各种行为,如网页前进、后退等

通过$rawfile加载本地资源

对于入参1,如果加载本地网页,可以通过$rawfile加载本地资源文件。

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController()
  build() {
    Column() {
      // 通过$rawfile加载本地资源文件。
      Web({ src: $rawfile("index.html"), controller: this.controller })
    }
  }
}

通过resource协议加载本地资源文件

对于入参1,如果加载本地网页,可以通过resource协议加载本地资源文件。

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController()
  build() {
    Column() {
      // 通过resource协议加载本地资源文件。
      Web({ src: "resource://rawfile/index.html", controller: this.controller })
    }
  }
}

加载在线网页

对于入参1,如果加载在线网页,可以传入对应的网页地址。

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController()
  build() {
    Column() {
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

当访问在线网页时,需要在module.json5文件中添加网络权限:ohos.permission.INTERNET。

"module": {
    "requestPermissions": [
         {"name": "ohos.permission.INTERNET"}
     ]
 }

Webview的基本使用

@ohos.web.webview是系统提供的基础能力,提供了许多web控制的能力。例如,WebMessagePort、 WebviewController等。

表2 Webview能力介绍

名称

说明

WebMessagePort

通过WebMessagePort可以进行消息的发送以及接收。

WebviewController

通过WebviewController可以控制Web组件各种行为。

WebCookieManager

通过WebCookie可以控制Web组件中的cookie的各种行为

WebviewController

通过WebviewController可以控制Web组件各种行为。一个WebviewController对象只能控制一个Web组件,且必须在Web组件和WebviewController绑定后,才能调用WebviewController上的方法(静态方法除外)。

WebviewController下包含runJavaScript、 registerJavaScriptProxy、 createWebMessagePorts等接口。

表3 WebviewController接口介绍

接口名称

说明

runJavaScript

异步执行JavaScript脚本,并通过回调方式返回脚本执行的结果。runJavaScript需要在loadUrl完成后,比如onPageEnd中调用。

registerJavaScriptProxy

注入JavaScript对象到window对象中,并在window对象中调用该对象的方法。

createWebMessagePorts

创建Web消息端口

ArkTS调用H5

runJavaScript(script: string): Promise<string>

异步执行JavaScript脚本,并通过Promise方式返回脚本执行的结果。runJavaScript需要在loadUrl完成后,比如onPageEnd中调用。

import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .javaScriptAccess(true)
        .onPageEnd(e => {
          try {
            this.controller.runJavaScript('test()')
              .then((result) => {
                console.log('result: ' + result);
              })
              .catch((error: BusinessError) => {
                console.error("error: " + error);
              })
            if (e) {
              console.info('url: ', e.url);
            }
          } catch (error) {
            let e: BusinessError = error as BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
    }
  }
}

加载html文件

<!-- index.html -->
<!DOCTYPE html>
<html>
  <meta charset="utf-8">
  <body>
      Hello world!
  </body>
  <script type="text/javascript">
  function test() {
      console.log('Ark WebComponent')
      return "This value is from index.html"
  }
  </script>
</html>

案例介绍

在这个案例中抽奖转盘是一个Web页面。我们点击抽奖,Web页面中的抽奖转盘会开始运动,(停顿)结束抽奖后,原生页面会弹出一个提示弹窗。

图2 抽奖转盘案例

Web页面准备

Web抽奖应用的本地页面代码在entry\src\main\resources目录下,由index.html、index.js、index.css文件组成。抽奖方法的入口函数为startDraw,定义在index.js文件中,为Web应用。

index.html文件代码如下所示:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="./css/index.css">
    <meta charset="UTF-8">
    <title>抽奖页面</title>
    <style>
        #prize {
            border-radius: 16px 16px 16px 16px;
            background-image: linear-gradient(180deg, #A2DAFF 0%, #EAF5FF 100%);
            margin-left: 1.82%;
            margin-top: 1.43%;
            width: 96.5%;
            height: 96.7%;
        }
    </style>
</head>
<body>
    <div class="luckyDraw">
        <!-- Use an unordered list to implement a lottery tray -->
        <ul id="prize" class="prizes">
            <li class="prizes-li active"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" src="#"></li>
            <li class="prizes-li"><img class="pic" onclick="startDraw()" src="#"></li>
        </ul>
    </div>
    <script src="./js/index.js"></script>
</body>
</html>

index.js关键代码如下所示:

// 奖品数组
let prizesArr = ["啤酒", "奶茶", "汉堡", "咖啡", "西瓜", "鸡腿", "柠檬", "蛋糕"];
// 奖品对应的图片数组
let arrBigImg = ["./img/1-beer.png", "./img/2-milk.png", "./img/3-hamburg.png",
  "./img/4-coffee.png", "./img/5-watermelon.png", "./img/6-drumstick.png",
  "./img/7-lemon.png", "./img/8-cake.png", "./img/9-prizes.png"];
// 省略其他的其他参数
...
// 转盘函数
function roll() {
  // 省略实现代码
  ...
}

function startDraw() {
  if (isClick) {
    count = 0;
    // 随即生成位置
    index = Math.floor(Math.random() * prizesArr.length + 1);
    roll();
    isClick = false;
  }
}

function openDialog() {
  confirm(prizesArr[prizesPosition]);
}

原生页面

为了实现抽奖功能,在原生页面需要实现的具体步骤如下所示:

  1. 在按钮的点击事件中,通过runJavaScript方法,来调用Web页面中的抽奖方法。
  2. Web页面完成抽奖后,我们要在Web页面中调用confirm方法,提示抽奖完成。
  3. 完成抽奖后,要在原生页面中写一个onConfirm的确认事件。
  4. 在onConfirm确认事件中,调用AlertDialog方法,来实现二次确认弹窗, 用于用户的友好交互。

ArkTS关键代码如下所示:

import { webview } from '@kit.ArkWeb';
import { router } from '@kit.ArkUI';

@Entry
@Component
struct WebPage {
  // 创建WebviewController对象
  webController: webview.WebviewController = new webview.WebviewController();
  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      ...
      Row() {
        Column() {
          Row() {
          ...
          // Web组件,src为资源地址,controller为控制器
          Web({ src: this.params['path'], controller: this.webController })
            .zoomAccess(false)
            .width(Const.WebConstant_WIDTH)
            .aspectRatio(1)
            // 网页调用confirm()告警时触发此回调
            .onConfirm((event) => {
              // 用户定义的弹窗
              AlertDialog.show({
                message: Const.WEB_ALERT_DIALOG_TEXT_VALUE + event?.message,
                confirm: {
                  value: $r('app.string.web_alert_dialog_button_value'),
                  action: () => {
                    event?.result.handleConfirm();
                  }
                },
                cancel: () => {
                  event?.result.handleCancel();
                }
              });
              return true;
            })
            ...
          // 抽奖按钮
          Button($r('app.string.btnValue'))
            .fontSize(Const.WebConstant_BUTTON_FONT_SIZE)
            .fontColor($r('app.color.start_window_background'))
            .margin({ top: Const.WebConstant_BUTTON_MARGIN_TOP })
            .width(Const.WebConstant_BUTTON_WIDTH)
            .height(Const.WebConstant_BUTTON_HEIGHT)
            .backgroundColor($r('app.color.blue'))
            .borderRadius(Const.WebConstant_BUTTON_BORDER_RADIUS)
            .onClick(() => {
              // 调用js函数的入口
              this.webController.runJavaScript('startDraw()');
            })
        }
        .width(Const.WebConstant_FULL_WIDTH)
        .height(Const.WebConstant_FULL_HEIGHT)
      }
    ...
  }
}

 

posted @ 2024-10-25 11:51  为敢技术  阅读(0)  评论(0编辑  收藏  举报