欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > HarmonyOS开发 - 餐饮APP首页开发实例

HarmonyOS开发 - 餐饮APP首页开发实例

2024/10/28 13:22:00 来源:https://blog.csdn.net/jiciqiang/article/details/143090403  浏览:    关键词:HarmonyOS开发 - 餐饮APP首页开发实例

        一个餐饮APP开发,主要包括以下几个核心步骤和功能:

  1. 需求和功能规划:首先需要确定APP的基本功能,如商品展示、在线点餐、订单管理、支付结算、扫码核销等。同时需要实现多门店特色功能,如门店切换与定位、库存管理和销售数据统计等。此外,还有营销功能、如优惠券发放、会员制度、积分兑换等,以吸引顾客和提高用户的粘性。
  2. 选择开发方式:如企业有自己的技术团队,可以选择自主研发,以实现高度定制化。如没有,则可以选择第三方开发平台或外包给专业的软件公司,以降低成本和提高效率。
  3. 申请账号和认证:注册相关的账号并进行企业主体认证,以确保可以使用APP的更多功能,如支付接口等。
  4. 设计与开发:设计简洁、美观、易用的界面,确保各个功能模块的正常运行和数据的准确传输。特别是多门店管理系统的开发,需要建立一个集中的管理后台,用于管理各个门店的信息、菜品、库存、订单等,以使总部可以统一管理和监控。
  5. 测试与优化:在开发完成后,进行功能测试和优化,确保APP的稳定性和用户体验。测试内容包括订单处理、支付功能、用户界面等方面。
  6. 多门店管理:实现多门店的统一管理和调试,实时监控各门店的运营情况,确保高效顺畅。
  7. 营销工具:支持优惠券、满减活动、会员积会等多种促销方式,提升客户黏性和销售额。
  8. 支付功能:支持多种支付方式,确保支付案例,提升顾客满意度。

        首先我们先完成APP的首页开发,其中包含商品展示轮播图、应用分类、商品列表、底部导航等功能。

 一、环境搭建

1.1 DevEco Studio

        如果DevEco Studio应用已安装,则直接打开并创建项目即可。

9cdc05b97c0440aa8a4d08e438e7735f.png

        如系统中未安装DevEco Studio开发工具,可前云官方网站下载,地址:DevEco Studio-HarmonyOS Next Beta版-华为开发者联盟

        安装步骤地址:HarmonyOS开发之DevEco Studio安装_select the directory where ohpm has been installed-CSDN博客

2.2 仿真机安装

        如果你没有华为系统手机,可以点击并打开Device Manager管理界面,选择“Local Emulator”本地仿真器的创建。

e41d7dc8f1164ec8860327a44f007d86.png

        在Device Manager管理界面的右下角,点击“New Emulator”新仿真器创建按钮,选择您需要创建的仿真设备即可,这里选择“Huawei_Phone”。

065cce1fd36347939a7c29c3e475c09d.png

        然后点击下一步,进入虚拟设备的配置界面,选择您需要的版本即可。这里选择最新版本(注意:在点击”下一步“按钮前,需要点击Name列中下载图标,将需要安装的对应版本先下载,否则会提示“Download the system image first”错误),如下图:

965be6db70154e92bdf9d168dba70127.png

        点击“下一步”后,会进入新界面,自定义设备名称后,点击“完成”即可。如下图:

e4d03eb0e2794cdea1b5be351edeaebe.png

        当仿真设备创建完成后,最初管理界面会多出新创建仿真设备信息,如下图:

1c64d06903eb4038abc1c177427753f2.png

        此时,点击右侧“播放”按钮,则可以启动仿真设备了。如下图:

7bc25e7ac63c4355814fe4e3cf7cd41c.png

二、创建APP应用

        创建项目应用,首先打开DevEco Studio开发工具,点击“File” -> “New” -> “Create Project”,打开

d1af06d436aa435cbf9640bcdb3362e6.png

        选择创建一个空应用,点击“下一步”。

c880086644be4ccb95d274955edff5ba.png

        修改项目名称后,点击“完成”即可。

7a17d5b0cc524abd81eef552ffa100a4.png

        此时项目则已创建成功,如下图:

a0dc868b0ae241a39f7141feb1921b1d.png

