3.2 Hyperlink组件和Navigator组件 原创 精华

鸿蒙开发之南拳北腿
发布于 2022-5-24 21:06
浏览
3收藏

本节讲解ArkUI eTS中实现页面跳转的三个方案。包括:使用Hyperlink组件打开浏览器跳转到第三方网页、使用Navigator组件跳转到App内的其它页面和使用页面路由接口router。对于目前Hyperlink组件Beta版存在的问题,给出了使用建议。

3.2.1 Hyperlink组件

做B/S架构开发的同学,应该很熟悉超级链接组件“a”,通常,链接到另一个网页,写法如下:

<a href="http://www.baidu.com" title="百度" />

而在ArkUI eTS官方提供的组件中有一个和它对标的组件Hyperlink。该组件的接口写法为:

Hyperlink(address: string, content?: string)

其中接口参数"address"对标"href",可选参数content对标"title"。

示例代码如下:

      /**
       * 接口:Hyperlink(address: string, content?: string)
       *    address: string hyperlink组件跳转的网页。
       *    content: string hyperlink组件中超链接显示文本。
       */
      Hyperlink('https://ost.51cto.com/person/posts/15589203', '鸿蒙开发之南拳北腿') {
        Image($r("app.media.cover"))
          .width("100%")
          .aspectRatio(1.5)
          .borderRadius($r("app.float.radius_L"))
      }

本地预览器只能查看界面效果,无法跳转网页,所以建议在远程模拟器测试,效果如下:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

我们发现,接口参数“content”的文本“鸿蒙开发之南拳北腿”是没有显示的,点击图片后,打开浏览器,进入了参数“address”指向的网页。

在上述示范代码中,我放了一个子组件Image。但是,如果我再放入一个子组件呢?说干就干,我在Image组件后面放入一行代码:

Text('鸿蒙开发ArkUI最佳实践')

神奇的一幕发生了:在本地预览器和远程模拟器中发现,接口参数“content”的文本居然出现了!

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

让人不能接受的是,这个文本字号大小不可控制,文字颜色也不可控制,在深色模式下直接就看不到了。当然,目前Hyperlink组件还处于Beta版阶段,有点小瑕疵,也是可以理解的,希望华为的同学能在Release版时优化下这个问题。

“问题”还没有完。我们给新增加的Text组件加入一点样式,代码如下:

        Text('鸿蒙开发ArkUI最佳实践')
          .fontColor($r("app.color.fgLevel1"))
          .fontSize($r("app.float.fontSizeH8"))
          .fontWeight(Number($r("app.float.fontWeightH8")))

我们对比下浅色模式和深色模式下的效果:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

原本适配深色模式的文字,在深色模式下不再显示白色文字了!我猜,这与Hyperlink组件的color属性有关。

官方文档中对color属性的描述是: 当子组件中有文本和图片时,设置文本和图片的颜色。

可能即使未设置color属性,Hyperlink组件的color属性默认值也会作用于其子组件。那么,如何破局?代码修改如下:

      Hyperlink('https://ost.51cto.com/person/posts/15589203', '鸿蒙开发之南拳北腿') { // Hyperlink接口
        Image($r("app.media.cover"))
          .width("100%")
          .aspectRatio(1.5)
          .borderRadius($r("app.float.radius_L"))
        Text('鸿蒙开发ArkUI最佳实践')
          .fontSize($r("app.float.fontSizeH8"))
          .fontWeight(Number($r("app.float.fontWeightH8")))
      }.color($r("app.color.fgLevel1")) // 

效果如下:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

"app.color.fgLevel1"这个资源颜色在浅色模式下显示为黑色,在深色模式下显示为白色。现在文字显示合理了,但图片被影响了。

对于Hyperlink组件的使用,我的建议是:

不要设置接口参数“content”;

同时,在其容器中只放一个子组件,以免互相影响;

最后,文本链接的颜色,需要通过Hyperlink的color属性设置。

上述代码改造如下:

      /**
       * 接口:Hyperlink(address: string, content?: string)
       *    address: string hyperlink组件跳转的网页。
       *    content: string hyperlink组件中超链接显示文本。
       */
      Hyperlink('https://ost.51cto.com/person/posts/15589203') { // Hyperlink接口
        Image($r("app.media.cover"))
          .width("100%")
          .aspectRatio(1.5)
          .borderRadius($r("app.float.radius_L"))
      }

      /**
       * 属性:color:color 当子组件中有文本和图片时,设置文本和图片的颜色。
       */
      Hyperlink('https://ost.51cto.com/person/posts/15589203') {
        Text('鸿蒙开发ArkUI最佳实践')
          .fontSize($r("app.float.fontSizeH8"))
          .fontWeight(Number($r("app.float.fontWeightH8")))
          .decoration({ type: TextDecorationType.Underline })
      }.color($r("app.color.info")) // 属性:color

浅色模式和深色模式下的效果如下:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

本小节源码位于/pages/HyperlinkSample.ets。

3.2.2 Navigator组件

