一个餐饮APP开辟,主要包括以下几个核心步骤和功能:
- 需求和功能规划:首先必要确定APP的基本功能,如商品展示、在线点餐、订单管理、付出结算、扫码核销等。同时必要实现多门店特色功能,如门店切换与定位、库存管理和销售数据统计等。别的,另有营销功能、如优惠券发放、会员制度、积分兑换等,以吸引顾客和进步用户的粘性。
- 选择开辟方式:如企业有本身的技术团队,可以选择自主研发,以实现高度定制化。如没有,则可以选择第三方开辟平台或外包给专业的软件公司,以低落本钱和进步效率。
- 申请账号和认证:注册相关的账号并进行企业主体认证,以确保可以利用APP的更多功能,如付出接口等。
- 计划与开辟:计划简洁、美观、易用的界面,确保各个功能模块的正常运行和数据的准确传输。特别是多门店管理体系的开辟,必要创建一个集中的管理后台,用于管理各个门店的信息、菜品、库存、订单等,以使总部可以统一管理和监控。
- 测试与优化:在开辟完成后,进行功能测试和优化,确保APP的稳定性和用户体验。测试内容包括订单处理、付出功能、用户界面等方面。
- 多门店管理:实现多门店的统一管理和调试,实时监控各门店的运营情况,确保高效顺畅。
- 营销工具:支持优惠券、满减活动、会员积会等多种促销方式,提升客户黏性和销售额。
- 付出功能:支持多种付出方式,确保付出案例,提升顾客满足度。
首先我们先完成APP的首页开辟,其中包含商品展示轮播图、应用分类、商品列表、底部导航等功能。
一、情况搭建
1.1 DevEco Studio
如果DevEco Studio应用已安装,则直接打开并创建项目即可。
如体系中未安装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”本地仿真器的创建。
在Device Manager管理界面的右下角,点击“New Emulator”新仿真器创建按钮,选择您必要创建的仿真装备即可,这里选择“Huawei_Phone”。
然后点击下一步,进入假造装备的配置界面,选择您必要的版本即可。这里选择最新版本(注意:在点击”下一步“按钮前,必要点击Name列中下载图标,将必要安装的对应版本先下载,否则会提示“Download the system image first”错误),如下图:
点击“下一步”后,会进入新界面,自定义装备名称后,点击“完成”即可。如下图:
当仿真装备创建完成后,最初管理界面会多出新创建仿真装备信息,如下图:
此时,点击右侧“播放”按钮,则可以启动仿真装备了。如下图:
二、创建APP应用
创建项目应用,首先打开DevEco Studio开辟工具,点击“File” -> “New” -> “Create Project”,打开
选择创建一个空应用,点击“下一步”。
修改项目名称后,点击“完成”即可。
此时项目则已创建乐成,如下图:
2.1 Previewer预览
点击右侧的“previewer”即可检察界面结果,如下图:
2.2 仿真装备预览
当仿真装备启动后,在DevEco Studio中会显示创建的仿真装备的名称,此时点击右侧“Run”或“Debug”即可在仿真装备中预览界面结果了。
点击“Run”后,刚创建的项目界面,则在仿真装备中显示了,如下图:
三、餐饮APP首页
在介绍完HarmonyOS项目开辟中,对DevEco Studio安装、仿真装备创建后,接下来将通过HarmonyOS完成如下图的首页的搭建工作。
上图原型已上传到资源中,必要的朋友可以前去下载,地址:https://download.csdn.net/download/jiciqiang/89906021
图片资源,可下载原型资源包后,打开压缩包并解压,在image目录中检察。如下图:
3.1 自定义组件 - 低代码开辟
在创建顶部导航前,我们先在ets目录中新建components目录,用于存放自定义组件。
当components创建乐成后,在其内部创建Header.ets文件,用于自定义顶部导航组件。
选中components目录并右击,创建组件,如下图:
此操作会创建出一个低代码操作界面,可以帮助开辟人员快速搭建界面结构及样式设置。如果您照旧风俗于手动代码搭建,可以直接在components目录中创建ets文件,定义Header组件。低代码界面如下图:
当我们点击“天生est文件”转换按钮后,会弹出要天生的代码弹框,如下图:
进行转换后再打开Header.ets文件,则代码已经天生。此时各人会发现,低代码文件自动删除了,这操作是不可逆的过程。
说明:利用低代码开辟界面过程中,如果界面必要利用到其他暂时不支持可视化结构的控件,可以在低代码界面开辟完成后,单独“转换”按钮,将低代码界面转换为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)
- }
- }
复制代码 界面结果如下图:
界面内容和样式虽然已完成了,但是当搜刮内容改变时,必要将输入文本上报给父组件,从而做出相应操作及跳转动作。所以我们在Header.ets文件添加相应变量、方法和事件,将信息传递给父组件。
components/Header.ets代码如下:
- @Preview
- @Component
- export default struct Header {
- // 搜索关键词
- @State keyword: string = ''
- // 关键词内容改变时回调函数
- private onSearchChange: (data: string) => void
- build() {
- 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)
- }
- }
复制代码 此时点击顶部导航栏中“搜刮”按钮,则可以在父组件中输出输入框中的内容了。如下图:
该篇现在只讲首页搭建部分内容,所以搜刮功能后续操作暂时不再详说,后续偶然机或者各人自行追加即可。
3.3 自定义组件 - 底部菜单
接下来我们来完善下底部菜单导航的开辟工作,这里将利用到UI界面的Tabs组件。
3.3.1 Tabs组件
Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。TabContent是内容页,TabBar是导航页签栏,页面结构如下图所示,根据不同的导航类型,结构会有区别,可以分为底部导航、顶部导航、侧边导航,其导航栏分别位于底部、顶部和侧边。
说明:
- TabContent组件不支持设置通用宽度属性,其宽度默认撑满Tabs父组件。
- TabContent组件不支持设置通用高度属性,其高度由Tabs父组件高度与TabBar组件高度决定。
Tabs利用花括号包裹TabContent,如下图,其中TabContent显示相应的内容页。
官方文档地址:文档中央
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)
- }
- }
复制代码 页面结果如下图:
3.4 自定义构建函数 - 轮播图
Swiper组件提供滑动轮播显示的本领。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。通常,在一些应用首页显示推荐的内容时,必要用到轮播显示的本领。
在components/Index目录中创建轮播图组件,文件结构如下图:
代码如下:
- @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)
- }
- }
复制代码 页面结果如下图:
3.5 自定义构建函数 - 分类列表
接下来完身分类列表信息,在components/Index目录中创建CategoryList.ets组件。
创建后visual低代码编辑界面,如下图:
当界面内容搭建完后,通过转换按钮,生身分类列表的组件代码。代码如下:
- @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)
- }
- }
复制代码 页面结果如下图:
3.6 自定义构建函数 - 产物列表
最后,再创建一个产物列表,在components/Index目录中创建ProductList组件。
3.6.1 visual低代码编辑
这部分样式结构会稍微复杂点,所以在visual文件的低代码模式下,先画出基本表面和第一个产物信息,其他等转换为代码模式时,通过列表循环输出即可。如下图:
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" })
- }
- }
复制代码 此时将其引入到首页中结果是这样的,如下图:
产物信息是通过接口获取的列表数据,然后通过GridRow组件和GridCol组件组合利用,将产物渲染成两列。这里暂时未调用接口,所以先将数据定义在组件中,通过ForEach遍历数组。
components/Index/ProductList.ets代码如下:
- type ProductType = {
- title: string
- thumb: Resource
- price: number
- originPrice: 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%")
- }
- }
复制代码 此时首页就已完成了,结果如下图:
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)
- }
- }
复制代码 此时页面超出部分则可以上拉检察了,如下图:
这就是首页全部静态代码了,后期须根据接口数据动态渲染及增长交互功能,这期就不解说了。渴望对各人有所帮助~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |