写点什么

图片导航组件 | 纯血鸿蒙组件库 AUI

  • 2025-05-09
    广东
  • 本文字数:5993 字

    阅读完需:约 20 分钟

图片导航组件 | 纯血鸿蒙组件库AUI

一、组件调用方式

1.背景图模式调用方法:

首先输入 A_ImageNav,然后给 data 和 color 属性赋值,如下图所示:

在属性 data 中需要给按钮的文字(text)、背景图(src)、跳转页面的路由(router)、标题(title)和子标题(subTitle)赋值,如下图所示:

在本地模拟器上运行效果如下:

2.非背景图模式调用方法:

需要给导航数据 data 赋值,同时将 bgImageMode 设置为 false(非背景图模式)。根据需要,可以给导航标题(navTitle)和导航子标题(navSubTitle)赋值,如下图所示:

在属性 data 中仅需要给文本(text)、小图标的图片(src)、跳转页面的路由(router)赋值,如下图所示:

在本地模拟器上浅色模式和深色模式下,运行效果如下:


二、在线排版

点击“App 引导页”的“设计页面”按钮,进入页面设计器:

从组件库将“图片导航组件”拖拽到页面设计器排版区,如下图所示:

在右侧组件设置面板中,可以设置按钮的背景颜色。也可以根据图片的实际尺寸调整背景图的高度,修改后记得点击“保存设置”按钮。如下图所示:

点击“配置数据”按钮,为每个导航项绑定真实存在的页面作为路由跳转的目标,也可以根据自己的业务实际需要,修改按钮文字、背景图、标题和子标题。如下图所示:

侧栏菜单中,选择“纯血鸿蒙”,然后点击页面右上角的“代码魔法”图标,一秒生成生产级纯血鸿蒙项目工程,然后选择“引导页”(GuideView.ets),查看根据配置生成的鸿蒙代码。如下图所示:

现在我们继续进入页面设计器,将组件的模式改为“非背景图模式”,在组件设置面板中,将“背景图模式”属性设置为“否”,如下图所示:

可根据业务需要增加导航标题和导航子标题,如下图所示:

在“非背景图模式”下,配置数据中的标题和子标题不是必要的,可以清空,如下图所示:

再次生成鸿蒙代码:


三、源码解析

在“图片导航组件”当中有 6 个属性:

data 是一个数组(Array)类型的数据,它接受 ImageModel 的数据结构,包含图片地址、按钮、文字、大标题、子标题和页面跳转的路由,其中大标题和子标题仅在背景图模式时需要赋值,如下图所示:

ImageModel 源码如下:

/* * 图片导航Model * src:图片地址(支持"https://xxx"远程图片和media文件夹的本地图片) * text:文字 * title:标题 * subTitle:子标题 * router:路由 */
interface ImageModel { src: string text?: string title?: string subTitle?: string router?: string};
export { ImageModel };
复制代码

现在,我们继续分析图片导航组件 A_ImageNav 的源码。

首先以手机设备为标准初始化相关内部状态变量。@State 注解在这里无须了解,后续有课程系统讲解。这里只需要关心如下变量:compImageSize 是非背景图模式时小图标图片的尺寸,compImageMarginTop 和 compImageMarginBottom 是该图片的上下外边距,compWidth 和 compHeight 是该图片所在卡片容器的尺寸。这几个变量仅在非背景图模式时有作用。如下图所示:

aboutToAppear 函数在创建自定义组件的新实例后,在执行其 build()函数之前执行。 在 aboutToAppear 函数中,针对设备类型是折叠屏或者平板时的变量值做了适配,实现“一端开发,多端部署”(简称“一多”)的处理,同时,对于图片不是远程图片时做了本地资源的路径处理,如下图所示:

在背景图模式时,通过 ForEach 循环遍历轮播图数据,下面有一个列组件(Column),利用多个属性控制背景图的表现,其中 width 控制背景图宽度,手机设备时为 100%(常量值:GirdConstants.FULL_PERCENT),折叠屏和平板时宽度为设备屏幕宽度的 70%;height 属性控制背景图的高度,利用 backgroundImageHeight 赋值;背景图片(backgroundImage)支持远程图片或本地资源;borderRadius 控制圆角,padding 控制内间距,如下图所示:

展开列组件,用两个文本组件(Text)展示大标题和子标题,用按钮组件(Button)展示按钮,按钮的背景颜色由组件属性 color 决定,默认是 info(蓝色)。如下图所示:

按钮的点击事件(onClick)实现页面路由跳转,如下图所示:

现在,将背景图模式的相关代码折叠隐藏起来。非背景图模式的时候,使用中号标题组件(A_Title_M)展示导航标题的文本,使用大号子标题组件(A_SubTitle_L)展示导航子标题的文本,如下图所示:

在 List 组件中,使用 ForEach 遍历导航数据,每项数据通过列组件(Column)包裹起来,设置宽、高,圆角、背景颜色和点击后路由跳转的事件。如下图所示:

在列组件内部,有两个元素,第一个是图片(Image),第二个是文本(Text),用来显示卡片里面的图标式图片和文字,如下图所示:

图片导航组件的源码如下:

/* * Copyright (c) 2024 AIGCoder.com(AI极客) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/** 调用示例一: A_ImageNav({ data: [ { text: '立即体验', src: 'https://cdn.aigcoder.com/sample/ImageNav/pic1.jpeg', router: 'MainTabView', title: 'AI极客', subTitle: 'AIGC赋能程序开发,降本增效,快速生成前后端全技术栈代码。' }, { text: '设计App', src: 'https://cdn.aigcoder.com/sample/ImageNav/pic2.png', router: 'OrderDetail/2', title: '纯血鸿蒙', subTitle: '纯血鸿蒙开发神器,快速开发高质量鸿蒙应用。' } ], color: ColorConstants.DANGER })
调用示例二: A_ImageNav({ data: [ { text: 'AIGC', src: 'https://cdn.aigcoder.com/sample/ImageNav/pic3.png', router: 'MainTabView' }, { text: '纯血鸿蒙', src: 'https://cdn.aigcoder.com/sample/ImageNav/pic4.png', router: 'OrderList' } ], bgImageMode: false, navTitle: 'AIGC低代码平台', navSubTitle: 'AIGC,纯血鸿蒙', }) */
import { ColorConstants } from "../../constants/ColorConstants"import { FloatConstants } from "../../constants/FloatConstants"import { GirdConstants } from "../../constants/GirdConstants"import { ImageModel } from "../../models/ImageModel"import { A_Title_M } from "../text/A_Title_M"import { A_SubTitle_L } from "../text/A_SubTitle_L"
/** * 【图片导航】 * data:图片数据 * color:按钮颜色 * backgroundImageHeight:背景图高度 * bgImageMode:背景图模式(默认) * navTitle:导航标题(非背景图模式时可选) * navSubTitle:导航子标题(非背景图模式时可选) */@Componentexport struct A_ImageNav { @Prop data: Array<ImageModel> @Prop color?: ResourceStr @Prop backgroundImageHeight?: string = '200vp' @Prop bgImageMode?: boolean = true @Prop navTitle?: string = '' @Prop navSubTitle?: string = ''
@StorageLink('pageInfo') pageInfo: NavPathStack = new NavPathStack() @StorageLink('deviceType') deviceType: string = GirdConstants.DEVICE_SM
@State compImageSize: Length = '62vp' @State compImageMarginTop: Length = '28vp' @State compImageMarginBottom: Length = '12vp' @State compWidth: Length = '264vp' @State compHeight: Length = '148vp' @State compTextMarginTop: Length = '150vp' private compData: Array<ImageModel> = this.data
aboutToAppear(): void { this.compData.forEach(element => { switch (this.deviceType){ case GirdConstants.DEVICE_MD: case GirdConstants.DEVICE_LG: this.compImageMarginTop = '70vp' this.compImageMarginBottom = '24vp' this.compWidth = '168vp' this.compHeight = '248vp' break case GirdConstants.DEVICE_SM: default: break } if(!(element.src.startsWith("http://") || element.src.startsWith("https://"))){ element.src = 'app.media.' + element.src } }) }
build() { Column({space:GirdConstants.TWELVE}) { if(this.bgImageMode){ ForEach(this.compData, (item: ImageModel) => { Column() { Text(item.title) .fontSize(FloatConstants.FONT_SIZE_TITLE_M) .fontColor(ColorConstants.FG_LEVEL1_ALPHA) Text(item.subTitle) .fontSize(FloatConstants.FONT_SIZE_SUB_TITLE_L) .fontColor(ColorConstants.FG_LEVEL2_ALPHA) .margin({ top: FloatConstants.SPACE_S }) Blank() Column() { Button() { Text(item.text) .fontSize(FloatConstants.FONT_SIZE_BODY_L) .fontColor(ColorConstants.FG_LEVEL1_ALPHA) } .backgroundColor(this.color) .width(FloatConstants.BUTTON_WIDTH1) .height(FloatConstants.HEIGHT_BUTTON_L) .borderRadius(FloatConstants.RADIUS_BUTTON_L) .onClick(() => { if (item.router) { // 跳转到新页面 const router = item.router if (router.includes("/")) { this.pageInfo.pushPathByName(router.substring(0, router.indexOf("/")), router.substring(router.indexOf("/") + 1)) } else { this.pageInfo.pushPathByName(router, null) } } }) } .alignItems(HorizontalAlign.End) .width(GirdConstants.FULL_PERCENT) } .width(this.deviceType === GirdConstants.DEVICE_SM ? GirdConstants.FULL_PERCENT : GirdConstants.SEVENTY_PERCENT) .height(this.backgroundImageHeight) .margin({ top: FloatConstants.SPACE_L }) .backgroundImage((item.src.startsWith("http://") || item.src.startsWith("https://")) ? item.src : $r(item.src)) .backgroundImageSize({ width: GirdConstants.FULL_PERCENT, height: this.backgroundImageHeight }) .borderRadius(FloatConstants.RADIUS_XL) .padding(FloatConstants.PADDING_CARD) .alignItems(HorizontalAlign.Start) .justifyContent(FlexAlign.SpaceBetween) }, (item: ImageModel, index?: number) => index + JSON.stringify(item)) } else { A_Title_M({text:this.navTitle}) .margin({ top: this.deviceType === GirdConstants.DEVICE_SM ? GirdConstants.ZERO : this.compTextMarginTop })
A_SubTitle_L({text:this.navSubTitle})
List() { ForEach(this.compData, (item: ImageModel, index: number) => { ListItem() { Column({space:GirdConstants.TWELVE}) { Image((item.src.startsWith("http://") || item.src.startsWith("https://")) ? item.src : $r(item.src)) .width(this.compImageSize) .height(this.compImageSize) .borderRadius(FloatConstants.RADIUS_S) .margin({ top: this.compImageMarginTop, bottom: this.compImageMarginBottom })
Text(item.text) .fontColor(ColorConstants.FG_LEVEL3) .fontSize(FloatConstants.FONT_SIZE_BODY_L) .lineHeight(FloatConstants.SPACE_TEXT_LINE_L) .fontWeight(FontWeight.Medium) .margin({ bottom: this.compImageMarginTop }) } .width(this.compWidth) .height(this.compHeight) .borderRadius(FloatConstants.RADIUS_L) .backgroundColor(ColorConstants.CARD_BG) .onClick(() => { if (item.router) { // 跳转到新页面 const router = item.router if (router.includes("/")) { this.pageInfo.pushPathByName(router.substring(0, router.indexOf("/")), router.substring(router.indexOf("/") + 1)) } else { this.pageInfo.pushPathByName(router, null) } } }) } .width(this.deviceType === GirdConstants.DEVICE_SM ? GirdConstants.FULL_PERCENT : this.compWidth) .height(this.compHeight) .margin({ top: FloatConstants.SPACE_L, right: this.deviceType === GirdConstants.DEVICE_SM ? GirdConstants.ZERO : FloatConstants.PADDING_CARD }) }, (item: ImageModel) => JSON.stringify(item)) } .padding({ left: this.deviceType === GirdConstants.DEVICE_SM ? GirdConstants.ZERO : FloatConstants.PADDING_CARD }) .listDirection(this.deviceType === GirdConstants.DEVICE_SM ? Axis.Vertical : Axis.Horizontal) } } }}
复制代码


用户头像

还未添加个人签名 2025-04-29 加入

还未添加个人简介

评论

发布
暂无评论
图片导航组件 | 纯血鸿蒙组件库AUI_HarmonyOS_华哥的全栈次元舱_InfoQ写作社区