Navigator组件用于跳转到App内的其它页面。我们在“3.1.2 Span组件”这一小节的“1.建立页面导航”中初步使用该组件实现了首页和各个组件演示页之间互相跳转。接下来,我们正式学习这个组件的接口和属性。

新建一个NavigatorSample.ets页面,初始代码如下:

/**
 * 路由容器组件(Navigator):提供路由跳转能力,可以包含子组件。
 */
@Entry
@Component
struct NavigatorSample {
  build() {
    Column({space:8}) {
      // 返回首页
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/index', type: NavigationType.Back }) {
          Text('返回')
            .fontColor($r("app.color.fgLevel1"))
            .fontSize($r("app.float.fontSizeH8"))
            .fontWeight(Number($r("app.float.fontWeightH8")))
        }
      }

      /**
       * 接口:Navigator(value?: {target: string, type?: NavigationType})
       *    target:string 指定跳转目标页面的路径。
       *    type:NavigationType 默认值Push 指定路由方式。
       *        NavigationType.Push 跳转到应用内的指定页面。
       *        NavigationType.Replace 用应用内的某个页面替换当前页面,并销毁被替换的页面。
       *        NavigationType.Back 返回上一页面或指定的页面。
       */
      Navigator({ target: 'pages/HyperlinkSample', type: NavigationType.Replace }) {
        Text('用Hyperlink页面替换当前页面')
          .fontColor($r("app.color.info"))
          .fontSize($r("app.float.fontSizeH8"))
          .fontWeight(Number($r("app.float.fontWeightH8")))
          .decoration({ type: TextDecorationType.Underline, color: $r("app.color.info") })
      }

    }
    .width('100%').height('100%').backgroundColor($r("app.color.appBg")) // App背景颜色
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")}) // 屏幕边缘间隔
    .alignItems(HorizontalAlign.Start)
  }
}

在上面代码中,“返回”首页的Navigator组件,采用NavigationType.Back的类型。上一节教程中,从index.ets页面创建导航采用的是NavigationType.Push的类型。这里重点讲一下NavigationType.Replace的类型。

我们做三个简单的实验,然后得出一些结论:

实验一

在NavigatorSample.ets页面启动本地预览器。

注意,不要在本地预览器中先打开了index页面再跳转到NavigatorSample.ets页面,而是,在DevEco Studio中打开NavigatorSample.ets页面,然后启动本地预览器或刷新本地预览器,确保NavigatorSample.ets页面是本地预览器启动的第一个页面,否则实验会不够严谨。

如下左图。然后点击链接,跳转到HyperlinkSample.ets页面。HyperlinkSample.ets页面的返回链接代码如下:

      // 返回NavigatorSample页面
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/NavigatorSample', type: NavigationType.Back }) {
          Text('返回')
            .fontColor($r("app.color.fgLevel1"))
            .fontSize($r("app.float.fontSizeH8"))
            .fontWeight(Number($r("app.float.fontWeightH8")))
        }
        Blank()
      }.width('100%')

如下右图。然后点击左上角的“返回”,会发生什么?

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

答案是:什么也不会发生。因为上级页面NavigatorSample.ets通过NavigationType.Replace方式路由过来的时候,已经将自己“销毁”了。所以HyperlinkSample.ets页面不知道返回到哪里了,像一个可怜迷路的孩子。

实验二

将HyperlinkSample.ets页面的返回链接重新指向首页index.ets(修改Navigator组件的target值为’pages/index’),代码如下:

	  // 返回首页
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/index', type: NavigationType.Back }) {
          Text('返回')
            .fontColor($r("app.color.fgLevel1"))
            .fontSize($r("app.float.fontSizeH8"))
            .fontWeight(Number($r("app.float.fontWeightH8")))
        }
        Blank()
      }.width('100%')

从NavigatorSample.ets页面启动本地预览器,然后重新做上面的实验,结果也是进入HyperlinkSample.ets页面后点击返回,没反应。

实验三

然后,我们在index.ets页面启动本地预览器,点击首页中的"4.Navigator组件",使用NavigationType.Push的方式跳转到NavigatorSample.ets页面,然后点击“用Hyperlink页面替换当前页面”,使用NavigationType.Replace方式进入HyperlinkSample.ets页面,然后点击“返回”,会发生什么?

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

虽然NavigatorSample.ets页面已经销毁了,找不上了,但是“它爸还在”,返回了index.ets页面。

结论

1.如果通过NavigationType.Replace方式从A页面进入B页面,那么不要在B页面中通过NavigationType.Back的方式返回页面A(参考实验一)。当然,如果在页面B的Navigator组件中只写target指向页面A,不写可选参数type,那么可以进入页面A(但不是返回),此时,不是唤醒了页面A,而是重新启动了新的页面A。大家可以观察一下,通过有效的NavigationType.Back返回页面时,页面从手机等设备的左侧滑回屏幕中,如果是新进入一个页面,是从设备右侧滑入屏幕中。

