【HarmonyOS】鸿蒙系统在租房项目中的项目实战(一)

从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 "鸿蒙开发",对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是什么?鸿蒙仅仅是一个手机操作系统吗?它的出现能够和Android和IOS三分天下吗?它未来的潜力能否制霸整个手机市场呢?

今天实现一个简单的小案例,从零开始讲解如何通过鸿蒙开发实现一个租房平台的案例。

目录

初始化项目

搭建tabBar

轮播图搭建

主内容搭建


初始化项目

首先我们先打开DevEco Studio,点击新建项目:

然后根据自己的情况选择应用,这里我们选择空的 Empty Ability 进行创建:

创建完成点击结束之后,我们就可以在pages目录下的index.ets文件中编写代码,如下所示可以看到我们的项目已经成功运行了:

http封装:因为项目肯定是需要用到接口内容的,所以这里我们新建完项目之后需要封装一下请求方法方便后期调用,这里我们可以借助官方给我们提供的第三方仓库网站:地址 如下所示:

然后我们下载我们调用接口的第三方库,终端执行如下命令进行安装:

bash 复制代码
ohpm install @ohos/axios

然后我们在ets目录下新建utils工具文件夹,在该文件夹下新建http.ts文件对axios进行二次封装

javascript 复制代码
import axios from '@ohos/axios'
import { promptAction } from '@kit.ArkUI'

const http  = axios.create({
  baseURL: 'http://192.168.0.110:6060', // 请求地址
  timeout: 5000,
})

http.interceptors.request.use(
  (config) => {
    // 后期可以添加校验token内容
    return config
  },
  (error) => {
    promptAction.showToast(error.message) // 错误提示
    return Promise.reject(error)
  },
)

http.interceptors.response.use(
  (response) => {
    if (response.data.code === 200) {
      return response.data
    } else {
      promptAction.showToast(response.data.message) // 错误提示
      return Promise.reject(response.data.message)
    }
  },
  (error) => {
    promptAction.showToast(error.message) // 错误提示
    return Promise.reject(error)
  },
)
export default http

封装好接口之后,接下来我们需要配置下网络权限,方便后期我们使用真机模拟器的时候,网络服务是能够正常去请求的,如下所示:

在开发项目的时候,接口可能很多需要统一管理,我们直接在ets目录下去创建api文件夹去统一管理项目的接口:

javascript 复制代码
import http from "../../utils/http"
import type { HomeData } from './type'

// 统一管理接口
enum API {
  HOME_INFO = '/home/info',
}

// 获取首页数据
export const reqHomeData = () =>
  http.get<any, HomeData>(API.HOME_INFO)

搭建tabBar

接下来我们开始搭建我们的tabBar内容,这里我们使用官方文档提供的Tabs组件进行搭建,这里我们先创建五个ets文件代表五个要实现的五个tab界面,首先我们先准备好tab切换的图片资源,资源可以在阿里云图标库上进行寻找,这里不再赘述,找到对应的这种放置在b资源文件base下的media目录里面:

然后我们通过构建器创建一个tab函数,里面实现的是图片和文本,根据用户点击不同的tab然后进行样式的切换,代码如下:

javascript 复制代码
import Home from "./Home"
import See from "./See"
import Service from "./Service"
import Discover from "./Discover"
import My from "./My"

@Entry
@Component
struct Index {
  @State currentTabBarIndex: number = 0
  @Builder tabBarBuilder(image: Resource, activeImage: Resource, text: string, index: number) {
    Column() {
      Image(this.currentTabBarIndex === index ? activeImage : image).width(28).height(28 )
      Text(text).fontSize(10).fontColor(this.currentTabBarIndex === index ? '#000' : '#A0A0A0')
    }
  }
  build() {
    Tabs({ barPosition: BarPosition.End }) {
      TabContent() {
        Home()
      }.tabBar(this.tabBarBuilder($r('app.media.tabbar_home'), $r('app.media.tabbar_home_active'), '首页', 0))
      TabContent() {
        See()
      }.tabBar(this.tabBarBuilder($r('app.media.tabbar_see'), $r('app.media.tabbar_see_active'), '想看', 1))
      TabContent() {
        Service()
      }.tabBar(this.tabBarBuilder($r('app.media.tabbar_service'), $r('app.media.tabbar_service_active'), '服务', 2))
      TabContent() {
        Discover()
      }.tabBar(this.tabBarBuilder($r('app.media.tabbar_discover'), $r('app.media.tabbar_discover_active'), '发现', 3))
      TabContent() {
        My()
      }.tabBar(this.tabBarBuilder($r('app.media.tabbar_my'), $r('app.media.tabbar_my_active'), '我的', 4))
    }
    .barHeight(50).scrollable(false)
    .onChange((index: number) => {
      this.currentTabBarIndex = index
    })
  }
}

