• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 页面级弹出框
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @liyi0309-->
5<!--Designer: @houguobiao-->
6<!--Tester: @lxl007-->
7<!--Adviser: @HelloCrease-->
8ArkUI的弹出框默认设置为全局级别,弹窗节点作为页面根节点的子节点,显示层级高于应用中的所有路由/导航页面。当页面内进行路由跳转时,如果应用未主动调用close方法关闭弹出框,弹出框不会自动关闭,并且会在下一个跳转页面上继续显示。
9
10从API version 15开始,如果开发者希望在路由跳转后,弹出框能够随前一个路由页面的切换而消失,并在路由返回后弹出框能够继续正常显示,可以通过页面级弹出框来实现。
11
12> **说明:**
13>
14> 当且仅当弹出框为非子窗模式时,页面级能力才会生效。即showInSubWindow参数不设置或设置为false。
15>
16> 页面级弹出框通常与导航路由能力结合使用,可以参考[组件导航和页面路由概述](arkts-navigation-introduction.md)了解相关术语。
17>
18> 页面级弹出框的使用方式是在当前弹出框的入参之中新增了相关属性能力,使用前可以通过[弹出框概述](arkts-base-dialog-overview.md)了解基础的弹出框使用方法。
19
20
21## 设置页面级弹出框参数
22
23> **说明:**
24>
25> 详细变量定义请参考[完整示例](#完整示例)。
26
27在弹出框的options入参中设置[levelMode](../reference/apis-arkui/js-apis-promptAction.md#levelmode15枚举说明)属性,值为LevelMode.EMBEDDED表示开启页面级弹出框能力。
28
29当弹出框弹出时,会自动获取当前显示的Page页面并将弹出框节点挂载在此页面下。此时弹出框的显示层级高于此Page页面下的所有Navigation页面。
30
31```ts
32this.getUIContext().getPromptAction().openCustomDialog({
33  builder: () => {
34    this.customDialogComponent();
35  },
36  levelMode: LevelMode.EMBEDDED, // 启用页面级弹出框
37})
38```
39
40## 弹出框在指定页面内弹出
41
42如果希望弹出框显示在某个指定页面内,需通过第二个参数levelUniqueId来实现。此参数接收页面内的节点id,设置后,弹出框显示时会自动查询此id对应的节点所在的Navigation页面,并将其挂载在此页面下。
43
44如下代码示例所示,Text节点为指定页面的节点,设置自定义id后,通过[getFrameNodeById](../reference/apis-arkui/arkts-apis-uicontext-uicontext.md#getframenodebyid12)方法获取该节点,再通过[getUniqueId](../reference/apis-arkui/js-apis-arkui-frameNode.md#getuniqueid12)获取节点的内部id,并将其作为levelUniqueId的值传入。
45
46```ts
47Text(this.message).id("test_text")
48  .onClick(() => {
49    const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
50    this.getUIContext().getPromptAction().openCustomDialog({
51      builder: () => {
52        this.customDialogComponent();
53      },
54      levelMode: LevelMode.EMBEDDED, // 启用页面级弹出框
55      levelUniqueId: node?.getUniqueId(), // 设置页面级弹出框所在页面的任意节点ID
56    })
57  })
58```
59
60## 设置页面级弹出框蒙层样式
61
62如果弹出框配置了蒙层,蒙层的遮盖范围会根据页面层级的变化进行调整,默认遮罩范围为弹出框父节点的显示区域(Page页面或者Navigation页面)。此时,状态栏和导航条不会被蒙层遮挡。若希望遮挡状态栏和导航条,可将[immersiveMode](../reference/apis-arkui/js-apis-promptAction.md#immersivemode15枚举说明)参数的值设为ImmersiveMode.EXTEND63
64```ts
65Text(this.message).id("test_text")
66  .onClick(() => {
67    const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
68    this.getUIContext().getPromptAction().openCustomDialog({
69      builder: () => {
70        this.customDialogComponent();
71      },
72      levelMode: LevelMode.EMBEDDED, // 启用页面级弹出框
73      levelUniqueId: node?.getUniqueId(), // 设置页面级弹出框所在页面的任意节点ID
74      immersiveMode: ImmersiveMode.EXTEND, // 设置页面级弹出框蒙层的显示模式
75    })
76  })
77```
78
79## 交互说明
80
81页面内弹出框在部分交互逻辑上依然遵循部分弹出框指定的交互策略:
82
831. 侧滑时先关闭弹出框。通过侧滑手势返回上一页时,如果页面上存在弹出框,弹出框会优先关闭并结束本次手势行为。如果期望返回上一页,需要再次触发侧滑手势。
84
852. 点击弹出框的蒙层,默认会关闭弹出框,点击蒙层以外的区域则不会。
86
87## 完整示例
88```ts
89// Index.ets
90import { LevelMode, ImmersiveMode } from '@kit.ArkUI';
91
92let customDialogId: number = 0;
93
94@Builder
95function customDialogBuilder(uiContext: UIContext) {
96  Column() {
97    Text('Custom dialog Message').fontSize(20).height(100)
98    Row() {
99      Button("Next").onClick(() => {
100        // 在弹窗内部进行路由跳转。
101        uiContext.getRouter().pushUrl({url: 'pages/Next'});
102      })
103      Blank().width(50)
104      Button("Close").onClick(() => {
105        uiContext.getPromptAction().closeCustomDialog(customDialogId);
106      })
107    }
108  }.padding(20)
109}
110
111@Entry
112@Component
113struct Index {
114  @State message: string = 'Hello World';
115  private uiContext: UIContext = this.getUIContext();
116
117  @Builder
118  customDialogComponent() {
119    customDialogBuilder(this.uiContext);
120  }
121
122  build() {
123    Row() {
124      Column() {
125        Text(this.message).id("test_text")
126          .fontSize(50)
127          .fontWeight(FontWeight.Bold)
128          .onClick(() => {
129            const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
130            this.uiContext.getPromptAction().openCustomDialog({
131              builder: () => {
132                this.customDialogComponent();
133              },
134              levelMode: LevelMode.EMBEDDED, // 启用页面级弹出框
135              levelUniqueId: node?.getUniqueId(), // 设置页面级弹出框所在页面的任意节点ID
136              immersiveMode: ImmersiveMode.EXTEND, // 设置页面级弹出框蒙层的显示模式
137            }).then((dialogId: number) => {
138              customDialogId = dialogId;
139            })
140          })
141      }
142      .width('100%')
143    }
144    .height('100%')
145  }
146}
147```
148```ts
149// Next.ets
150@Entry
151@Component
152struct Next {
153  @State message: string = 'Back';
154
155  build() {
156    Row() {
157      Column() {
158        Button(this.message)
159          .fontSize(20)
160          .fontWeight(FontWeight.Bold)
161          .onClick(() => {
162            this.getUIContext().getRouter().back();
163          })
164      }
165      .width('100%')
166    }
167    .height('100%')
168  }
169}
170```
171![embedded_dialog](figures/embedded_dialog.gif)