鴻蒙HarmonyOS實戰-Web元件(前端函式和應用側函式相互呼叫)

蜀道山QAQ發表於2024-05-29

🚀前言

前端函式和應用側函式相互呼叫是指前端頁面中的JavaScript函式和應用程式側的函式之間進行相互呼叫。

在前端開發中,常常會使用JavaScript函式來處理使用者的互動事件和操作。這些函式可以在前端頁面中定義,例如透過事件監聽器或者按鈕點選事件來觸發函式的執行。這些前端函式可以使用DOM操作、修改頁面樣式以及向後端傳送請求等。

而應用側函式是指在應用程式中定義的函式,例如後端伺服器端指令碼、資料庫操作函式等。這些函式通常用於處理業務邏輯、資料處理、資料庫操作等。

前端函式和應用側函式可以透過各種方式進行相互呼叫。例如,前端函式可以透過AJAX請求將資料傳送到應用側函式進行處理,應用側函式可以返回處理結果給前端函式。另外,前端函式也可以透過呼叫後端API介面來執行應用側函式。

不過HarmonyOS的Web元件前端函式和應用側函式相互呼叫是已經封裝好的。

🚀一、呼叫前端頁面函式

🔎1.應用側呼叫前端頁面函式

🦋1.1 前端頁面

<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<h1>執行JavaScript</h1>
<p id="locationInfo">位置資訊</p>
<script>
    var locationInfo=document.getElementById("locationInfo");
    function htmlTest() {
        locationInfo.innerHTML='JavaScript Hello World! '
    }
</script>
</body>
</html>

🦋1.2 應用側

// xxx.ets
import web_webview from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  webviewController: web_webview.WebviewController = new web_webview.WebviewController();

  build() {
    Column() {
      Web({ src: $rawfile('local.html'), controller: this.webviewController})
      Button('runJavaScript')
        .onClick(() => {
          this.webviewController.runJavaScript('htmlTest()');
        })
    }
  }
}

image

🔎2.前端頁面呼叫應用側函式

🦋2.1 前端頁面

<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<button type="button" onclick="callArkTS()">Click Me!</button>
<p id="demo"></p>
<script>
    function callArkTS() {
        let str = testObjName.test();
        document.getElementById("demo").innerHTML = str;
        console.info('ArkTS Hello World! :' + str);
    }
</script>
</body>
</html>

🦋2.2 應用側

☀️2.2.1 初始化時呼叫
// xxx.ets
import web_webview from '@ohos.web.webview';

class testClass {
  constructor() {
  }

  test(): string {
    return 'ArkTS Hello World!';
  }
}

@Entry
@Component
struct WebComponent {
  webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  // 宣告需要註冊的物件
  @State testObj: testClass = new testClass();

  build() {
    Column() {
      // web元件載入本地index.html頁面
      Web({ src: $rawfile('index.html'), controller: this.webviewController})
        // 將物件注入到web端
        .javaScriptProxy({
          object: this.testObj,
          name: "testObjName",
          methodList: ["test"],
          controller: this.webviewController
        })
    }
  }
}

image

☀️2.2.2 初始化後呼叫
// xxx.ets
import web_webview from '@ohos.web.webview';
// @ts-ignore
import business_error from '@ohos.base';

class testClass {
  constructor() {
  }

  test(): string {
    return "ArkUI Web Component";
  }

  toString(): void {
    console.log('Web Component toString');
  }
}

@Entry
@Component
struct Index {
  webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  @State testObj: testClass = new testClass();

