3.2 Hyperlink组件和Navigator组件 原创 精华
本节讲解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"))
}
本地预览器只能查看界面效果,无法跳转网页,所以建议在远程模拟器测试,效果如下:
我们发现,接口参数“content”的文本“鸿蒙开发之南拳北腿”是没有显示的,点击图片后,打开浏览器,进入了参数“address”指向的网页。
在上述示范代码中,我放了一个子组件Image。但是,如果我再放入一个子组件呢?说干就干,我在Image组件后面放入一行代码:
Text('鸿蒙开发ArkUI最佳实践')
神奇的一幕发生了:在本地预览器和远程模拟器中发现,接口参数“content”的文本居然出现了!
让人不能接受的是,这个文本字号大小不可控制,文字颜色也不可控制,在深色模式下直接就看不到了。当然,目前Hyperlink组件还处于Beta版阶段,有点小瑕疵,也是可以理解的,希望华为的同学能在Release版时优化下这个问题。
“问题”还没有完。我们给新增加的Text组件加入一点样式,代码如下:
Text('鸿蒙开发ArkUI最佳实践')
.fontColor($r("app.color.fgLevel1"))
.fontSize($r("app.float.fontSizeH8"))
.fontWeight(Number($r("app.float.fontWeightH8")))
我们对比下浅色模式和深色模式下的效果:
原本适配深色模式的文字,在深色模式下不再显示白色文字了!我猜,这与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")) //
效果如下:
"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
浅色模式和深色模式下的效果如下:
本小节源码位于/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%')
如下右图。然后点击左上角的“返回”,会发生什么?
答案是:什么也不会发生。因为上级页面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页面,然后点击“返回”,会发生什么?
虽然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'
目前该接口支持设备的情况如下表所示:
可以发现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)
}
}
效果如下图所示:
其它router接口可参考ArkUI接口文档:
【源码地址:https://gitee.com/cloudev/harmonyos3/tree/master/3.0/BaseComponent 】
注意:由于Getee近日因政策改变,对原来开源的代码都做了需要重新审核的要求。如果大家访问源码时打不开,请过几天再试下。已提交审核。
很实用的教程,学习了!
硬核我拳哥!
又新学到一个组件开发(偷笑)
很实用哦
这个好,收藏先
每天一个新组件