• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Loading Web Pages
2
3
4Page loading is a basic capability of the **Web** component. Depending on the data source, page loading falls into three types: loading of network pages, loading of local pages, and loading of HTML rich text data.
5
6
7If you need to obtain online resources when loading a page, declare the network access permission in the **module.json5** file. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
8
9  ```
10  "requestPermissions":[
11      {
12        "name" : "ohos.permission.INTERNET"
13      }
14    ]
15  ```
16
17## Loading Network Pages
18
19You can specify the default network page to be loaded when creating a **Web** component. After the default network page is loaded, call [loadUrl()](../reference/apis-arkweb/js-apis-webview.md#loadurl) if you want to change the network page displayed by the **Web** component. The value of the first parameter **src** of the **Web** component cannot be dynamically changed through a state variable (for example, @State). To change the value, call [loadUrl()](../reference/apis-arkweb/js-apis-webview.md#loadurl).
20
21
22In the following example, after the **www.\example.com** page is loaded by the **Web** component, **loadUrl** is called to change the displayed page to **www\.example1.com**.
23
24
25
26```ts
27// xxx.ets
28import { webview } from '@kit.ArkWeb';
29import { BusinessError } from '@kit.BasicServicesKit';
30
31@Entry
32@Component
33struct WebComponent {
34  controller: webview.WebviewController = new webview.WebviewController();
35
36  build() {
37    Column() {
38      Button('loadUrl')
39        .onClick(() => {
40          try {
41            // Upon button clicking, call loadUrl to redirect to www.example1.com.
42            this.controller.loadUrl('www.example1.com');
43          } catch (error) {
44            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
45          }
46        })
47      // When creating a Web component, set the default network page to be loaded to www.example.com.
48      Web({ src: 'www.example.com', controller: this.controller })
49    }
50  }
51}
52```
53
54
55## Loading Local Pages
56
57The following example shows how to load a local page file.
58
59Local page files are stored in the application's **rawfile** directory. You can specify the local page to be loaded by default when creating a **Web** component. After page loading is complete, you can call [loadUrl()](../reference/apis-arkweb/js-apis-webview.md#loadurl) to change the displayed page of the **Web** component.
60
61To reference a local CSS file when loading a local HTML file, perform the following steps:
62
63```html
64<link rel="stylesheet" href="resource://rawfile/xxx.css">
65<link rel="stylesheet" href="file:// /data/storage/el2/base/haps/entry/cache/xxx.css">// Load the local CSS file in the sandbox path.
66```
67
68- Local page file in the application's resources/rawfile directory:
69
70    **Figure 1** Path of local page files
71
72    ![resource-path](figures/resource-path.png)
73
74
75- Application code:
76
77  ```ts
78  // xxx.ets
79  import { webview } from '@kit.ArkWeb';
80  import { BusinessError } from '@kit.BasicServicesKit';
81
82  @Entry
83  @Component
84  struct WebComponent {
85    controller: webview.WebviewController = new webview.WebviewController();
86
87    build() {
88      Column() {
89        Button('loadUrl')
90          .onClick(() => {
91            try {
92              // Upon button clicking, call loadUrl to redirect to local1.html.
93              this.controller.loadUrl($rawfile("local1.html"));
94            } catch (error) {
95              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
96            }
97          })
98        // When creating a Web component, load the local.html file through $rawfile.
99        Web({ src: $rawfile("local.html"), controller: this.controller })
100      }
101    }
102  }
103  ```
104
105
106- Code of the **local.html** page:
107
108  ```html
109  <!-- local.html -->
110  <!DOCTYPE html>
111  <html>
112    <body>
113      <p>Hello World</p>
114    </body>
115  </html>
116  ```
117
118- Code of the **local1.html** page:
119
120  ```html
121  <!-- local1.html -->
122  <!DOCTYPE html>
123  <html>
124    <body>
125      <p>This is local1 page</p>
126    </body>
127  </html>
128  ```
129
130Example of loading local page files in the sandbox:
131
1321. Obtain the sandbox path through the constructed singleton object **GlobalContext**.
133
134   ```ts
135   // GlobalContext.ets
136   export class GlobalContext {
137     private constructor() {}
138     private static instance: GlobalContext;
139     private _objects = new Map<string, Object>();
140
141     public static getContext(): GlobalContext {
142       if (!GlobalContext.instance) {
143         GlobalContext.instance = new GlobalContext();
144       }
145       return GlobalContext.instance;
146     }
147
148     getObject(value: string): Object | undefined {
149       return this._objects.get(value);
150     }
151
152     setObject(key: string, objectClass: Object): void {
153       this._objects.set(key, objectClass);
154     }
155   }
156   ```
157
158   ```ts
159   // xxx.ets
160   import { webview } from '@kit.ArkWeb';
161   import { GlobalContext } from '../GlobalContext';
162
163   let url = 'file://' + GlobalContext.getContext().getObject("filesDir") + '/index.html';
164
165   @Entry
166   @Component
167   struct WebComponent {
168     controller: webview.WebviewController = new webview.WebviewController();
169
170     build() {
171       Column() {
172         // Load the files in the sandbox.
173         Web({ src: url, controller: this.controller })
174       }
175     }
176   }
177   ```
178
1792. Modify the **EntryAbility.ets** file.
180
181   The following uses **filesDir** as an example to describe how to obtain the path of the sandbox. For details about how to obtain other paths, see [Obtaining Application File Paths](../application-models/application-context-stage.md#obtaining-application-file-paths).
182
183   ```ts
184   // xxx.ets
185   import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
186   import { webview } from '@kit.ArkWeb';
187   import { GlobalContext } from '../GlobalContext';
188
189   export default class EntryAbility extends UIAbility {
190     onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
191       // Data synchronization between the UIAbility component and UI can be implemented by binding filesDir to the GlobalContext object.
192       GlobalContext.getContext().setObject("filesDir", this.context.filesDir);
193       console.log("Sandbox path is " + GlobalContext.getContext().getObject("filesDir"));
194     }
195   }
196   ```
197
198   HTML file to be loaded:
199
200   ```html
201   <!-- index.html -->
202   <!DOCTYPE html>
203   <html>
204       <body>
205           <p>Hello World</p>
206       </body>
207   </html>
208   ```
209
210
211## Loading HTML Rich Text Data
212
213The **Web** component provides the [loadData()](../reference/apis-arkweb/js-apis-webview.md#loaddata) API for you to load HTML rich text data. This API is applicable if you want to display some page sections instead of the entire page. To load a large number of HTML files, set **baseUrl** to data.
214
215```ts
216// xxx.ets
217import { webview } from '@kit.ArkWeb';
218import { BusinessError } from '@kit.BasicServicesKit';
219
220@Entry
221@Component
222struct WebComponent {
223  controller: webview.WebviewController = new webview.WebviewController();
224
225  build() {
226    Column() {
227      Button('loadData')
228        .onClick(() => {
229          try {
230            // Upon button clicking, call loadData to load HTML rich text data.
231            this.controller.loadData(
232              "<html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>",
233              "text/html",
234              "UTF-8"
235            );
236          } catch (error) {
237            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
238          }
239        })
240      // When creating a Web component, set the default network page to be loaded to www.example.com.
241      Web({ src: 'www.example.com', controller: this.controller })
242    }
243  }
244}
245```
246
247The **Web** component can load HTML strings using data urls.
248
249```ts
250// xxx.ets
251import { webview } from '@kit.ArkWeb';
252import { BusinessError } from '@kit.BasicServicesKit';
253
254@Entry
255@Component
256struct WebComponent {
257  controller: webview.WebviewController = new webview.WebviewController();
258  htmlStr: string = "data:text/html, <html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>";
259
260  build() {
261    Column() {
262      // When creating a Web component, set the default network page to be loaded to htmlStr.
263      Web({ src: this.htmlStr, controller: this.controller })
264    }
265  }
266}
267```
268
269## Dynamically Creating a Web Component
270**Web** components can be created with commands. Components created in this mode are not immediately mounted to the component tree, that is, they are not presented to users (their state is **Hidden** or **InActive**). You can dynamically mount the components as required in subsequent use. It is recommended that the number of **Web** instances started in the background be less than or equal to 200.
271
272```ts
273// Carrier ability
274// EntryAbility.ets
275import { createNWeb } from "../pages/common"
276onWindowStageCreate(windowStage: window.WindowStage): void {
277  windowStage.loadContent('pages/Index', (err, data) => {
278    // Dynamically create a Web component (UIContext needs to be passed in). The component can be created at any time after loadContent() is called.
279    createNWeb("https://www.example.com", windowStage.getMainWindowSync().getUIContext());
280    if (err.code) {
281      return;
282    }
283  });
284}
285```
286```ts
287// Create a NodeController instance.
288// common.ets
289import { UIContext, NodeController, BuilderNode, Size, FrameNode } from '@kit.ArkUI';
290import { webview } from '@kit.ArkWeb';
291
292// @Builder contains the specific content of the dynamically created component.
293// Data is an input parameter of encapsulation class.
294class Data{
295  url: string = "https://www.example.com";
296  controller: WebviewController = new webview.WebviewController();
297}
298
299@Builder
300function WebBuilder(data:Data) {
301  Column() {
302    Web({ src: data.url, controller: data.controller })
303      .width("100%")
304      .height("100%")
305  }
306}
307
308let wrap = wrapBuilder<Data[]>(WebBuilder);
309
310// NodeController is used to control and report the behavior of the node on the NodeContainer. This function must be used together with NodeContainer.
311export class myNodeController extends NodeController {
312  private rootnode: BuilderNode<Data[]> | null = null;
313  // This function must be overridden. It is used to build the number of nodes and return the number of nodes mounted to the corresponding NodeContainer.
314  // Call it when the NodeContainer is created or call rebuild() to refresh.
315  makeNode(uiContext: UIContext): FrameNode | null {
316    console.log(" uicontext is undefined : "+ (uiContext === undefined));
317    if (this.rootnode != null) {
318      // Return the FrameNode.
319      return this.rootnode.getFrameNode();
320    }
321    // Return null to detach the dynamic component from the bound node.
322    return null;
323  }
324  // Called when the layout size changes.
325  aboutToResize(size: Size) {
326    console.log("aboutToResize width : " + size.width  +  " height : " + size.height );
327  }
328
329  // Called when the NodeContainer bound to the controller is about to appear.
330  aboutToAppear() {
331    console.log("aboutToAppear");
332  }
333
334  // Called when the NodeContainer bound to the controller is about to disappear.
335  aboutToDisappear() {
336    console.log("aboutToDisappear");
337  }
338
339  // This function is a custom function and can be used as an initialization function.
340  // Initialize BuilderNode through UIContext, and then initialize the content in @Builder through the build API in BuilderNode.
341  initWeb(url:string, uiContext:UIContext, control:WebviewController) {
342    if(this.rootnode != null)
343    {
344      return;
345    }
346    // Create a node. UIContext is required.
347    this.rootnode = new BuilderNode(uiContext);
348    // Create a dynamic Web component.
349    this.rootnode.build(wrap, { url:url, controller:control });
350  }
351}
352// Create a map to save the required NodeController.
353let NodeMap:Map<string, myNodeController | undefined> = new Map();
354// Create a map to save the required WebViewController.
355let controllerMap:Map<string, WebviewController | undefined> = new Map();
356
357// UIContext is required for initialization and needs to be obtained from the ability.
358export const createNWeb = (url: string, uiContext: UIContext) => {
359  // Create a NodeController instance.
360  let baseNode = new myNodeController();
361  let controller = new webview.WebviewController() ;
362  // Initialize the custom Web component.
363  baseNode.initWeb(url, uiContext, controller);
364  controllerMap.set(url, controller)
365  NodeMap.set(url, baseNode);
366}
367// Customize the API for obtaining the NodeController.
368export const getNWeb = (url : string) : myNodeController | undefined => {
369  return NodeMap.get(url);
370}
371```
372```ts
373// Use the Page page of the NodeController.
374// Index.ets
375import { getNWeb } from "./common"
376@Entry
377@Component
378struct Index {
379  build() {
380    Row() {
381      Column() {
382        // NodeContainer is used to bind to the NodeController. A rebuild call triggers makeNode.
383        // The Page page is bound to the NodeController through the NodeContainer API to display the dynamic component.
384        NodeContainer(getNWeb("https://www.example.com"))
385          .height("90%")
386          .width("100%")
387      }
388      .width('100%')
389    }
390    .height('100%')
391  }
392}
393
394```
395**Common troubleshooting procedure**
3961. Check the network permission configuration of the application.
397
398   Check whether the network permission has been added to the **module.json5** file. For details, see [Declaring Permissions in the Configuration File](../security/AccessToken/declare-permissions.md).
399   ```ts
400   "requestPermissions":[
401       {
402         "name" : "ohos.permission.INTERNET"
403       }
404     ]
405   ```
4062. Check the logic for binding **NodeContainer** to nodes.
407
408   Check whether the node is added to the component tree. You are advised to add **Text** above the existing **Web** component (see the following example). If **Text** is not displayed when a white screen is displayed, check the binding between **NodeContainer** and the node.
409   ```ts
410   @Builder
411   function WebBuilder(data:Data) {
412     Column() {
413       Text('test')
414       Web({ src: data.url, controller: data.controller })
415         .width("100%")
416         .height("100%")
417     }
418   }
419   ```
4203. Check the visibility of the **Web** component.
421
422   If the entire node has been added to the tree, you can view the [WebPattern::OnVisibleAreaChange](../reference/apis-arkui/arkui-ts/ts-universal-component-visible-area-change-event.md#onvisibleareachange) log to check whether the **Web** component is visible. Invisible **Web** components may cause a white screen.
423## Samples
424
425The following samples are provided to help you better understand how to develop the **Web** component:
426
427- [Browser (ArkTS) (Full SDK) (API9)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-5.0.1-Release/code/BasicFeature/Web/Browser)
428