当前位置: 首页 > news >正文

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

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

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

目录

房源推荐搭建

封装滚动组件

状态功能适配

想看模块搭建


房源推荐搭建

接下来我们开始编写房源推荐的相关内容,首先我们先把接口写好,这里我们先根据后端返回的接口类型的数据将接口类型编写一遍:

// 公共类型
interface BaseResponse {code: number;message: string;
}
interface BaseID { id: number }
interface BaseName { name: string }
interface BaseTitle { title: string }
interface BaseSubTitle { sub_title: string }
interface BaseImageURL { imageURL: string }// 房源推荐数据
interface BaseRecommendData extends BaseResponse {data: RecommendData[]
}
interface RecommendData extends BaseID {housePicture: stringtags: BaseName[]houseTitle: stringaddress: stringrentPriceUnit: stringrentPriceListing: stringrentArea: string
}export {BaseRecommendData,RecommendData
}

然后我们根据后端的路径开始编写接口函数,将上面的类型赋值的接口的返回值当中:

import http from "../../utils/http"
import type { HomeData, BaseRecommendData } from './type'// 统一管理接口
enum API {HOME_INFO = '/home/info',ROOM_RECOMMEND = '/house/nearbyHouses'
}// 获取首页数据
export const reqHomeData = () =>http.get<any, HomeData>(API.HOME_INFO)// 获取房源推荐数据
export const reqRecommendData = () =>http.get<any, BaseRecommendData>(API.ROOM_RECOMMEND)

因为房源组件的数据仅仅是该组件要使用而已,所以我们的接口数据就只需要在该组件进行调用即可,代码如下所示:

@State roomRecommentList: RecommendData[] = []
// 获取房源数据
getRoomRecommendData = async () => {const res: BaseRecommendData = await reqRecommendData()this.roomRecommentList = res.data
}aboutToAppear(): void {this.getRoomRecommendData()
}

后面就是借助Grid布局调整调整样式即可,最终呈现的效果如下所示:

封装滚动组件

接下来我们开始封装滚动组件,因为搜索栏的组件可能多个页面都会用到,并且会随着页面的滚动的时候出现在顶部并渐变显示,这里我们也是需要对其颜色样式进行一个动态的渲染,这里我们都将其放置在公共组件当中去,这里也是用到了插槽的内容,具体如下:

如下代码我们封装了一个插槽,一个是用于放置滚动的主体内容,另一个是放置搜索栏:

interface IColor {bgColor: stringfontColor: string
}@Component
export default struct ScrollContainer {@Builder customBuilder() {}@BuilderParam navBuilderParam: ($$: IColor) => void = this.customBuilder@BuilderParam contentBuilderParam: () => void = this.customBuilder@State scrollY: number = 0 // 存储滚动条位置(y轴滚动距离)@State bgColor: string = 'rgba(0, 0, 0, 0)' // 背景颜色@State fontColor: string = 'rgba(255, 255, 255, 1)' // 字体颜色// 处理滚动事件handleScroll = (xOffset: number, yOffset: number) => {this.scrollY += yOffset // 存储滚动条位置(y轴滚动距离)this.calcColor() // 监听文字颜色变化范围}// 监听文字颜色变化范围calcColor = () => {if (this.scrollY < 10) {// 到达顶部,渐变开始this.bgColor = 'rgba(255, 255, 255, 0)'this.fontColor = 'rgba(255, 255, 255, 1)'} else if (this.scrollY <= 100) {// 渐变中(透明度 0 -> 1)const  colorOpacity = (this.scrollY - 10) / (100 - 10)this.bgColor = `rgba(255, 255, 255, ${colorOpacity})`this.fontColor = `rgba(0, 0, 0, ${colorOpacity})`} else {// 渐变结束this.bgColor = 'rgba(255, 255, 255, 1)'this.fontColor = 'rgba(0, 0, 0, 1)'}}build() {Stack() {Scroll() {Column() {this.contentBuilderParam()}.width('100%')}.width('100%').height('100%').scrollBar(BarState.Off).align(Alignment.TopStart).onDidScroll(this.handleScroll)// 搜索栏组件, 按引用传递this.navBuilderParam({ bgColor: this.bgColor, fontColor: this.fontColor })}.width('100%').alignContent(Alignment.TopStart)}
}