2.1 Previewer预览        

        点击右侧的“previewer”即可查看界面效果,如下图:

32c4d4a322b74fde918ac54db0eaf1dc.png

2.2 仿真设备预览

        当仿真设备启动后,在DevEco Studio中会显示创建的仿真设备的名称,此时点击右侧“Run”或“Debug”即可在仿真设备中预览界面效果了。

81b0d61f942a4bab93421db79438e9a1.png

        点击“Run”后,刚创建的项目界面,则在仿真设备中显示了,如下图:

5df7631def814ef88c09f6ac74789695.png

三、餐饮APP首页

        在介绍完HarmonyOS项目开发中,对DevEco Studio安装、仿真设备创建后,接下来将通过HarmonyOS完成如下图的首页的搭建工作。

dd81b0eea52b437e87e3c6ce215eea06.png

       上图原型已上传到资源中,需要的朋友可以前去下载,地址:https://download.csdn.net/download/jiciqiang/89906021

        图片资源,可下载原型资源包后,打开压缩包并解压,在image目录中查看。如下图:

cbd933fd8c404675bd6d6ec6e173d887.png

3.1 自定义组件 - 低代码开发

        在创建顶部导航前,我们先在ets目录中新建components目录,用于存放自定义组件。

e936441520ec4066ac5b5250c7a9f6b6.png

f4797fd5596c4439bcd97984e7cb6b85.png

        当components创建成功后,在其内部创建Header.ets文件,用于自定义顶部导航组件。

089e2b9ef8164387ac396ebf7b13d0b1.png

        选中components目录并右击,创建组件,如下图:

5c6cd5b158544388a92eeb1b3ff4f4db.png

        此操作会创建出一个低代码操作界面,可以帮助开发人员快速搭建界面布局及样式设置。如果您还是习惯于手动代码搭建,可以直接在components目录中创建ets文件,定义Header组件。低代码界面如下图:

3a3782b571004191b9cb2669bf0c61f2.png

        当我们点击“生成est文件”转换按钮后,会弹出要生成的代码弹框,如下图:

095525ada68246048521c71f51e783d4.png

        进行转换后再打开Header.ets文件,则代码已经生成。此时大家会发现,低代码文件自动删除了,这操作是不可逆的过程。

c76b3742516d407a80897c65ece19853.png

说明:使用低代码开发界面过程中,如果界面需要使用到其他暂时不支持可视化布局的控件,可以在低代码界面开发完成后,单独“转换”按钮,将低代码界面转换为ets文件。

注意:代码转换操作会删除visual文件及其父目录,且为不可逆过程,代码转换后不能通过html/css或ets文件反向生成visual文件。多设备开发的场景,可以单击界面画布query模式,可以为组件设置不同的样式和属性。当前media query模式仅针对不同设备类型和不同屏幕状态(横屏/竖屏)有效。

        DevEco低代码文档地址:文档中心

3.2 自定义组件 - 顶部导航       

        顶部导航组件开内容和样式开发完成后,可以打开pages目录下的index.ets文件,将Header组件引入进去后,再来查看下效果。

        代码如下:

import Header from '../components/Header'
@Entry
@Component
struct Index {@State message: string = 'Hello World'build() {Row() {Column() {Header()Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}
}

        界面效果如下图:

349920aa963c44afa05403ec2b896bd6.png

        界面内容和样式虽然已完成了,但是当搜索内容改变时,需要将输入文本上报给父组件,从而做出相应操作及跳转动作。所以我们在Header.ets文件添加相应变量、方法和事件,将信息传递给父组件。

components/Header.ets代码如下:

@Preview
@Component
export default struct Header {// 搜索关键词@State keyword: string = ''// 关键词内容改变时回调函数private onSearchChange: (data: string) => voidbuild() {Row() {Image($rawfile('position_u5.png')).width("16vp").height("25vp").margin({ top: "0vp", bottom: "0vp", left: "0vp", right: "0vp" })Text("门店信息\n").width("65vp").height("40vp").fontSize("12fp")TextInput({ text: this.keyword, placeholder: "请输入搜索关键词" }).width("170vp").height("40vp").placeholderColor("#262626").placeholderFont({ size: 12 }).onChange((e) => this.keyword = e)Button("搜索").width("70vp").height("40vp").onClick(() => {this.onSearchChange(this.keyword) // 点击查询事件,将信息传递给父组件})}    .width("100%").padding({ top: "10vp", bottom: "10vp", left: "15vp", right: "15vp" }).justifyContent(FlexAlign.SpaceBetween)}
}

pages/Index.ets代码如下:

import Header from '../components/Header'
@Entry
@Component
struct Index {@State keyword: string = ''build() {Row() {Column() {Header({onSearchChange: this.onSearchChange.bind(this)})}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}/*** 搜索内容改变事件* @param data*/onSearchChange(data: string){console.log('search', data)}
}

        此时点击顶部导航栏中“搜索”按钮,则可以在父组件中输出输入框中的内容了。如下图:

3e3f9af26a6c4b469f70f4fcc24bbadf.png

0a725ef92ab04787bea0071e9d3d7e3a.png

        该篇目前只讲首页搭建部分内容,所以搜索功能后续操作暂时不再详说,后续有机会或者大家自行追加即可。

3.3 自定义组件 - 底部菜单

ff4f3d4985994a62a958188d2f74153d.png

        接下来我们来完善下底部菜单导航的开发工作,这里将使用到UI界面的Tabs组件。

3.3.1 Tabs组件

        Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。TabContent是内容页,TabBar是导航页签栏,页面结构如下图所示,根据不同的导航类型,布局会有区别,可以分为底部导航、顶部导航、侧边导航,其导航栏分别位于底部、顶部和侧边。

35b2dd93cda541a9830b3a47b6782e52.png

说明:

  • TabContent组件不支持设置通用宽度属性,其宽度默认撑满Tabs父组件。
  • TabContent组件不支持设置通用高度属性,其高度由Tabs父组件高度与TabBar组件高度决定。

        Tabs使用花括号包裹TabContent,如下图,其中TabContent显示相应的内容页。

6c82dac3fd284d3787673daf9a127c81.png

        官方文档地址:文档中心

3.3.2 实现Tabs菜单

        了解了Tabs结构后,我们使用它完成底部导航菜单代码部分。visual低代码模式中也有Tabs组件,由于这里没有复杂的样式结构,直接在页面中定义即可。

        pages/index.ets代码如下:

import Header from '../components/Header'
@Entry
@Component
struct Index {@State keyword: string = ''build() {Row() {Column() {Tabs({barPosition: BarPosition.End}){TabContent(){Header({onSearchChange: this.onSearchChange.bind(this)})}.tabBar({icon: $rawfile('u48.png'), text: '首页'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u43.png'), text: '订单'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u53.png'), text: '我的'})}.barMode(BarMode.Fixed).barHeight(60)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}/*** 搜索内容改变事件* @param data*/onSearchChange(data: string){console.log('search value:', data)}
}

        页面效果如下图:

ec38ddf4a4d74092b9897590ef5e53ba.png

3.4 自定义构建函数 - 轮播图

        Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。通常,在一些应用首页显示推荐的内容时,需要用到轮播显示的能力。

        在components/Index目录中创建轮播图组件,文件结构如下图:

d096d2ad3fc2403fb07b7700715f8aea.png

        代码如下:

@Preview
@Component
export default struct CarouselMap {private swiperController: SwiperController = new SwiperController()build() {Row() {Swiper(this.swiperController){Image($rawfile('u13.png')).borderRadius(10)Image($rawfile('u13.png')).borderRadius(10)}.width("100%").height("200vp").padding(10).index(0)         // 默认索引.autoPlay(true)   // 自动播放.loop(true)       // 循环播放.itemSpace(10)    // 图片的间隙.onChange((index: number) => {console.log('testTag swiper index:', index)})}}
}

        当轮播图组件定义好后,将期引入到首页中,pages/index.ets代码如下:

import Header from '../components/Header'
import CarouseMap from '../components/Index/CarouselMap'
@Entry
@Component
struct Index {@State keyword: string = ''build() {Row() {Column() {Tabs({barPosition: BarPosition.End}){TabContent(){// 增加Column原因是因为TabContent中只有一个子组件,否则会报错Column(){Header({onSearchChange: this.onSearchChange.bind(this)})CarouseMap()}.width('100%').height('100%').alignItems(HorizontalAlign.Start)}.tabBar({icon: $rawfile('u48.png'), text: '首页'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u43.png'), text: '订单'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u53.png'), text: '我的'})}.barMode(BarMode.Fixed).barHeight(60)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}/*** 搜索内容改变事件* @param data*/onSearchChange(data: string){console.log('search value:', data)}
}