  build() {
    Column() {
      Button('refresh')
        .onClick(() => {
          try {
            this.webviewController.refresh();
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Button('Register JavaScript To Window')
        .onClick(() => {
          try {
            this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "test"]);
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Web({ src: $rawfile('local.html'), controller: this.webviewController })
    }
  }
}

image

🔎3.建立應用側與前端頁面資料通道

🦋3.1 前端頁面

<!--xxx.html-->
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebView Message Port Demo</title>
</head>
<body>
    <h1>WebView Message Port Demo</h1>
    <div>
        <input type="button" value="SendToEts" onclick="PostMsgToEts(msgFromJS.value);"/><br/>
        <input id="msgFromJS" type="text" value="send this message from HTML to ets"/><br/>
    </div>
    <p class="output">display received message send from ets</p>
</body>
<script>
var h5Port;
var output = document.querySelector('.output');
window.addEventListener('message', function (event) {
    if (event.data === '__init_port__') {
        if (event.ports[0] !== null) {
            h5Port = event.ports[0]; // 1. 儲存從ets側傳送過來的埠
            h5Port.onmessage = function (event) {
              // 2. 接收ets側傳送過來的訊息.
              var msg = 'Got message from ets:';
              var result = event.data;
              if (typeof(result) === 'string') {
                console.info(`received string message from html5, string is: ${result}`);
                msg = msg + result;
              } else if (typeof(result) === 'object') {
                if (result instanceof ArrayBuffer) {
                  console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
                  msg = msg + 'lenght is ' + result.byteLength;
                } else {
                  console.info('not support');
                }
              } else {
                console.info('not support');
              }
              output.innerHTML = msg;
            }
        }
    }
})
// 3. 使用h5Port往ets側傳送訊息.
function PostMsgToEts(data) {
    if (h5Port) {
      h5Port.postMessage(data);
    } else {
      console.error('h5Port is null, Please initialize first');
    }
}
</script>
</html>

🦋3.2 應用側

// xxx.ets
import web_webview from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  controller: web_webview.WebviewController = new web_webview.WebviewController();
  ports: web_webview.WebMessagePort[];
  @State sendFromEts: string = 'Send this message from ets to HTML';
  @State receivedFromHtml: string = 'Display received message send from HTML';

  build() {
    Column() {
      // 展示接收到的來自HTML的內容
      Text(this.receivedFromHtml)
      // 輸入框的內容傳送到html
      TextInput({placeholder: 'Send this message from ets to HTML'})
        .onChange((value: string) => {
          this.sendFromEts = value;
        })

      Button('postMessage')
        .onClick(() => {
          try {
            // 1、建立兩個訊息埠。
            this.ports = this.controller.createWebMessagePorts();
            // 2、在應用側的訊息埠(如埠1)上註冊回撥事件。
            this.ports[1].onMessageEvent((result: web_webview.WebMessage) => {
              let msg = 'Got msg from HTML:';
              if (typeof(result) === 'string') {
                console.info(`received string message from html5, string is: ${result}`);
                msg = msg + result;
              } else if (typeof(result) === 'object') {
                if (result instanceof ArrayBuffer) {
                  console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
                  msg = msg + 'lenght is ' + result.byteLength;
                } else {
                  console.info('not support');
                }
              } else {
                console.info('not support');
              }
              this.receivedFromHtml = msg;
            })
            // 3、將另一個訊息埠(如埠0)傳送到HTML側,由HTML側儲存並使用。
            this.controller.postMessage('__init_port__', [this.ports[0]], '*');
          } catch (error) {
            console.error(`ErrorCode: ${error.code},  Message: ${error.message}`);
          }
        })

      // 4、使用應用側的埠給另一個已經傳送到html的埠傳送訊息。
      Button('SendDataToHTML')
        .onClick(() => {
          try {
            if (this.ports && this.ports[1]) {
              this.ports[1].postMessageEvent(this.sendFromEts);
            } else {
              console.error(`ports is null, Please initialize first`);
            }
          } catch (error) {
            console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
          }
        })
      Web({ src: $rawfile('xxx.html'), controller: this.controller })
    }
  }
}

image

🚀寫在最後

  • 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
  • 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  • 關注小編,同時可以期待後續文章ing🚀,不定期分享原創知識。
  • 更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY

image

相關文章