接下来我们需要对首页的内容进行改造一下,将原本的代码直接删掉,采用插槽的方式进行书写,因为使用@Builder会导致this指向的问题,所以我们在调用的时候,包一层箭头函数即可:

import { reqHomeData } from '../api/home'
import type { HomeData, bannerList, navList, tileList, planList } from '../api/home/type'
import { PADDING, SHADOW_RADIUS } from '../contants/size'
import SwiperLayout from '../components/Home/SwiperLayout'
import SearchBar from '../components/Home/SearchBar'
import NavList from '../components/Home/NavList'
import TitleList from  '../components/Home/TitleList'
import PlanList from '../components/Home/PlanList'
import RoomRecommend from '../components/Home/RoomRecommend'
import ScrollContainer from '../components/Container/ScrollContainer'interface IColor {bgColor: stringfontColor: string
}@Component
export default struct Home {@State bannerList: bannerList[] = []@State navList: navList[] = []@State titleList: tileList[] = []@State planList: planList[] = []@State adPicture: string = ''// 获取首页数据getHomeData = async () => {const res: HomeData = await reqHomeData()this.bannerList = res.data.bannerListthis.navList = res.data.navListthis.titleList = res.data.tileListthis.planList = res.data.planListthis.adPicture = res.data.adPicture}// 初始化页面调用aboutToAppear(): void {this.getHomeData()}@BuildernavBuilder($$: IColor) {// 搜索栏组件SearchBar({ bgColor: $$.bgColor, fontColor: $$.fontColor })}@BuildercontentBuilder() {SwiperLayout({ bannerList: this.bannerList }) // 轮播图组件使用props通信Column() {NavList({ navList: this.navList }) // 导航栏组件使用props通信TitleList({ titleList: this.titleList }) // 标题栏组件使用props通信PlanList({ planList: this.planList }) // 列表组件Image(this.adPicture) // 广告图.width('100%').height(60).objectFit(ImageFit.Fill).margin({ top: 10 }).shadow({ offsetX: 0, offsetY: 0, radius: SHADOW_RADIUS, color: 'rgba(0, 0, 0, 0.14)' })}.width('100%').padding({ left: PADDING, right: PADDING })RoomRecommend() // 推荐房源组件}build() {ScrollContainer({navBuilderParam: this.navBuilder,contentBuilderParam: () => {// 使用Builder函数,需要使用箭头函数指向this实例this.contentBuilder()},})}
}

最终呈现的效果如下所示,依然实现了原本的效果:

状态功能适配

        因为我们上面都是按照UI设计稿来设置的宽高度,也就是说我们把样式给写死了,当用户用其他不同的比例的显示器去查看我们设计的页面的时候,就会出现适配问题,为此我们需要对一些功能的状态适配问题进行相应的处理。

我们来到进入应用窗口的函数当中进行编写,将获取到的相关状态高度颜色等进行持久化存储:

然后我们可以在滚动容器当中拿到对应的对象:

windowStyle?: window.WindowgetWindowStyle = async  () => {this.windowStyle = await window.getLastWindow(getContext(this))
}

在设定颜色的内容处根据滚动距离设置不同的颜色内容:

然后我们可以根据适配器的内容设置一下适配函数,在所有的定义宽高距离的内容当中调用一下该函数进行适配:

