希望在网络加载的时候页面整体加一个遮罩层

每个页面添加一个遮罩层,计划使用zindex实现,页面数量10+,每个页面使用原生开发,布局都不一样;

(1)zindex是否能解决问题

(2)如果使用zindex的话,如何才能提取公共逻辑,让遮罩层的代码统一维护,只写一次。这里可能涉及@state控制,还有ArkUI公共代码的抽取。

因为每个页面的最外层容器不一样,有的是stack(), 有的是column(),因此无法用外层容器统一。

HarmonyOS
2024-09-29 13:17:45
浏览
收藏 0
回答 2
待解决
回答 2
按赞同
/
按时间
鱼弦CTO
1

要在每个页面添加一个遮罩层,并且使用 ​​zIndex​​ 来实现,同时保证代码的统一维护和复用,这是可以通过创建一个高阶组件(HOC)或者自定义 Hook 的方式来解决的。下面是对你的问题的详细解答和实现方案。

### 方案分析

#### (1) ​​zIndex​​ 是否能解决问题

​zIndex​​ 可以用于控制元素在页面上的层级关系,所以它能够解决在网络加载时显示遮罩层的问题。通过将遮罩层的 ​​zIndex​​ 设置为比其他内容更高,可以确保它覆盖在所有内容之上。

#### (2) 如何提取公共逻辑,统一维护遮罩层代码

为了避免在每个页面重复编写遮罩层相关的代码,可以使用高阶组件(HOC)或者自定义 Hook 将遮罩层的逻辑提取到一个公共模块中。这样,只需在每个页面调用这个公共模块即可。

### 具体实现

#### 1. 创建一个 LoadingOverlay 组件

首先,我们创建一个通用的 ​​LoadingOverlay​​ 组件,用于显示遮罩层。

import { View, Text } from '@arkui/components';

