使用Web元件載入頁面

为敢技术發表於2024-10-19

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公眾號:山青詠芝(MaoistLearning)
➤部落格園地址:為敢技術(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen
➤原文地址:https://www.cnblogs.com/strengthen/p/18475706
➤如果連結不是為敢技術的部落格園地址,則可能是爬取作者的文章。
➤原文已修改更新!強烈建議點選原文地址閱讀!支援作者!支援原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

頁面載入是Web元件的基本功能。根據頁面載入資料來源可以分為三種常用場景,包括載入網路頁面、載入本地頁面、載入HTML格式的富文字資料。

頁面載入過程中,若涉及網路資源獲取,需要配置ohos.permission.INTERNET網路訪問許可權。

載入網路頁面

開發者可以在Web元件建立時,指定預設載入的網路頁面 。在預設頁面載入完成後,如果開發者需要變更此Web元件顯示的網路頁面,可以透過呼叫loadUrl()介面載入指定的網頁。Web元件的第一個引數變數src不能透過狀態變數(例如:@State)動態更改地址,如需更改,請透過loadUrl()重新載入。

在下面的示例中,在Web元件載入完“www.example.com”頁面後,開發者可透過loadUrl介面將此Web元件顯示頁面變更為“www.example1.com”。

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

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

  build() {
    Column() {
      Button('loadUrl')
        .onClick(() => {
          try {
            // 點選按鈕時,透過loadUrl,跳轉到www.example1.com
            this.controller.loadUrl('www.example1.com');
          } catch (error) {
            let e: BusinessError = error as BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      // 元件建立時,載入www.example.com
      Web({ src: 'www.example.com', controller: this.controller})
    }
  }
}

載入本地頁面

將本地頁面檔案放在應用的rawfile目錄下,開發者可以在Web元件建立的時候指定預設載入的本地頁面 ,並且載入完成後可透過呼叫loadUrl()介面變更當前Web元件的頁面。

在下面的示例中展示載入本地頁面檔案的方法:

  • 將資原始檔放置在應用的resources/rawfile目錄下。

    圖1 資原始檔路徑

  • 應用側程式碼。

    // xxx.ets
    import { webview } from '@kit.ArkWeb';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct WebComponent {
      controller: webview.WebviewController = new webview.WebviewController();
    
      build() {
        Column() {
          Button('loadUrl')
            .onClick(() => {
              try {
                // 點選按鈕時,透過loadUrl,跳轉到local1.html
                this.controller.loadUrl($rawfile("local1.html"));
              } catch (error) {
                let e: BusinessError= error as BusinessError;
                console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
              }
            })
          // 元件建立時,透過$rawfile載入本地檔案local.html
          Web({ src: $rawfile("local.html"), controller: this.controller })
        }
      }
    }
  • local.html頁面程式碼。

    <!-- local.html -->
    <!DOCTYPE html>
    <html>
      <body>
        <p>Hello World</p>
      </body>
    </html>
  • local1.html頁面程式碼。

    <!-- local1.html -->
    <!DOCTYPE html>
    <html>
      <body>
        <p>This is local1 page</p>
      </body>
    </html>

載入HTML格式的文字資料

Web元件可以透過loadData()介面實現載入HTML格式的文字資料。當開發者不需要載入整個頁面,只需要顯示一些頁面片段時,可透過此功能來快速載入頁面。

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

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

  build() {
    Column() {
      Button('loadData')
        .onClick(() => {
          try {
            // 點選按鈕時,透過loadData,載入HTML格式的文字資料
            this.controller.loadData(
              "<html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>",
              "text/html",
              "UTF-8"
            );
          } catch (error) {
            let e: BusinessError= error as BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      // 元件建立時,載入www.example.com
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

動態建立Web元件

支援命令式建立Web元件,這種方式建立的元件不會立即掛載到元件樹,即不會對使用者呈現(元件狀態為Hidden和InActive),開發者可以在後續使用中按需動態掛載。後臺啟動的Web例項不建議超過200個。

// 載體Ability
// EntryAbility.ets
import { createNWeb } from "../pages/common"
onWindowStageCreate(windowStage: window.WindowStage): void {
  windowStage.loadContent('pages/Index', (err, data) => {
    // 建立Web動態元件(需傳入UIContext),loadContent之後的任意時機均可建立
    createNWeb("https://www.example.com", windowStage.getMainWindowSync().getUIContext());
    if (err.code) {
      return;
    }
  });
}
// 建立NodeController
// common.ets
import { webview } from '@kit.ArkWeb';
import { NodeController, BuilderNode, Size, FrameNode, UIContext } from '@kit.ArkUI';

// @Builder中為動態元件的具體元件內容
// Data為入參封裝類
class Data{
  url: string = "https://www.example.com";
  controller: WebviewController = new webview.WebviewController();
}

@Builder
function WebBuilder(data:Data) {
  Column() {
    Web({ src: data.url, controller: data.controller })
      .width("100%")
      .height("100%")
  }
}

let wrap = wrapBuilder<Data[]>(WebBuilder);

// 用於控制和反饋對應的NodeContainer上的節點的行為,需要與NodeContainer一起使用
export class myNodeController extends NodeController {
  private rootnode: BuilderNode<Data[]> | null = null;
  // 必須要重寫的方法,用於構建節點數、返回節點掛載在對應NodeContainer中
  // 在對應NodeContainer建立的時候呼叫、或者透過rebuild方法呼叫重新整理
  makeNode(uiContext: UIContext): FrameNode | null {
    console.log(" uicontext is undefined : "+ (uiContext === undefined));
    if (this.rootnode != null) {
      // 返回FrameNode節點
      return this.rootnode.getFrameNode();
    }
    // 返回null控制動態元件脫離繫結節點
    return null;
  }
  // 當佈局大小發生變化時進行回撥
  aboutToResize(size: Size) {
    console.log("aboutToResize width : " + size.width  +  " height : " + size.height )
  }

  // 當controller對應的NodeContainer在Appear的時候進行回撥
  aboutToAppear() {
    console.log("aboutToAppear")
  }

  // 當controller對應的NodeContainer在Disappear的時候進行回撥
  aboutToDisappear() {
    console.log("aboutToDisappear")
  }

  // 此函式為自定義函式,可作為初始化函式使用
  // 透過UIContext初始化BuilderNode,再透過BuilderNode中的build介面初始化@Builder中的內容
  initWeb(url:string, uiContext:UIContext, control:WebviewController) {
    if(this.rootnode != null)
    {
      return;
    }
    // 建立節點,需要uiContext
    this.rootnode = new BuilderNode(uiContext)
    // 建立動態Web元件
    this.rootnode.build(wrap, { url:url, controller:control })
  }
}
 // 建立Map儲存所需要的NodeController
let NodeMap:Map<string, myNodeController | undefined> = new Map();
// 建立Map儲存所需要的WebViewController
let controllerMap:Map<string, WebviewController | undefined> = new Map();

// 初始化需要UIContext 需在Ability獲取
export const createNWeb = (url: string, uiContext: UIContext) => {
  // 建立NodeController 
  let baseNode = new myNodeController();
  let controller = new webview.WebviewController() ;
  // 初始化自定義Web元件
  baseNode.initWeb(url, uiContext, controller);
  controllerMap.set(url, controller)
  NodeMap.set(url, baseNode);
}
// 自定義獲取NodeController介面
export const getNWeb = (url : string) : myNodeController | undefined => {
  return NodeMap.get(url);
}
// 使用NodeController的Page頁
// Index.ets
import { getNWeb } from "./common"
@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        // NodeContainer用於與NodeController節點繫結,rebuild會觸發makeNode
        // Page頁透過NodeContainer介面繫結NodeController,實現動態元件頁面顯示
        NodeContainer(getNWeb("https://www.example.com"))
          .height("90%")
          .width("100%")
      }
      .width('100%')
    }
    .height('100%')
  }
}

相關文章