/** 计算元素真正的大小:元素在设计稿的大小 / 设计稿总宽度 = x / 真机宽度(保证元素在不同设备占比相同)x = 元素在设计稿的大小 / 设计稿总宽度 * 真机宽度* */const DRAFT_WIDTH = 360
// 预览器获取不到宽度,给预览器默认值360
const windowWidth = AppStorage.get('windowWidth') as number || 360
const rvp = (val: number) => {return val / DRAFT_WIDTH * windowWidth
}export default rvp

然后我们给设置的每一个距离的内容都调用该函数即可:

想看模块搭建

接下来我们开始搭建想看的模块内容,首先我们先处理一下导航栏的样式内容,如下所示:

import { PADDING } from "../../contants/size"
import rvp from "../../utils/responsive"@Component
export default struct NavBar {@StorageProp('topHeight') topHeight: number = 0build() {Row() {Row({ space: rvp(6) }) {Image($r('app.media.bag')).width(rvp(16)).height(rvp(16))Text('请写通勤地址').fontSize(rvp(12)).fontColor($r('app.color.black'))}Row({ space: rvp(28) }) {Column({ space: rvp(1) }) {Image($r('app.media.message')).width(rvp(20)).height(rvp(20)).fillColor($r('app.color.black'))Text('消息').fontSize(rvp(10)).fontColor($r('app.color.black'))}Column({ space: rvp(1) }) {Image($r('app.media.journey')).width(rvp(20)).height(rvp(20))Text('行程').fontSize(rvp(10)).fontColor($r('app.color.black'))}}}.width('100%').height(rvp(44)).justifyContent(FlexAlign.SpaceBetween).padding({ left: rvp(PADDING), right: rvp(PADDING) }).margin({ top: this.topHeight })}
}

接着处理一下找房的一些图片文字资源的显示:

import { PADDING } from "../../contants/size"
import rvp from "../../utils/responsive"@Component
export default struct NavBar {@StorageProp('topHeight') topHeight: number = 0build() {Column() {Image($r('app.media.find_room')).width(rvp(60)).height(rvp(23)).margin({ left: rvp(4) })Text('发现你想看的房子').margin({ left: rvp(4), top: rvp(20) }).fontSize(rvp(12)).fontColor($r('app.color.black'))Image($r('app.media.blank')).width(rvp(234)).height(rvp(221)).alignSelf(ItemAlign.Center).margin({ top: rvp(7) })Text("暂无想看房源,试试如下找房方式").width('100%').textAlign(TextAlign.Center).margin({ top: rvp(10) }).fontSize(rvp(16)).fontColor($r('app.color.black')).fontWeight(600)Row({ space: rvp(10) }) {Row({ space: rvp(5) }) {Image($r('app.media.bus')).width(rvp(40)).height(rvp(40))Column({ space: rvp(3) }) {Text('通勤找房').fontSize(rvp(16)).fontColor($r('app.color.black'))Text('找公交车站附件房源').fontSize(rvp(12)).fontColor($r('app.color.gray'))}.alignItems(HorizontalAlign.Start)}Row({ space: rvp(5) }) {Image($r('app.media.map')).width(rvp(40)).height(rvp(40))Column({ space: rvp(3) }) {Text('地图找房').fontSize(rvp(16)).fontColor($r('app.color.black'))Text('找地图附件房源').fontSize(rvp(12)).fontColor($r('app.color.gray'))}.alignItems(HorizontalAlign.Start)}}.width('100%').height(rvp(70)).border({ width: 1, color: $r('app.color.shadow') }).margin({ top: rvp(10) }).justifyContent(FlexAlign.SpaceAround)}.width('100%').alignItems(HorizontalAlign.Start).padding({ top: rvp(54), left: rvp(PADDING), right: rvp(PADDING) })}
}

然后我们将两个封装的组件在See的想看模块中进行调用,如下所示:

import NavBar from '../components/See/NavBar'
import FindRoom from '../components/See/FindRoom'@Component
export default struct See {build() {Column() {NavBar()FindRoom()}.width('100%').height('100%').linearGradient({direction: GradientDirection.Bottom,colors: [['#DEFBE5', 0], ['#FFFFFF', 0.3]]})}
}

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