最终呈现的效果如下所示:

因为项目中可能许多地方会使用相同的变量,例如文字颜色或者大小等等,这里我们设置一下全局公共的样式内容,如下所示:

然后我们回到刚才我们设置tab的颜色的位置,设置成我们定义的全局公共样式:

当然我们也可以设置一下公共的常量内容,类似整个页面布局的边距,阴影圆角等等,这里我们直接在ets文件夹下新建一个资源目录,用于存放我们的定义的常量内容,方便后期用到:

轮播图搭建

首页的内容有很多,这里我们简单的讲每个模块用到的内容都讲解一下**,**在home页面,我们通过Scroll组件来排列模块内容,首先我们先实现轮播图组件,这里我们将轮播图组件抽离出去,然后通过props将接口当中的数据传递给组件:

javascript 复制代码
import { reqHomeData } from '../api/home'
import type { HomeData, bannerList } from '../api/home/type'
import SwiperLayout from '../components/Home/SwiperLayout'

@Component
export default struct Home {
  @State bannerList: bannerList[] = []
  // 获取首页数据
  getHomeData = async () => {
    const res: HomeData = await reqHomeData()
    this.bannerList = res.data.bannerList
  }
  
  // 初始化页面调用
  aboutToAppear(): void {
    this.getHomeData()
  }
  build() {
    Scroll() {
      Column() {
        // 轮播图组件使用props通信
        SwiperLayout({ bannerList: this.bannerList })
      }.width('100%')
    }.width('100%').height('100%')
    .scrollBar(BarState.Off)
    .align(Alignment.TopStart)
  }
}

在轮播图组件当中,我们调用轮播组件Swiper,通过ForEach循环渲染图片资源,然后轮播组件设置对应的轮播参数内容即可,代码如下所示:

javascript 复制代码
import type { bannerList } from '../../api/home/type'

@Component
export default struct SwiperLayout {
  @Prop bannerList: bannerList[];
  build() {
    Swiper() {
      ForEach(this.bannerList, (item: bannerList) => {
        Image(item.imageURL).width('100%').height('100%').objectFit(ImageFit.Fill)
      }, (banner: bannerList) => banner.id.toString())
    }
    .width('100%').height(211 -36) // 减去状态栏高度36
    .autoPlay(true).interval(3000)
    .indicator(
      new DotIndicator()
        .color($r('app.color.indicator_color'))
        .selectedColor($r('app.color.indicator_color_active'))
    )
  }
}

去除上下留白:因为新版本的鸿蒙预览器是有安全距离的,也就是说手机预览器上下会有一定的空间留白,如果想清除这些留白的话在index.ets根文件中调用如下函数即可:

javascript 复制代码
import { window } from '@kit.ArkUI';

onPageShow(): void {
  window.getLastWindow(AppStorage.get("context"), (err, data) => {
    if (err.code) {
      console.error('Failed to get last window. Cause:' + JSON.stringify(err));
      return;
    }
    data.setWindowLayoutFullScreen(true)
  });
}

最终呈现的效果如下所示:

主内容搭建

搜索栏搭建:内容很简单,我们借助层叠组件Stack在轮播图组件上搭建一个搜索栏组件,如下所示:

然后也是借助层叠组件,调整一下样式即可,然后把静态的搜索栏搭建出来:

javascript 复制代码
import { PADDING, PADDING_S } from '../../contants/size'

