DEV Community

Cover image for Nested scrolling of Web components
liu yang
liu yang

Posted on

Nested scrolling of Web components

Nested Scrolling with Web Components in HarmonyOS Next

Typical Use Case for Nested Scrolling

Nested scrolling is a common scenario where multiple independent scrollable areas exist on a single page. When a user scrolls through content in one area, it can trigger scrolling in other areas to achieve a seamless up-and-down page scrolling experience.

Key Concepts

  • Nested Scroll Mode: This mode determines how the Web component interacts with its parent scrollable containers. It can be set to different modes such as SELF_ONLY, SELF_FIRST, PARENT_FIRST, and PARALLEL.
  • NestedScrollOptions: This object contains two properties, scrollForward and scrollBackward, each of which is an enumeration of NestedScrollMode.

Example Implementation

The following example demonstrates how to implement nested scrolling with Web components in a HarmonyOS Next application. This example includes buttons to dynamically change the nested scroll mode and displays multiple scrollable areas.

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

@Entry
@Component
struct NestedScroll {
  private scrollerForScroll: Scroller = new Scroller();
  controller: webview.WebviewController = new webview.WebviewController();
  controller2: webview.WebviewController = new webview.WebviewController();

  // NestedScrollMode settings
  @State NestedScrollMode0: NestedScrollMode = NestedScrollMode.SELF_ONLY;
  @State NestedScrollMode1: NestedScrollMode = NestedScrollMode.SELF_FIRST;
  @State NestedScrollMode2: NestedScrollMode = NestedScrollMode.PARENT_FIRST;
  @State NestedScrollMode3: NestedScrollMode = NestedScrollMode.PARALLEL;

  // Current scroll modes
  @State NestedScrollModeF: NestedScrollMode = NestedScrollMode.SELF_FIRST;
  @State NestedScrollModeB: NestedScrollMode = NestedScrollMode.SELF_FIRST;

  // Scroll direction
  @State ScrollDirection: ScrollDirection = ScrollDirection.Vertical;

  build() {
    Flex() {
      Scroll(this.scrollerForScroll) {
        Column({ space: 5 }) {
          Row({}) {
            Text('Scroll Mode Before').fontSize(5)
            Button('SELF_ONLY').onClick((event: ClickEvent) => {
              this.NestedScrollModeF = this.NestedScrollMode0;
            }).fontSize(5)
            Button('SELF_FIRST').onClick((event: ClickEvent) => {
              this.NestedScrollModeF = this.NestedScrollMode1;
            }).fontSize(5)
            Button('PARENT_FIRST').onClick((event: ClickEvent) => {
              this.NestedScrollModeF = this.NestedScrollMode2;
            }).fontSize(5)
            Button('PARALLEL').onClick((event: ClickEvent) => {
              this.NestedScrollModeF = this.NestedScrollMode3;
            }).fontSize(5)
          }

          Row({}) {
            Text('Scroll Mode After').fontSize(5)
            Button('SELF_ONLY').onClick((event: ClickEvent) => {
              this.NestedScrollModeB = this.NestedScrollMode0;
            }).fontSize(5)
            Button('SELF_FIRST').onClick((event: ClickEvent) => {
              this.NestedScrollModeB = this.NestedScrollMode1;
            }).fontSize(5)
            Button('PARENT_FIRST').onClick((event: ClickEvent) => {
              this.NestedScrollModeB = this.NestedScrollMode2;
            }).fontSize(5)
            Button('PARALLEL').onClick((event: ClickEvent) => {
              this.NestedScrollModeB = this.NestedScrollMode3;
            }).fontSize(5)
          }

          Text('Current Scroll Mode Before ---' + `${this.NestedScrollModeF}`).fontSize(10)
          Text('Current Scroll Mode After ---' + `${this.NestedScrollModeB}`).fontSize(10)

          Text("Scroll Area")
            .width("100%")
            .height("10%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)
          Text("Scroll Area")
            .width("100%")
            .height("10%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)
          Text("Scroll Area")
            .width("100%")
            .height("10%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)

          Web({ src: "https://www.example.com", controller: this.controller })
            .nestedScroll({
              scrollForward: this.NestedScrollModeF,
              scrollBackward: this.NestedScrollModeB,
            })
            .height("40%")
            .width("100%")

          Text("Scroll Area")
            .width("100%")
            .height("20%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)

          Text("Scroll Area")
            .width("100%")
            .height("20%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)

          Web({ src: "https://www.example.com", controller: this.controller2 })
            .nestedScroll({
              scrollForward: this.NestedScrollModeF,
              scrollBackward: this.NestedScrollModeB,
            })
            .height("40%")
            .width("90%")

          Text("Scroll Area")
            .width("100%")
            .height("20%")
            .backgroundColor(0X330000FF)
            .fontSize(16)
            .textAlign(TextAlign.Center)

        }.width("95%").border({ width: 5 })
      }
      .width("100%").height("120%").border({ width: 5 }).scrollable(this.ScrollDirection)
    }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20)
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • NestedScrollMode: This enumeration defines how the Web component should handle nested scrolling. Options include:
    • SELF_ONLY: The Web component scrolls independently without interacting with the parent.
    • SELF_FIRST: The Web component scrolls first, and if it reaches the edge, the parent container continues scrolling.
    • PARENT_FIRST: The parent container scrolls first, and if it reaches the edge, the Web component continues scrolling.
    • PARALLEL: Both the Web component and the parent container scroll simultaneously.
  • nestedScroll: This property is used to set the nested scroll behavior for the Web component. It takes a NestedScrollOptions object with scrollForward and scrollBackward properties.
  • Buttons: These allow the user to dynamically change the nested scroll mode during runtime.

Supported Containers and Input Events

  • Supported Containers: Grid, List, Scroll, Swiper, Tabs, WaterFlow.
  • Supported Input Events: Gestures, mouse, touchpad.

Top comments (0)