相关文章:

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

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…...

11.16 Vue element

Ajax 概念&#xff1a;Asynchronous JavaScript Anderson XML&#xff0c;异步的JavaScript和XML。 作用&#xff1a; 数据交换&#xff1a;通过Ajax 可以给服务器发送请求&#xff0c;并收取服务器相应的数据。异步交互&#xff1a;可以在不重新加载整个页面的情况下&#…...

Gin 框架中的路由

1、路由概述 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等) 组成的,涉及到应用如何响应客户端对某个网站节点的访问。 RESTful API 是目前比较成熟的一套互联网应用程序的 API 设计理论,所以我们设计我们的路 由的时候建议参考 …...

在MATLAB中实现自适应滤波算法

自适应滤波算法是一种根据信号特性自动调整滤波参数的数字信号处理方法&#xff0c;其可以有效处理噪声干扰和信号畸变问题。在许多实时数据处理系统中&#xff0c;自适应滤波算法得到了广泛应用。在MATLAB中&#xff0c;可以使用多种方法实现自适应滤波算法。本文将介绍自适应…...

linux文件与重定向

目录 一、共识原理 二、回顾C语言文件函数 1.fopen 2.fwrite 3.fclose 三、文件系统调用 1.open 2.write 3.访问文件的本质 4.stdin&&stdout&&stderror 5.文件的引用计数 四、重定向 1.文件描述符的分配规则 2. 输出重定向 3.重定向系统调用 4.…...

基于Python的仓库管理系统设计与实现

背景&#xff1a; 基于Python的仓库管理系统功能介绍 本仓库管理系统采用Python语言开发&#xff0c;利用Django框架和MySQL数据库&#xff0c;实现了高效、便捷的仓库管理功能。 用户管理&#xff1a; 支持员工和管理员角色的管理。 用户注册、登录和权限分配功能&#x…...

【Pikachu】URL重定向实战

人生在世只有一次&#xff0c;不必勉强选择自己不喜欢的路&#xff0c;随性而生或随性而死都没关系&#xff0c;不过无论选择哪条路&#xff0c;都不要忘记自己的初心。 1.不安全的url跳转实战 首先点击页面上的链接&#xff0c;观察url 直接修改url为https://www.baidu.com进…...

C语言实现3D动态爱心图形的绘制与动画效果

**标题&#xff1a;C语言实现3D动态爱心图形的绘制与动画效果** --- ### 一、引言 在计算机图形学中&#xff0c;三维图形的绘制和动画处理是一个重要且有趣的研究方向。通过数学公式描述的几何体可以在计算机屏幕上展示出丰富多彩的动态效果&#xff0c;其中“爱心”图形作…...

深入理解Nginx:从基础配置到高级优化

什么是Nginx&#xff1f; Nginx&#xff08;发音为“Engine-X”&#xff09;是一个高性能的HTTP和反向代理服务器&#xff0c;同时也可以作为邮件代理服务器和通用的TCP/UDP代理服务器。Nginx以其高并发处理能力、稳定性和灵活的配置闻名&#xff0c;是现代Web开发和部署的核心…...

ONLYOFFICE8.2版本测评,团队协作的办公软件

文章目录 引言ONLYOFFICE产品简介功能与特点1. 实时协作2. 兼容性3. 模板库4. 评论和修订5. 安全性 体验与测评功能测试 邀请用户使用项目介绍结尾了解更多 引言 在数字化办公的浪潮中&#xff0c;效率和协作成为了工作的核心。ONLYOFFICE作为一个强大的办公套件&#xff0c;正…...

spring 和 grpc 的整合

spring 和 grpc 的整合 首先我们要知道 grpc 中我们在使用的时候用到了 grpc 的那些东西 dil 的编写serverimplserverbuilder addService 客户端的 stub 编写 这里面我们看一下我们那些地方可能需要 spring 帮我们管理&#xff0c;那些地方我们需要自己来管理呢&#xff1f;…...