2.使用NavigationType.Back的方式返回某页面时,该页面可以在后台,但不能是被销毁的或未启动过的,否则无法返回。实验二中通过NavigatorSample.ets页面启动预览器(index.ets页面并未启动),虽然target指向’pages/index’,但不满足NavigationType.Back的条件,也是无法返回的。

3.页面A通过NavigationType.Replace方式进入页面B有两个含义:A页面销毁,同时B取代A的位置。所以实验三中从index.ets页面PUSH到NavigatorSample.ets页面,然后通过Replace方式进入HyperlinkSample.ets页面,等价于从index.ets页面PUSH到HyperlinkSample.ets页面,所以从HyperlinkSample.ets页面返回首页是可以的。

Navigator组件的属性

接下来,讲解Navigator的两个属性 active 和 params 。

active:当前路由组件是否处于激活状态,处于激活状态时,会生效相应的路由操作。

官方示范代码:

// Navigator Page
@Entry
@Component
struct NavigatorExample {
  @State active: boolean = false
  @State Text: string = 'news'

  build() {
    // .....此处代码省略......

      Navigator() {
        Text('Back to previous page').width('100%').textAlign(TextAlign.Center)
      }.active(this.active)
      .onClick(() => {
        this.active = true
      })
    }.height(150).width(350).padding(35)
  }
}

根据我的测试,目前这个active属性不起作用。我使用如下代码,点击后仍然会回退到上一页:

      /**
       * 属性:
       * .active(boolean):当前路由组件是否处于激活状态,处于激活状态时,会生效相应的路由操作。
       */
      Navigator() {
        Text('Back to previous page').width('100%').textAlign(TextAlign.Center)
      }.active(false) // 疑似目前该属性没作用,等待release版的表现

params:跳转时要同时传递到目标页面的数据,可在目标页面使用router.getParams()获得。

示范代码如下:

      /**
       * 属性:
       * .params(Object):默认值undefined 跳转时要同时传递到目标页面的数据,可在目标页面使用router.getParams()获得。
       */
      Navigator({ target: 'pages/RouterSample', type: NavigationType.Push }) {
        Text('传递参数示范')
          .fontColor($r("app.color.info"))
          .fontSize($r("app.float.fontSizeH8"))
          .fontWeight(Number($r("app.float.fontWeightH8")))
          .decoration({ type: TextDecorationType.Underline, color: $r("app.color.info") })
      }
      .params({ info: '大王叫我来巡山' }) // 跳转时要同时传递到目标页面的数据

3.2.3 页面路由router

其它组件也可以通过页面路由router接口实现Navigator组件的能力。使用router接口前需要导入模块,代码如下:

import router from '@system.router'

目前该接口支持设备的情况如下表所示:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

可以发现router.push、router.replace和router.back可以和Navigator组件对标。本节仅演示router.push接口的使用和通过router接收上一个页面传递的参数:

(示范代码见RouterSample.ets)

// 导入模块
import router from '@system.router'

/**
 * 页面路由接口router
 */
@Entry
@Component
struct RouterSample {
  // 通过router接收上一个页面传递的参数
  @State info: string = router.getParams().info

  build() {
    Column({space:8}) {
      // 返回首页
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/NavigatorSample', type: NavigationType.Back }) {
          Text('返回')
            .fontColor($r("app.color.fgLevel1"))
            .fontSize($r("app.float.fontSizeH8"))
            .fontWeight(Number($r("app.float.fontWeightH8")))
        }
      }

      /**
       * 显示接收的参数,并演示router.push用法
       */
      Button(this.info) // 显示接收的参数
        .onClick(() => { // 常规组件通常通过onClick事件调用router接口实现页面路由
          router.push({ // 使用push模式
            uri: 'pages/NavigatorSample', // 转向的目标页面
            params: { // 同时传参
              data: '我想换你的紫金葫芦',
            },
          });
        })
    }
    .width('100%').height('100%').backgroundColor($r("app.color.appBg")) // App背景颜色
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")}) // 屏幕边缘间隔
    .alignItems(HorizontalAlign.Start)
  }
}

效果如下图所示:

3.2 Hyperlink组件和Navigator组件-鸿蒙开发者社区

其它router接口可参考ArkUI接口文档:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-basic-features-routes-0000000000611824

【源码地址:https://gitee.com/cloudev/harmonyos3/tree/master/3.0/BaseComponent

注意:由于Getee近日因政策改变,对原来开源的代码都做了需要重新审核的要求。如果大家访问源码时打不开,请过几天再试下。已提交审核。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
7
收藏 3
回复
举报
6条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

很实用的教程,学习了!

1
回复
2022-5-25 09:55:38
小威爱学习
小威爱学习

硬核我拳哥!

1
回复
2022-5-25 21:20:13
Edice
Edice

又新学到一个组件开发(偷笑)

回复
2022-5-26 15:16:07
wx6210f8f73042b
wx6210f8f73042b

很实用哦

 

回复
2022-5-27 10:24:04
物联风景
物联风景

这个好,收藏先

回复
2022-5-27 10:40:28
wx6245597465b5f
wx6245597465b5f

每天一个新组件

回复
2022-5-27 11:47:08
回复
    相关推荐