        页面效果如下图:

6d80d84fdcdd4ba987bd266c22ba088f.png

3.5 自定义构建函数 - 分类列表

       接下来完成分类列表信息,在components/Index目录中创建CategoryList.ets组件。

0678c7939e33467e83c4cba005f36149.png

        创建后visual低代码编辑界面,如下图:

dcd9a5d0598c48e6819b62d2b5bf5a40.png

        当界面内容搭建完后,通过转换按钮,生成分类列表的组件代码。代码如下:

@Preview
@Component
export default struct MiddleMenu {build() {Row() {Column() {Image($rawfile('u27.png')).width("64vp").height("64vp")Text("门店").height("32vp").textAlign(TextAlign.Center).fontSize("16fp").fontWeight(FontWeight.Bold)}Column() {Image($rawfile('u25.png')).width("64vp").height("64vp")Text("水果").height("32vp").textAlign(TextAlign.Center).fontSize("16fp").fontWeight(FontWeight.Bold)}Column() {Image($rawfile('u27.png')).width("64vp").height("64vp")Text("美食").height("32vp").textAlign(TextAlign.Center).fontSize("16fp").fontWeight(FontWeight.Bold)}Column() {Image($rawfile('u29.png')).width("64vp").height("64vp")Text("包厢").height("32vp").textAlign(TextAlign.Center).fontSize("16fp").fontWeight(FontWeight.Bold)}}    .width("100%").padding({ top: 10, bottom: 10, left: 20, right: 20 }).justifyContent(FlexAlign.SpaceBetween)}
}

        再将分类列表组件引入到首页中,代码如下:

import Header from '../components/Header'
import CarouseMap from '../components/Index/CarouselMap'
import CategoryList from '../components/Index/CategoryList'
@Entry
@Component
struct Index {@State keyword: string = ''build() {Row() {Column() {Tabs({barPosition: BarPosition.End}){TabContent(){// 增加Column原因是因为TabContent中只有一个子组件,否则会报错Column(){Header({onSearchChange: this.onSearchChange.bind(this)})    // 顶部导航CarouseMap()        // 轮播图CategoryList()      // 分类列表}.width('100%').height('100%').alignItems(HorizontalAlign.Start)}.tabBar({icon: $rawfile('u48.png'), text: '首页'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u43.png'), text: '订单'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u53.png'), text: '我的'})}.barMode(BarMode.Fixed).barHeight(60)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}/*** 搜索内容改变事件* @param data*/onSearchChange(data: string){console.log('search value:', data)}
}

        页面效果如下图:

48d0882d25ef4541aa5fb4dff6aa9a18.png

3.6 自定义构建函数 - 产品列表

        最后,再创建一个产品列表,在components/Index目录中创建ProductList组件。

27a7dd22606b4e0ea25d15a337229b58.png

3.6.1 visual低代码编辑

        这部分样式结构会稍微复杂点,所以在visual文件的低代码模式下,先画出基本轮廓和第一个产品信息,其他等转换为代码模式时,通过列表循环输出即可。如下图:

1998aedd55b24b208520bb978208e660.png

3.6.2 转换为代码

        转换后的代码,只是基本结构和部分产品样式,代码如下:

@Preview
@Component
export default struct ProductList {build() {Row({ space: "0vp" }) {Column() {Text("精品特卖").width("100%").height("50vp").fontSize("16fp").fontWeight(FontWeight.Bold)Row() {Row() {Column() {Column() {Image($rawfile('u62.png')).width("150vp").height("65vp")Text("啫啫鱼头").width("150vp").height("26vp").textOverflow({ overflow: TextOverflow.Ellipsis }).fontSize("10fp")Row() {Text("¥52").width("60vp").height("30vp").fontColor("#ff0000").fontSize("12fp").fontWeight(FontWeight.Bold)Text("原价:55元").width("90vp").height("30vp").fontColor("#575757").decoration({ type: TextDecorationType.LineThrough, color: "#313030" })}                .width("150vp")}}Column()}}Row() {Column()Column()}}      .width("100%")}    .width("100%").padding({ top: "10vp", bottom: "10vp", left: "15vp", right: "15vp" })}
}