企业项目级IDEA设置类注释、方法注释模板(仅增加@author和@date)

文章目录 前言一 设置类注释1.1 添加模板1.2 复制配置 二 设置方法注释2.1 添加模版2.2 设置模版2.3 设置参数变量2.4 配置对应快捷键2.5 配置对应作用域2.6 使用方式 说明 前言 公司代码规范中&#xff0c;需要在标准JavaDoc注释的基础上加上作者和日期。网上虽然有很多现成的…...

1 设计模式原则之开闭原则

一、开闭原则 1.定义 开闭原则&#xff1a;对扩展开放&#xff0c;对修改关闭。 2.具体用法 在程序需要进行拓展的时候&#xff0c;不能去修改原有的代码&#xff0c;实现一个热插拔的效果。简言之&#xff0c;是为了使程序的扩展性好&#xff0c;易于维护和升级。 想要达到这…...

前端大环境

需求增长&#xff1a; 数字化转型推动&#xff1a;企业和组织的数字化转型进程不断加快&#xff0c;对前端开发的需求持续增加。无论是企业官网、电子商务平台、在线办公系统还是各种移动端应用&#xff0c;都需要专业的前端开发来打造良好的用户界面和交互体验。新兴技术和平台…...

Electron: 主进程和渲染进程之间通信

// 渲染进程 向 主进程 异步通信// preload.js 预加载 const {ipcRenderer} require(electron) ipcRenderer.send(on-send-event, 这里是需要传递的参数) // 第一步ipcRenderer.on(on-resend-event, (e, data) > {console.log(data) // 打印的是ipcMain.on传递过来的参数&a…...

社交电商的优势及其与 AI 智能名片小程序、S2B2C 商城系统的融合发展

摘要&#xff1a;本文深入分析了社交电商相较于传统电商的优势&#xff0c;包括门槛低、易操作、更生活化和可团队化运作等特点。同时&#xff0c;探讨了 AI 智能名片小程序和 S2B2C 商城系统在社交电商发展中的作用&#xff0c;以及它们与社交电商融合所带来的新机遇和发展前景…...

蓝桥杯c++算法学习【4】之简单数论(阶乘约数、求值、循环小数、等差数列、最大比例:::非常典型的必刷例题!!!)

别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! 关注博主&#xff0c;更多蓝桥杯nice题目静待更新:) 简单数论 一、阶乘约数 【问题描述】 定义阶乘n!123...n。 请问100! &#xff08;100 的阶乘&#xff09;有多少个正约数。 【答案提交】 这…...

重构代码之删除对参数的赋值

删除对参数的赋值 是一种重构技术&#xff0c;旨在消除对方法参数的重新赋值。这种实践可以增强代码的可读性和维护性&#xff0c;避免潜在的副作用。以下是详细讲解&#xff1a; 一、动机 保护参数的意图&#xff1a;方法参数通常表示传入数据或状态。如果重新赋值&#xff…...

Docker的基本概念、安装步骤以及一些简单的用法

Docker 是一种开源的容器化平台&#xff0c;允许开发者打包应用及其依赖项到一个可移植的容器中。容器可以在任何支持Docker的环境中运行&#xff0c;这使得应用的部署和管理变得更加简单和高效。 1. Docker的基本概念 在深入学习Docker之前&#xff0c;了解一些基本概念是很…...

VuePress v2 快速搭建属于自己的个人博客网站

目录 为什么用VuePress&#xff1f; 一、前期准备 Node.js 使用主题快速开发 二、VuePress安装 三、个性化定制 修改配置信息 删除不需要的信息 博客上传 四、部署 使用github快速部署 初始化仓库 本地配置 配置github的ssh密钥 部署 为什么用VuePress&#xff…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...