@Component
export default struct SearchBar {
  build() {
    Row({ space: PADDING }) {
      Text('北京').fontSize(14).fontColor($r('app.color.white'))
      Stack() {
        TextInput().width(244).height('100%').backgroundColor($r('app.color.white'))
        Row() {
          Image($r('app.media.search')).width(18).height(18)
          Text('公司/地铁/小区,马上搜索')
            .fontSize(10)
            .fontColor($r('app.color.gray'))
            .layoutWeight(1)
            .margin({ left: PADDING_S, right: PADDING_S })
          Column() {}.width(1).height(18).backgroundColor($r('app.color.line')).margin({ right: PADDING })
          Image($r('app.media.position')).width(18).height(18)
        }.width('100%').padding({ left: PADDING, right: PADDING })
      }.width(244)
      Image($r('app.media.message')).width(24).height(24).fillColor($r('app.color.white'))
    }
    .width('100%')
    .height(38)
    .padding({ left: PADDING, right: PADDING })
    .margin({ top: 4 })
  }
}

最终呈现的效果如下所示:

导航栏搭建:导航栏的内容这里我们就使用Grid布局进行处理,首先我们先定义导航栏组件然后在Home文件中进行引入,然后将首页的接口函数data中的数值赋值给navList,然后通过props的方式传递给导航栏组件,如下所示:

然后我们来到导航栏组件,通过Grid布局并调整相应的样式即可:

javascript 复制代码
import { navList } from '../../api/home/type'

@Component
export default struct NavList {
  @Prop navList: navList[]
  build() {
    Grid() {
      ForEach(this.navList, (item: navList) => {
        GridItem() {
          Column({ space: 8 }) {
            Image(item.imageURL).width(58).height(56).objectFit(ImageFit.Fill)
            Text(item.title).fontSize(12).fontColor($r('app.color.black'))
          }
        }
      }, (nav: navList) => nav.id.toString())
    }
    .width('100%')
    .height(170)
    .rowsTemplate('1fr 1fr')
    .columnsTemplate('1fr 1fr 1fr 1fr')
    .rowsGap(14)
    .columnsGap(32)
    .margin({ top: 24 })
  }
}

最终呈现的效果如下所示:

标题栏搭建:接下来开始对标题栏中的内容进行书写,老样子我们需要先定义标题栏组件,然后在Home文件中进行引入,并将首页数据data当中的titleList通过props通信传递给标题栏组件:

然后这里就很简单了,通过ForEach的方式进行渲染数据即可:

javascript 复制代码
import { tileList } from '../../api/home/type'

@Component
export default struct TitleList {
  @Prop titleList: tileList[]
  build() {
    Row({ space:32 }) {
      ForEach(this.titleList, (item: tileList) => {
        Column({ space: 8 }) {
          Image(item.imageURL).width('100%').height(58).objectFit(ImageFit.Fill)
          Row({ space: 5 }) {
            Text(item.title).fontSize(12).fontColor($r('app.color.black'))
            Text(item.sub_title).fontSize(10).fontColor($r('app.color.gray'))
          }.width('100%')
        }.width(148)
      }, (tit: tileList) => tit.id.toString())
    }
    .width('100%')
    .margin({ top: 12 })
  }
}

最终呈现的效果如下所示:

列表栏搭建:同理列表栏搭建的方式和上面一样,这里就直接给出代码了:

javascript 复制代码
import { planList } from '../../api/home/type'

@Component
export default struct PlanList {
  @Prop planList: planList[]
  build() {
    Row({ space: 5 }) {
      ForEach(this.planList, (item: planList) => {
        Image(item.imageURL).width(78).height(60).objectFit(ImageFit.Fill)
      }, (plan: planList) => plan.id.toString())
    }
    .width('100%')
    .margin({ top: 18 })
  }
}

效果如下所示:

下面的内容就放置一个广告图,代码很简单,这里就不再赘述了:

相关推荐
SuperHeroWu71 小时前
【HarmonyOS】鸿蒙应用接入微博分享
华为·harmonyos·鸿蒙·微博·微博分享·微博sdk集成·sdk集成
zhangjr05754 小时前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
努力的小雨6 小时前
零基础入门gRPC:从 0 实现一个Hello World
经验分享
有过~7 小时前
XviD4PSP视频无损转换器
经验分享·电脑
诗歌难吟46410 小时前
初识ArkUI
harmonyos
SameX11 小时前
HarmonyOS Next 设备安全特性深度剖析学习
harmonyos
催催1211 小时前
手机领夹麦克风哪个牌子好,哪种领夹麦性价比高,热门麦克风推荐
网络·人工智能·经验分享·其他·智能手机
郭梧悠12 小时前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos
郝晨妤1 天前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙
Peace*1 天前
HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案
harmonyos·鸿蒙·鸿蒙系统