function LoadingOverlay() {
  return (
    <View style={{
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      backgroundColor: 'rgba(0,0,0,0.5)',
      zIndex: 1000,
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <Text style={{ color: '#FFF' }}>Loading...</Text>
    </View>
  );
}

export default LoadingOverlay;

#### 2. 创建一个高阶组件(HOC)

创建一个高阶组件,将遮罩层逻辑封装起来。

import { useState } from '@arkui/hooks';
import LoadingOverlay from './LoadingOverlay';

function withLoadingOverlay(WrappedComponent: any) {
  return function ComponentWithLoading(props: any) {
    const [isLoading, setIsLoading] = useState(false);

    const showLoading = () => setIsLoading(true);
    const hideLoading = () => setIsLoading(false);

    return (
      <>
        <WrappedComponent {...props} showLoading={showLoading} hideLoading={hideLoading} />
        {isLoading && <LoadingOverlay />}
      </>
    );
  };
}

export default withLoadingOverlay;

#### 3. 使用 HOC 在各个页面中

在各个页面组件中使用高阶组件来包裹原有的组件。

import { Stack, Button, Text } from '@arkui/components';
import withLoadingOverlay from './withLoadingOverlay';
import { useEffect } from '@arkui/hooks';

function Page1({ showLoading, hideLoading }: any) {
  useEffect(() => {
    // 模拟网络请求
    showLoading();
    setTimeout(() => {
      hideLoading();
    }, 3000);
  }, []);

  return (
    <Stack style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Page 1 Content</Text>
      <Button onClick={showLoading}>Show Loading</Button>
    </Stack>
  );
}

export default withLoadingOverlay(Page1);

你可以在其他页面中以同样的方式使用 ​​withLoadingOverlay​​ 高阶组件。

### 解释

  1. LoadingOverlay​ 组件: 定义了一个遮罩层组件,包含一些简单的样式和 "Loading..." 文本。
  2. 高阶组件 withLoadingOverlay​:
  • 它接受一个组件作为参数,并返回一个新组件。
  • 在新组件内部,使用​​useState​​ 管理​​isLoading​​ 状态,并提供​​showLoading​​ 和​​hideLoading​​ 方法来控制遮罩层的显示和隐藏。
  • 渲染传入的组件并传递​​showLoading​​ 和​​hideLoading​​ 方法。
  1. 页面组件 Page1​:
  • 使用​​withLoadingOverlay​​ 包裹原来的页面组件,使其具有显示和隐藏遮罩层的能力。
  • 使用​​useEffect​​ 模拟网络请求,在组件挂载时显示遮罩层,延迟3秒后隐藏遮罩层。

通过这种方式,你只需在每个页面中调用高阶组件,即可轻松实现遮罩层的统一管理和复用。如果有任何进一步的问题或需求,请随时提问!

分享
微博
QQ
微信
回复
2024-09-29 14:05:31
superinsect

可以使用自定义弹窗实现网络加载时页面遮罩,参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-methods-custom-dialog-box-V5

也可使用overlay,overlay可以增加遮罩文本或者作为叠加自定义组件的浮层,参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-overlay-V5

具体demo:

@CustomDialog  
struct CustomDialogExample {  
  controller: CustomDialogController = new CustomDialogController({  
    builder: CustomDialogExample({}),  
  })  
  
  build() {  
    Column() {  
      Image($r('app.media.icon'))  
        .width(80)  
        .height(80)  
    }  
  }  
}  
@Entry  
@Component  
struct OverlayExample {  
  private isShowLoading:Boolean = true;  
  dialogController: CustomDialogController = new CustomDialogController({  
    builder: CustomDialogExample(),  
  })  
  
  aboutToAppear(){  
    this.dialogController.open()  
    setTimeout(()=>{  
      this.dialogController.close()  
    },2000)  
  }  
  @Builder OverlayNode() {  
    Column() {  
      Column()  
        .height('100%')  
        .width('100%')  
        .backgroundColor('rgba(255,255,255,0.8)')  
    }.alignItems(HorizontalAlign.Center)  
  }  
  
  build() {  
    Column() {  
      Column() {  
        Button('OK', { type: ButtonType.Normal, stateEffect: true })  
          .borderRadius(8)  
          .backgroundColor(0x317aff)  
          .width(90)  
          .onClick(() => {  
            console.log('ButtonType.Normal')  
          })  
      }  
      .height(100)  
      .width('100%')  
      .backgroundColor('#000000')  
      .overlay(this.OverlayNode(), { align: Alignment.Center })  
    }.width('100%')  
  }  
}

还可使用canvas绘制图形的方式绘制遮罩层,具体demo如下:

import { window } from '@kit.ArkUI';  
@Entry  
@Component  
struct GlobalAlpha {  
  private settings: RenderingContextSettings = new RenderingContextSettings(true)  
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)  
  @State windowWidth: number = 0  
  @State windowHeight: number = 0  
  onPageShow(): void {  
    window.getLastWindow(getContext(this)).then((windowClass) => {  
      let rect: window.Rect = windowClass.getWindowProperties().windowRect;  
      // 导航条高度  
      let avoidArea1 = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);  
      let bottomHeight = avoidArea1.bottomRect.height;  
      // 状态栏高度  
      let avoidArea2 = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);  
      let statusHeight = avoidArea2.topRect.height;  
      this.windowHeight = px2vp(rect.height - bottomHeight - statusHeight);  
      this.windowWidth = px2vp(rect.width);  
    });  
  }  
  build() {  
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {  
      Canvas(this.context)  
        .width('100%')  
        .height('100%')  
        .backgroundColor('#2e7fd6')  
        .onReady(() =>{  
          this.context.fillText(String(this.windowHeight), 100, 60)  
          this.context.globalAlpha = 0.4  
          this.context.fillStyle = 'rgb(62, 64, 65)'  
          this.context.fillRect(0, 0, this.windowWidth, this.windowHeight)  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}
分享
微博
QQ
微信
回复
2024-09-29 15:53:34
相关问题
HarmonyOS 如何实现一个遮罩
442浏览 • 1回复 待解决
如何加载一个网页链接到页面中?
380浏览 • 1回复 待解决
如何实现一个监听网络变化方法
614浏览 • 1回复 待解决