        此时将其引入到首页中效果是这样的,如下图:

45e8ba724da84dd2b6e8f443dd572159.png

        产品信息是通过接口获取的列表数据,然后通过GridRow组件和GridCol组件组合使用,将产品渲染成两列。这里暂时未调用接口,所以先将数据定义在组件中,通过ForEach遍历数组。

        components/Index/ProductList.ets代码如下:


type ProductType = {title: stringthumb: Resourceprice: numberoriginPrice: number
}@Preview
@Component
export default struct ProductList {@State productList: Array<ProductType> = [{ title: '啫啫鱼头', thumb: $rawfile('u62.png'), price: 52, originPrice: 55 },{ title: '黑椒汁啫牛肉', thumb: $rawfile('u76.png'), price: 55, originPrice: 60 },{ title: '啫啫田鸡', thumb: $rawfile('u90.png'), price: 52, originPrice: 55 },{ title: '咸蛋黄啫苦瓜', thumb: $rawfile('u104.png'), price: 26, originPrice: 30 }]// 定义内联构建函数@Builder ImageItems(item: ProductType){Row(){Column(){Image(item.thumb).width("100%").height("100vp").borderRadius(8)Text(item.title).width("100%").height("36vp").textOverflow({ overflow: TextOverflow.Ellipsis }).fontSize("18fp")Row() {Text("¥" + item.price).width("40%").fontColor("#ff0000").fontSize("18fp").fontWeight(FontWeight.Bold)Text("原价:" + item.originPrice + "元").width("60%").fontColor("#575757").fontSize("12fp").decoration({ type: TextDecorationType.LineThrough, color: "#313030" })}.width("100%").alignItems(VerticalAlign.Center)}}.width('100%').padding(10)}build() {Row({ space: "0vp" }) {Column() {Text("精品特卖").width("100%").height("50vp").fontSize("16fp").fontWeight(FontWeight.Bold).padding(10)// 每行分两列展示GridRow({columns: 2}){ForEach(this.productList, (item: ProductType, index) => {GridCol(){this.ImageItems(item)}})}}.padding(5)}.width("100%")}
}

        此时首页就已完成了,效果如下图:

3b5ae9c2c6f44e48abf7e4111586bfbf.png

3.6.3 滚动条

        不过此时,大家可能会发现内容超出来屏幕可见区域,无法上拉显示。这个问题比较简单,可以使用List和ListItem组件解决。

        pages/index.ets最终代码如下:

import Header from '../components/Header'
import CarouseMap from '../components/Index/CarouselMap'
import CategoryList from '../components/Index/CategoryList'
import ProductList from '../components/Index/ProductList'
@Entry
@Component
struct Index {@State keyword: string = ''build() {Row() {Column() {Tabs({barPosition: BarPosition.End}){TabContent(){// 增加Column原因是因为TabContent中只有一个子组件,否则会报错Column(){Header({onSearchChange: this.onSearchChange.bind(this)})    // 顶部导航List(){ListItem(){Column(){CarouseMap()        // 轮播图CategoryList()      // 分类列表ProductList()       // 产品列表}}}.layoutWeight(1)}.width('100%').height('100%').alignItems(HorizontalAlign.Start)}.tabBar({icon: $rawfile('u48.png'), text: '首页'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u43.png'), text: '订单'})TabContent(){Text('待开发中...')}.tabBar({icon: $rawfile('u53.png'), text: '我的'})}.barMode(BarMode.Fixed).barHeight(60)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}/*** 搜索内容改变事件* @param data*/onSearchChange(data: string){console.log('search value:', data)}
}

        此时页面超出部分则可以上拉查看了,如下图:

1e0ad74db35e4301a3077ed165b3cf53.png

        这就是首页全部静态代码了,后期须根据接口数据动态渲染及增加交互功能,这期就不讲解了。希望对大家有所帮助~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com