DEV Community

kouwei qing
kouwei qing

Posted on

Web Scrolling, Event Callback, selectable Attribute, Listening to H5 Internal Routing, Height Setting for Nested Grids

[Daily HarmonyOS Knowledge] Web Scrolling, Event Callback, selectable Attribute, Listening to H5 Internal Routing, Height Setting for Nested Grids

1. HarmonyOS WebView cannot scroll after loading a URL?

When nesting a WebView inside a Scroll component, refer to the following demo:

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

@Entry
@Component
struct WebComponent {
  controller: web_webview.WebviewController = new web_webview.WebviewController()
  @State mode: WebLayoutMode = WebLayoutMode.FIT_CONTENT

  build() {
    Column() {
      Text("Here is the header area")
        .width("100%")
        .height('30%')
        .backgroundColor("#f89f0f")
        .fontSize(28)
        .fontColor("#FF0F0F")
      Web({ src: $rawfile('Index.html'), controller: this.controller })
        .width('100%')
        .height(200)// .layoutMode(this.mode)
        .zoomAccess(false)
        .domStorageAccess(true)
        .overviewModeAccess(true)
        .imageAccess(true)
        .onlineImageAccess(true)
        .fileAccess(true)
        .databaseAccess(true)
      Text("Here is the footer area")
        .fontSize(28)
        .fontColor("#FF0F0F")
        .width("100%")
        .height('40%')
        .backgroundColor("#f89f0f")
    }
    .width('100%')
    .height('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

2. HarmonyOS event callback?

There are two pages, A and B. Page A navigates to page B using the router.pushUrl method. Page B has a button btn. How to notify page A when btn is clicked, without page B ever navigating back.

Implement this using custom subscription events. Refer to the demo:

//index.ets
import display from '@ohos.display';
import emitter from '@ohos.events.emitter';
import { router } from '@kit.ArkUI';
import { JSON } from '@kit.ArkTS';

@Entry
@Component
struct DisplayTest {

  build() {
    Column({space:20}){
      Button('Test')
        .type(ButtonType.Capsule)
        .onClick(() => {
          let innerEvent: emitter.InnerEvent = {
            eventId: 12222
          };
          // Trigger the event with ID 12222
          emitter.on(innerEvent, (data) => {
            console.info('once callback' + JSON.stringify(data));
          });
          router.pushUrl({
            url:'pages/PageOne'
          })
        })
        .width('50%')
    }
    .width("100%")
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

//PageOne.ets
import emitter from '@ohos.events.emitter';

@Entry
@Component
struct PageOne {



  build() {
    Column(){
      Text('PageOne')
        .width('50%')
      Button('send')
        .type(ButtonType.Capsule)
        .width('50%')
        .onClick(() => {
          let eventData: emitter.EventData = {
            data: {
              "content": "c",
              "id": 1,
            }
          };

          let innerEvent: emitter.InnerEvent = {
            eventId: 12222,
            priority: emitter.EventPriority.HIGH
          };
          // Emit the event with ID 12222
          emitter.emit(innerEvent, eventData);
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

3. What is the selectable attribute in HarmonyOS ListItem for?

The selectable attribute of ListItem determines whether the current ListItem element can be selected by a mouse frame. This attribute cannot be used to implement multi-selection. Developers can maintain multi-selection states by setting attributeModifier with dynamic attributes.

Reference document: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-attribute-modifier-V5

Dynamically set component attributes, supporting if/else syntax and polymorphic style settings as needed.

4. How to listen to h5 internal routing jumps in a HarmonyOS web component?

Need to intercept h5 routing jumps inside the web component to process parameters. Are there methods to intercept this?

  1. Use to intercept URLs and return response data: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5
  2. Use to determine whether to block the access: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5#onloadintercept10

5. When nesting a Grid component inside a HarmonyOS Scroll, must the Grid set a height?

When nesting a Grid component inside a Scroll, does the Grid must set a height?

When the width and height of the Grid are not set, it adapts to the parent component's size by default. Set the width and height of the Grid's parent component (Column), such as .width("100%") .height("100%"), and it can be displayed normally.

Reference demo:

@Entry
@Component
export struct AllChannelsPage{

  @State tabs: Array<String> = new Array();

  @State dragChannel: string = 'drag';

  private deviceWidth: number = (AppStorage.get('deviceWidth') as number)
  @State itemWidth: number = 80;
  @State itemHeight: number = 80;
  @State mineRowCount: number = 1;
  @State mineGridHeight: number = 100;
  @State mainTitieDes: string = 'Click to enter the channel';

  aboutToAppear(): void {
    for(let i = 0; i < 30; i++ ){
      this.tabs.push('Channel' + i);
    }
    this.itemWidth = (this.deviceWidth - 32 - 30)/4;
    this.itemHeight = this.itemWidth / 2.1;
    this.mineRowCount = Math.ceil(this.tabs.length / 4);
    this.mineGridHeight = this.mineRowCount * this.itemHeight + (this.mineRowCount - 1) * 10
  }

  @Builder pixelMapBuilder() { // Drag process style
    Column() {
      Text(this.dragChannel)
        .fontSize('15fp')
          // .fontColor($r('app.color.color202022'))
        .textAlign(TextAlign.Center)
        .width(this.itemWidth)
        .height(this.itemHeight)
          // .backgroundColor($r('app.color.colorF9F9F9'))
        .borderRadius(4)
    }
  }

  changeIndex(index1: number, index2: number) { // Swap array positions
    let temp = this.tabs[index1];
    this.tabs[index1] = this.tabs[index2];
    this.tabs[index2] = temp;
  }

  build() {
    NavDestination(){
      Column(){
        Scroll(){
          Column(){
            Row(){
              Text().width(4).height(16)
                // .backgroundColor($r('app.color.colorF21333'))
                .borderRadius(2)
              Blank().width(6)
              Text('My Channels').fontSize('16fp')
              // .fontColor($r('app.color.color202022'))
              Blank().width(8)
              Text(this.mainTitieDes).fontSize('12fp')
              // .fontColor($r('app.color.colorB1B1BB'))
              Blank().layoutWeight(1)
              Text('Reset').fontSize('15fp')
              // .fontColor($r('app.color.color909099'))
              Text().width(1).height(10)
                // .backgroundColor($r('app.color.color909099'))
                .margin({left: 4, right: 4})
              Text('Edit').fontSize('15fp')
              // .fontColor($r('app.color.colorF21333'))
            }.width('100%')
            .margin({top: 5, bottom: 15})
            .padding({ left: 16, right: 16 })

            Grid() {
              ForEach(this.tabs, (channel: string) => {
                GridItem() {
                  Text(channel)
                    .fontSize((channel?? '').length > 5 ? '11fp': '15fp')
                      // .fontColor($r('app.color.color202022'))
                    .textAlign(TextAlign.Center)
                      // .width(this.itemWidth)
                      // .height(this.itemHeight)
                    .width('100%')
                    .height(80)
                      // .backgroundColor($r('app.color.colorF9F9F9'))
                    .borderRadius(4)
                  // .onTouch((event: TouchEvent) => {
                  //   if (event.type === TouchType.Up) {
                  //     this.dragChannel = channel.channelName ?? '';
                  //   }
                  // })
                }
              })
            }
            .columnsTemplate('1fr 1fr 1fr 1fr')
            .columnsGap(10)
            .rowsGap(10)
            .onScrollIndex((first: number) => {
              console.info(first.toString());
            })
            // .width('100%')
            // .height('80%')
            .padding({ left: 16, right: 16 })
            .supportAnimation(true)
            .editMode(true) // Set whether the Grid enters edit mode, allowing dragging of GridItems inside the Grid
            .onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // Triggered when dragging this component for the first time
              return this.pixelMapBuilder(); // Set the image displayed during dragging
            })
            .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => { // Triggered when stopping dragging within this component
              console.info('tag' + itemIndex + '', insertIndex + '') // itemIndex: drag start position, insertIndex: drag insertion position
              this.changeIndex(itemIndex, insertIndex)
            })
            .nestedScroll({
              scrollForward: NestedScrollMode.PARENT_FIRST,
              scrollBackward: NestedScrollMode.SELF_FIRST
            })

            Text().width('100%').height(500)
          }
          .width("100%")
          .height("100%")
        }
        .width('100%')
        .layoutWeight(1)

      }

    }.hideTitleBar(true)
  }

}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)