【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】鸿蒙系统在租房项目中的项目实战(二)
从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是…...

11.16 Vue element
Ajax 概念:Asynchronous JavaScript Anderson XML,异步的JavaScript和XML。 作用: 数据交换:通过Ajax 可以给服务器发送请求,并收取服务器相应的数据。异步交互:可以在不重新加载整个页面的情况下&#…...
Gin 框架中的路由
1、路由概述 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等) 组成的,涉及到应用如何响应客户端对某个网站节点的访问。 RESTful API 是目前比较成熟的一套互联网应用程序的 API 设计理论,所以我们设计我们的路 由的时候建议参考 …...

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

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

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

【Pikachu】URL重定向实战
人生在世只有一次,不必勉强选择自己不喜欢的路,随性而生或随性而死都没关系,不过无论选择哪条路,都不要忘记自己的初心。 1.不安全的url跳转实战 首先点击页面上的链接,观察url 直接修改url为https://www.baidu.com进…...
C语言实现3D动态爱心图形的绘制与动画效果
**标题:C语言实现3D动态爱心图形的绘制与动画效果** --- ### 一、引言 在计算机图形学中,三维图形的绘制和动画处理是一个重要且有趣的研究方向。通过数学公式描述的几何体可以在计算机屏幕上展示出丰富多彩的动态效果,其中“爱心”图形作…...
深入理解Nginx:从基础配置到高级优化
什么是Nginx? Nginx(发音为“Engine-X”)是一个高性能的HTTP和反向代理服务器,同时也可以作为邮件代理服务器和通用的TCP/UDP代理服务器。Nginx以其高并发处理能力、稳定性和灵活的配置闻名,是现代Web开发和部署的核心…...

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

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

企业项目级IDEA设置类注释、方法注释模板(仅增加@author和@date)
文章目录 前言一 设置类注释1.1 添加模板1.2 复制配置 二 设置方法注释2.1 添加模版2.2 设置模版2.3 设置参数变量2.4 配置对应快捷键2.5 配置对应作用域2.6 使用方式 说明 前言 公司代码规范中,需要在标准JavaDoc注释的基础上加上作者和日期。网上虽然有很多现成的…...
1 设计模式原则之开闭原则
一、开闭原则 1.定义 开闭原则:对扩展开放,对修改关闭。 2.具体用法 在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。 想要达到这…...
前端大环境
需求增长: 数字化转型推动:企业和组织的数字化转型进程不断加快,对前端开发的需求持续增加。无论是企业官网、电子商务平台、在线办公系统还是各种移动端应用,都需要专业的前端开发来打造良好的用户界面和交互体验。新兴技术和平台…...
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 商城系统的融合发展
摘要:本文深入分析了社交电商相较于传统电商的优势,包括门槛低、易操作、更生活化和可团队化运作等特点。同时,探讨了 AI 智能名片小程序和 S2B2C 商城系统在社交电商发展中的作用,以及它们与社交电商融合所带来的新机遇和发展前景…...

蓝桥杯c++算法学习【4】之简单数论(阶乘约数、求值、循环小数、等差数列、最大比例:::非常典型的必刷例题!!!)
别忘了请点个赞收藏关注支持一下博主喵!!!! 关注博主,更多蓝桥杯nice题目静待更新:) 简单数论 一、阶乘约数 【问题描述】 定义阶乘n!123...n。 请问100! (100 的阶乘)有多少个正约数。 【答案提交】 这…...
重构代码之删除对参数的赋值
删除对参数的赋值 是一种重构技术,旨在消除对方法参数的重新赋值。这种实践可以增强代码的可读性和维护性,避免潜在的副作用。以下是详细讲解: 一、动机 保护参数的意图:方法参数通常表示传入数据或状态。如果重新赋值ÿ…...
Docker的基本概念、安装步骤以及一些简单的用法
Docker 是一种开源的容器化平台,允许开发者打包应用及其依赖项到一个可移植的容器中。容器可以在任何支持Docker的环境中运行,这使得应用的部署和管理变得更加简单和高效。 1. Docker的基本概念 在深入学习Docker之前,了解一些基本概念是很…...

VuePress v2 快速搭建属于自己的个人博客网站
目录 为什么用VuePress? 一、前期准备 Node.js 使用主题快速开发 二、VuePress安装 三、个性化定制 修改配置信息 删除不需要的信息 博客上传 四、部署 使用github快速部署 初始化仓库 本地配置 配置github的ssh密钥 部署 为什么用VuePressÿ…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...