实现菜谱二级联动导航
本篇案例主要介绍如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能:
- 切换左侧导航,右侧滚动到对应的内容。
- 滚动右侧的内容,左侧会切换对应的导航。
1. 案例效果截图
2. 案例运用到的知识点
2.1. 核心知识点
- List:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
- ListItemGroup:该组件用来展示列表item分组,宽度默认充满List组件,必须配合List组件来使用。
2.2. 其他知识点
- ArkTS 语言基础
- 自定义组件和组件生命周期
- V1状态管理:@State、@Prop
- 自定义构建函数:@Builder
- 渲染控制:ForEach
- 内置组件:Column/Text/Row/
- 常量与资源分类的访问
- MVVM模式
3. 代码结构
├──entry/src/main/ets // 代码区
│ ├──common
│ │ └──constants
│ │ └──Constants.ets // 常量类
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口类
│ ├──pages
│ │ └──IndexPage.ets // 二级联动页面入口
│ ├──view
│ │ ├──ClassityItem.ets // 课程分类组件
│ │ └──CourseItem.ets // 课程信息组件
│ └──viewmodel
│ ├──ClassifyModel.ets // 导航Model
│ ├──ClassifyViewModel.ets // 导航ViewModel
│ ├──CourseModel.ets // 课程内容model
│ └──LinkDataModel.ets // 数据源model
└──entry/src/main/resources // 资源文件
4. 公共文件与资源
本案例涉及到的常量类和工具类代码如下:
4.1. 通用常量类
// entry/src/main/ets/common/constants/Constant.ets
export default class Constants {static readonly LABEL_FONT_WEIGHT: number = 400static readonly TITLE_FONT_WEIGHT: number = 500static readonly COURSE_ITEM_PADDING: number = 12static readonly LOADING_DURATION: number = 2000static readonly TITLE_LINE_NUMBER: number = 2static readonly FULL_PERCENT: string = '100%'static readonly CLASSIFY_TITLE_PERCENT: string = '55%'
}
本案例涉及到的资源文件如下:
4.2. string.json
// entry/src/main/resources/base/element/string.json
{"string": [{"name": "module_desc","value": "模块描述"},{"name": "EntryAbility_desc","value": "description"},{"name": "EntryAbility_label","value": "二级联动"},{"name": "loading","value": "加载数据中..."},{"name": "free_price","value": "免费"},{"name": "price_str","value": "¥%d"},{"name": "hei_ti_medium","value": "HarmonyHeiTi-Medium"},{"name": "hei_ti","value": "HarmonyHeiTi"}]
}
4.3. float.json
// entry/src/main/resources/base/element/float.json
{"float": [{"name": "classify_item_width","value": "100vp"},{"name": "dish_item_height","value": "96vp"},{"name": "classify_item_height","value": "56vp"},{"name": "title_line_height","value": "20vp"},{"name": "dish_item_padding","value": "12vp"},{"name": "item_padding_left","value": "8vp"},{"name": "normal_border_radius","value": "18vp"},{"name": "header_font_size","value": "18fp"},{"name": "normal_font_size","value": "14fp"}]
}
4.4. color.json
// entry/src/main/resources/base/element/color.json
{"color": [{"name": "start_window_background","value": "#FFFFFF"},{"name": "classify_background","value": "#0D182431"},{"name": "base_background","value": "#F1F3F5"},{"name": "base_font_color","value": "#182431"},{"name": "normal_font_color","value": "#99182431"},{"name": "price_color","value": "#FA2A2D"}]
}
其他资源请到源码中获取。
5. 定义数据结构和数据初始化
5.1. 菜品模型:DishModel
// entry/src/main/ets/viewModel/DishModel.ets
export default class DishModel {classifyId: numberdishId: numberdishName: stringimageUrl: stringviews: stringconstructor(classifyId: number, dishId: number, dishName: string, imageUrl: string, views: string) {this.classifyId = classifyIdthis.dishId = dishIdthis.dishName = dishNamethis.imageUrl = imageUrlthis.views = views}
}
5.2. 分类模型:ClassifyModel
// entry/src/main/ets/viewModel/ClassifyModel.ets
import DishModel from './DishModel'export default class ClassifyModel {classifyId: numberclassifyName: stringdishList: Array<DishModel>constructor(classifyId: number, classifyName: string, dishList: Array<DishModel>) {this.classifyId = classifyIdthis.classifyName = classifyNamethis.dishList = dishList}
}
5.3. 数据初始化模型:LinkDataModel
// entry/src/main/ets/viewModel/LinkDataModel.ets
export default class LinkDataModel {superId: numbersuperName: stringid: numberdishName: stringimageUrl: stringviews: stringconstructor(superId: number, superName: string, id: number, dishName: string, imageUrl: string, views: string) {this.superId = superIdthis.superName = superNamethis.id = idthis.dishName = dishNamethis.imageUrl = imageUrlthis.views = views}
}
5.4. 数据初始化:ClassifyViewModel
// entry/src/main/ets/viewModel/ClassifyViewModel.ets
import ClassifyModel from './ClassifyModel'
import DishModel from './DishModel'
import LinkDataModel from './LinkDataModel'class ClassifyViewModel {getLinkData(): Array<ClassifyModel> {let linkDataList: Array<ClassifyModel> = []let superId: number = 0LINK_DATA.forEach((item: LinkDataModel) => {let result: ClassifyModel | undefined = linkDataList.find((value: ClassifyModel) => value.classifyId === item.superId)if (result !== undefined) {let dishItem: DishModel = new DishModel(superId, item.id, item.dishName, item.imageUrl, item.views)result.dishList.push(dishItem)} else {let classifyItem: ClassifyModel = new ClassifyModel(item.superId, item.superName, [])linkDataList.push(classifyItem)}})return linkDataList}
}let classifyViewModel = new ClassifyViewModel()export default classifyViewModel as ClassifyViewModelconst LINK_DATA: LinkDataModel[] = [new LinkDataModel(1, '荤菜', 785855, '小炒牛肉', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/1313/561c9a314c8bb.jpg/OTAweDYwMA', '961.2万'),new LinkDataModel(1, '荤菜', 785834, '红烧肉', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/1311/561c79f4d4e14.jpg/OTAweDYwMA', '3672.3万'),new LinkDataModel(1, '荤菜', 786082, '糖醋排骨', 'https://s1.cdn.jiaonizuocai.com/videoImg/201509/0722/55ed97982b6fc.JPG/OTAweDYwMA', '3334.9万'),new LinkDataModel(2, '鱼类', 778816, '清蒸鱼', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/3113/311354095180.jpg/OTAweDYwMA', '1358.8万'),new LinkDataModel(3, '家常菜', 801048, '西红柿炒鸡蛋', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/1914/191406289.jpg/OTAweDYwMA', '624.1万'),new LinkDataModel(1, '荤菜', 780819, '蒜香排骨', 'https://s1.cdn.jiaonizuocai.com/videoImg/201509/0722/55eda07f5974c.JPG/OTAweDYwMA', '949.4万'),new LinkDataModel(4, '素菜', 775734, '鱼香茄子', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/1115/042148249114.jpg/OTAweDYwMA', '1106.6万'),new LinkDataModel(1, '荤菜', 808716, '土豆炖牛肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/0818/081841111186.jpg/OTAweDYwMA', '552.7万'),new LinkDataModel(2, '鱼类', 778785, '红烧鲫鱼', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/3111/311153367572.jpg/OTAweDYwMA', '919.6万'),new LinkDataModel(1, '荤菜', 216633, '红烧肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201502/0914/091427111222.jpg/OTAweDYwMA', '611.6万'),new LinkDataModel(5, '烘焙', 835381, '可可坚果曲奇饼干', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1515/151554197122.jpg/OTAweDYwMA', '13.5万'),new LinkDataModel(5, '烘焙', 773496, '轻乳酪蛋糕', 'https://s1.cdn.jiaonizuocai.com/caipu/201507/2722/272226259107.jpg/OTAweDYwMA', '108.1万'),new LinkDataModel(5, '烘焙', 789140, '玛格丽特饼干', 'https://s1.cdn.jiaonizuocai.com/caipu/201511/1414/141539449397.jpg/OTAweDYwMA', '79.0万'),new LinkDataModel(5, '烘焙', 769836, '黑森林蛋糕', 'https://s1.cdn.jiaonizuocai.com/caipu/201506/2714/271419323579.jpg/OTAweDYwMA', '65.2万'),new LinkDataModel(5, '烘焙', 837068, '古典巧克力蛋糕', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1718/171804353178.jpg/OTAweDYwMA', '5.9万'),new LinkDataModel(5, '烘焙', 798225, '抹茶蛋糕卷', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/0811/081154448687.jpg/OTAweDYwMA', '35.4万'),new LinkDataModel(5, '烘焙', 837729, '巧克力豆饼干', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1816/181618262807.jpg/OTAweDYwMA', '27.1万'),new LinkDataModel(5, '烘焙', 776491, '菠萝包', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/1617/200105387287.jpg/OTAweDYwMA', '71.0万'),new LinkDataModel(5, '烘焙', 818315, '磨牙棒', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/1710/171031541292.jpg/OTAweDYwMA', '21.7万'),new LinkDataModel(5, '烘焙', 217520, '港式吐司', 'https://s1.cdn.jiaonizuocai.com/caipu/201503/2020/202041142728.jpg/OTAweDYwMA', '11.1万'),new LinkDataModel(4, '素菜', 799859, '青椒炒香干', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/1423/211412215476.jpg/OTAweDYwMA', '73.5万'),new LinkDataModel(7, '凉菜', 793956, '凉拌黄豆芽', 'https://s1.cdn.jiaonizuocai.com/caipu/201512/1409/170911571133.jpg/OTAweDYwMA', '151.2万'),new LinkDataModel(4, '素菜', 813538, '虎皮青椒', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/3010/301011441374.jpg/OTAweDYwMA', '739.1万'),new LinkDataModel(4, '素菜', 787825, '番茄炒西兰花', 'https://s1.cdn.jiaonizuocai.com/videoImg/201511/0314/56384dbb6eccc.jpg/OTAweDYwMA', '421.9万'),new LinkDataModel(4, '素菜', 838447, '清炒茭白', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1915/191526528108.jpg/OTAweDYwMA', '184.5万'),new LinkDataModel(10, '汤类', 833605, '红豆薏米水', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1309/130946355952.jpg/OTAweDYwMA', '48.1万'),new LinkDataModel(4, '素菜', 834648, '清炒山药西兰花', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1415/141509466883.jpg/OTAweDYwMA', '99.4万'),new LinkDataModel(9, '主食', 834271, '泡菜饼', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1405/140546102661.jpg/OTAweDYwMA', '34.3万'),new LinkDataModel(4, '素菜', 834306, '莴笋炒鸡蛋', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1408/140812295301.jpg/OTAweDYwMA', '74.2万'),new LinkDataModel(7, '凉菜', 837294, '葱油爽脆南瓜', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1722/172215217867.jpg/OTAweDYwMA', '48.4万'),new LinkDataModel(7, '凉菜', 827955, '皮蛋拌豆腐', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/2121/212305195442.jpg/OTAweDYwMA', '388.8万'),new LinkDataModel(7, '凉菜', 778444, '凉拌海带丝', 'https://s1.cdn.jiaonizuocai.com/videoImg/201508/2722/55df165f2fa58.JPG/OTAweDYwMA', '617.5万'),new LinkDataModel(7, '凉菜', 805657, '凉拌芹菜', 'https://s1.cdn.jiaonizuocai.com/caipu/201602/1820/182006369191.jpg/OTAweDYwMA', '194.7万'),new LinkDataModel(7, '凉菜', 793956, '凉拌黄豆芽', 'https://s1.cdn.jiaonizuocai.com/caipu/201512/1409/170911571133.jpg/OTAweDYwMA', '151.2万'),new LinkDataModel(7, '凉菜', 790528, '凉拌藕片', 'https://s1.cdn.jiaonizuocai.com/caipu/201511/2314/231418172139.jpg/OTAweDYwMA', '283.5万'),new LinkDataModel(7, '凉菜', 835028, '玫瑰山药', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1507/150729137308.jpg/OTAweDYwMA', '44.9万'),new LinkDataModel(7, '凉菜', 832891, '凉拌黑木耳', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1120/112055191758.jpg/OTAweDYwMA', '168.4万'),new LinkDataModel(7, '凉菜', 772022, '生椒凉拌黑木耳', 'https://s1.cdn.jiaonizuocai.com/caipu/201507/1715/171548454593.jpg/OTAweDYwMA', '71.7万'),new LinkDataModel(7, '凉菜', 805785, '凉拌豆角', 'https://s1.cdn.jiaonizuocai.com/caipu/201602/1917/191726567021.jpg/OTAweDYwMA', '307.7万'),new LinkDataModel(1, '荤菜', 786082, '糖醋排骨', 'https://s1.cdn.jiaonizuocai.com/videoImg/201509/0722/55ed97982b6fc.JPG/OTAweDYwMA', '3334.9万'),new LinkDataModel(1, '荤菜', 778097, '香辣牛肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/2613/261328491342.jpg/OTAweDYwMA', '140.0万'),new LinkDataModel(4, '素菜', 780102, '麻婆豆腐', 'https://s1.cdn.jiaonizuocai.com/videoImg/201509/0721/55ed95c20615a.JPG/OTAweDYwMA', '1706.6万'),new LinkDataModel(1, '荤菜', 785822, '宫保鸡丁', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/1310/561c71166b43e.jpg/OTAweDYwMA', '1442.2万'),new LinkDataModel(1, '荤菜', 816684, '土豆炖排骨', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/1115/111530241183.jpg/OTAweDYwMA', '812.7万'),new LinkDataModel(4, '素菜', 813538, '虎皮青椒', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/3010/301011441374.jpg/OTAweDYwMA', '739.1万'),new LinkDataModel(1, '荤菜', 777356, '菠萝咕噜肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/2119/081045069894.jpg/OTAweDYwMA', '333.6万'),new LinkDataModel(1, '荤菜', 805787, '秘制红焖羊肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201602/1917/191735075144.jpg/OTAweDYwMA', '200.6万'),new LinkDataModel(3, '家常菜', 785839, '蒜苔炒腊肉', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/1313/561c91d3a7653.jpg/OTAweDYwMA', '304.5万'),new LinkDataModel(2, '鱼类', 778786, '红烧鱼块', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/3112/311201167492.jpg/OTAweDYwMA', '865.1万'),new LinkDataModel(1, '荤菜', 884945, '四川辣子鸡', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/0820/082033178610.jpg/OTAweDYwMA', '119.0万'),new LinkDataModel(1, '荤菜', 869093, '水煮鱼', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/1201/12105013291.jpg/OTAweDYwMA', '576.8万'),new LinkDataModel(9, '主食', 841128, '四川担担面', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/2321/241506061981.jpg/OTAweDYwMA', '100.9万'),new LinkDataModel(1, '荤菜', 891830, '四川椒麻鸡', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/2010/201007216534.jpg/OTAweDYwMA', '89.3万'),new LinkDataModel(1, '荤菜', 832801, '豉汁蒸排骨', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1118/112329444160.jpg/OTAweDYwMA', '139.6万'),new LinkDataModel(2, '鱼类', 887384, '川味水煮鱼', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/1220/122045335648.jpg/OTAweDYwMA', '64.4万'),new LinkDataModel(1, '荤菜', 848610, '干煸牛肉丝', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1821/182152287631.jpg/OTAweDYwMA', '150.0万'),new LinkDataModel(1, '荤菜', 867697, '重庆辣子鸡', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/0804/080441068530.jpg/OTAweDYwMA', '115.1万'),new LinkDataModel(3, '家常菜', 775083, ' 鱼香肉丝', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/0715/071505539312.jpg/OTAweDYwMA', '200.2万'),new LinkDataModel(1, '荤菜', 876373, '辣子鸡丁', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/2723/272304117232.jpg/OTAweDYwMA', '220.7万'),new LinkDataModel(9, '主食', 778426, '豆角焖面', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/2013/5625d476b1d48.jpg/OTAweDYwMA', '716.6万'),new LinkDataModel(9, '主食', 785494, '葱油饼', 'https://s1.cdn.jiaonizuocai.com/caipu/201510/1811/181119578074.jpg/OTAweDYwMA', '348.7万'),new LinkDataModel(9, '主食', 778826, '油泼面', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/0322/032223367102.jpg/OTAweDYwMA', '904.2万'),new LinkDataModel(9, '主食', 814477, '韭菜盒子', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/0300/030002493912.jpg/OTAweDYwMA', '174.6万'),new LinkDataModel(9, '主食', 782948, '阳春面', 'https://s1.cdn.jiaonizuocai.com/caipu/201510/0110/011059237019.jpg/OTAweDYwMA', '82.4万'),new LinkDataModel(9, '主食', 769530, '海鲜意大利面', 'https://s1.cdn.jiaonizuocai.com/caipu/201506/2416/071619394874.jpg/OTAweDYwMA', '154.6万'),new LinkDataModel(9, '主食', 797708, '南瓜馒头', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/0609/06090112749.jpg/OTAweDYwMA', '146.1万'),new LinkDataModel(9, '主食', 807546, '旺仔小馒头', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/0215/021509133265.jpg/OTAweDYwMA', '55.5万'),new LinkDataModel(9, '主食', 791681, '红糖馒头', 'https://s1.cdn.jiaonizuocai.com/caipu/201512/0108/010831371861.jpg/OTAweDYwMA', '159.0万'),new LinkDataModel(9, '主食', 832780, '牛奶刀切馒头', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1117/111715571754.jpg/OTAweDYwMA', '34.3万'),new LinkDataModel(10, '汤类', 876125, '牛肉汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/2718/271828041490.jpg/OTAweDYwMA', '100.9万'),new LinkDataModel(10, '汤类', 771608, '西班牙蔬菜冷汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201507/1413/141314488556.jpg/OTAweDYwMA', '2.2万'),new LinkDataModel(10, '汤类', 780219, '奶油蘑菇汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201509/1116/111618148851.jpg/OTAweDYwMA', '112.5万'),new LinkDataModel(10, '汤类', 878722, '奶油南瓜浓汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/3017/071527326993.jpg/OTAweDYwMA', '28.4万'),new LinkDataModel(10, '汤类', 791832, '奶油蘑菇汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201512/0206/020647208391.jpg/OTAweDYwMA', '21.4万'),new LinkDataModel(10, '汤类', 882037, '蘑菇奶油浓汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/0414/041445309000.jpg/OTAweDYwMA', '58.0万'),new LinkDataModel(10, '汤类', 834075, '法式奶油蘑菇汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201605/1320/132010025630.jpg/OTAweDYwMA', '20.3万'),new LinkDataModel(10, '汤类', 893258, '奶油蘑菇汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/2214/221448417863.jpg/OTAweDYwMA', '12.6万'),new LinkDataModel(10, '汤类', 817885, '双孢菇奶油浓汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/1522/162208419460.jpg/OTAweDYwMA', '4.5万'),new LinkDataModel(10, '汤类', 805209, '奶油南瓜浓汤', 'https://s1.cdn.jiaonizuocai.com/caipu/201602/1515/151510239140.jpg/OTAweDYwMA', '8.7万'),new LinkDataModel(4, '素菜', 778804, '黄豆芽炒粉条', 'https://s1.cdn.jiaonizuocai.com/caipu/201508/3113/311309175276.jpg/OTAweDYwMA', '399.3万'),new LinkDataModel(3, '家常菜', 778433, '木耳炒鸡蛋', 'https://s1.cdn.jiaonizuocai.com/videoImg/201508/2720/55defe33a9f40.JPG/OTAweDYwMA', '415.9万'),new LinkDataModel(9, '主食', 780078, '疙瘩汤', 'https://s1.cdn.jiaonizuocai.com/videoImg/201509/0722/55ed9d661ae37.JPG/OTAweDYwMA', '745.0万'),new LinkDataModel(11, '虾蟹类', 782253, '清蒸大闸蟹', 'https://s1.cdn.jiaonizuocai.com/caipu/201509/2600/26001924238.jpg/OTAweDYwMA', '122.5万'),new LinkDataModel(2, '粥类', 825833, '皮蛋瘦肉粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201604/1820/182014224139.jpg/OTAweDYwMA', '278.8万'),new LinkDataModel(4, '素菜', 787717, '红烧冬瓜', 'https://s1.cdn.jiaonizuocai.com/videoImg/201510/3013/5632fdfbd19c5.jpg/OTAweDYwMA', '752.5万'),new LinkDataModel(3, '家常菜', 801048, '西红柿炒鸡蛋', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/1914/191406289.jpg/OTAweDYwMA', '624.1万'),new LinkDataModel(7, '凉菜', 808259, '凉拌金针菇', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/0613/061327511225.jpg/OTAweDYwMA', '198.8万'),new LinkDataModel(2, '粥类', 800443, '腊八粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/1709/170957578030.jpg/OTAweDYwMA', '139.0万'),new LinkDataModel(3, '家常菜', 847345, '肉末芥兰', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1512/151228169151.jpg/OTAweDYwMA', '13.6万'),new LinkDataModel(1, '荤菜', 847174, '猪肉脯', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1419/141923517247.jpg/OTAweDYwMA', '57.4万'),new LinkDataModel(7, '凉菜', 845554, '三文鱼蔬菜色拉', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/0900/090038146021.jpg/OTAweDYwMA', '17.7万'),new LinkDataModel(7, '凉菜', 847037, '咸蛋黄酿五花肉', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1413/141306187943.jpg/OTAweDYwMA', '49.3万'),new LinkDataModel(7, '凉菜', 847222, '凉拌空心菜', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1422/142204442229.jpg/OTAweDYwMA', '52.8万'),new LinkDataModel(11, '虾蟹类', 846778, '黄金蝴蝶虾', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/1315/131802164544.jpg/OTAweDYwMA', '38.5万'),new LinkDataModel(5, '烘焙', 886037, '软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/1016/101601068769.jpg/OTAweDYwMA', '36.9万'),new LinkDataModel(5, '烘焙', 930245, '软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201703/2308/230800452523.jpg/OTAweDYwMA', '9.7万'),new LinkDataModel(5, '烘焙', 787748, '香甜软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201511/0320/032019467036.jpg/OTAweDYwMA', '18.0万'),new LinkDataModel(5, '烘焙', 889806, '松软小面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/1623/171115558624.jpg/OTAweDYwMA', '8.8万'),new LinkDataModel(5, '烘焙', 849358, '香甜软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201606/2100/210017219022.jpg/OTAweDYwMA', '5.4万'),new LinkDataModel(5, '烘焙', 786799, '全麦软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201510/2718/081946527521.jpg/OTAweDYwMA', '5.8万'),new LinkDataModel(5, '烘焙', 892020, '超软全麦面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/2014/201441546363.jpg/OTAweDYwMA', '6.2万'),new LinkDataModel(5, '烘焙', 811829, '免揉超软小面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201603/2218/221853559099.jpg/OTAweDYwMA', '7.0万'),new LinkDataModel(5, '烘焙', 940790, '蛋糕软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201705/0822/082240456329.jpg/OTAweDYwMA', '1.9万'),new LinkDataModel(5, '烘焙', 798476, '椰香软面包', 'https://s1.cdn.jiaonizuocai.com/caipu/201601/0915/091541485253.jpg/OTAweDYwMA', '1.3万'),new LinkDataModel(2, '粥类', 889627, '鸡肉青菜粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/1617/161750058722.jpg/OTAweDYwMA', '15.2万'),new LinkDataModel(2, '粥类', 898289, '南瓜小米粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201610/1219/121934468146.jpg/OTAweDYwMA', '3.5万'),new LinkDataModel(2, '粥类', 926909, '八宝粥营养改良版', 'https://s1.cdn.jiaonizuocai.com/caipu/201703/0817/081716469456.jpg/OTAweDYwMA', '9.4万'),new LinkDataModel(2, '粥类', 892051, '小米红豆粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201609/2015/201530034501.jpg/OTAweDYwMA', '11.3万'),new LinkDataModel(2, '粥类', 874927, '香菇青菜粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/2615/261531387841.jpg/OTAweDYwMA', '22.4万'),new LinkDataModel(2, '粥类', 899937, '红枣山药豆粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201610/1917/19173957277.jpg/OTAweDYwMA', '25.0万'),new LinkDataModel(2, '粥类', 877626, '小米玉米粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/2913/291350153179.jpg/OTAweDYwMA', '8.4万'),new LinkDataModel(2, '粥类', 951982, '潮汕海鲜粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201707/1010/101030575958.jpg/OTAweDYwMA', '17.7万'),new LinkDataModel(2, '粥类', 876215, '砂锅皮蛋瘦肉粥', 'https://s1.cdn.jiaonizuocai.com/caipu/201608/2719/271951393632.jpg/OTAweDYwMA', '14.2万')
]
6. 功能实现
6.1. 首页面
// entry/src/main/ets/pages/Index.ets
import Constants from '../common/constants/Constants'
import ClassifyModel from '../viewModel/ClassifyModel'
import DishModel from '../viewModel/DishModel'
import DishItem from '../views/DishItem'
import ClassifyItem from '../views/ClassifyItem'
import ClassifyViewModel from '../viewModel/ClassifyViewModel'@Entry
@Component
struct IndexPage {// 2. 定义模拟延迟加载的变量@State requestSuccess: boolean = false@State currentClassify: number = 0// 5. 初始化数据-2private classifyList: Array<ClassifyModel> = []private classifyScroller: Scroller = new Scroller()private scroller: Scroller = new Scroller()aboutToAppear() {setTimeout(() => {// 5. 初始化数据-3this.classifyList = ClassifyViewModel.getLinkData()// 2. 模拟延迟加载-2this.requestSuccess = true}, Constants.LOADING_DURATION)}// 8. 定义 ClassifyHeader @Builder -2@Builder ClassifyHeader(classifyName: string) {Row() {Text(classifyName).fontSize($r('app.float.header_font_size')).fontColor($r('app.color.base_font_color')).fontFamily($r('app.string.hei_ti_medium')).fontWeight(Constants.TITLE_FONT_WEIGHT)}.padding({ left: $r('app.float.item_padding_left') }).height($r('app.float.classify_item_height')).width(Constants.FULL_PERCENT).backgroundColor($r('app.color.base_background'))}classifyChangeAction(index: number, isClassify: boolean): void {if (this.currentClassify !== index) {this.currentClassify = index;if (isClassify) {this.scroller.scrollToIndex(index);} else {this.classifyScroller.scrollToIndex(index);}}}build() {// 1. 定义容器Row() {// 2. 模拟延迟加载-1if (this.requestSuccess) {// 4. 渲染左边的分类列表List({ scroller: this.classifyScroller }) {// 5. 初始化数据-1ForEach(this.classifyList, (item: ClassifyModel, index?: number) => {ListItem() {ClassifyItem({// 6. TODO:定义ClassifyItem,只要一个classifyNameclassifyName: item.classifyName,isSelected: this.currentClassify === index,onClickAction: () => {if (index !== undefined) {this.classifyChangeAction(index, true);}}})}}, (item: ClassifyModel) => item.classifyName + this.currentClassify)}.height(Constants.FULL_PERCENT).width($r('app.float.classify_item_width')).backgroundColor($r('app.color.classify_background')).scrollBar(BarState.Off)// 7. 定义右边菜品列表List({ scroller: this.scroller }) {ForEach(this.classifyList, (classifyItem: ClassifyModel) => {ListItemGroup({// 8. 定义 ClassifyHeader @Builderheader: this.ClassifyHeader(classifyItem.classifyName),space: Constants.COURSE_ITEM_PADDING}) {ForEach(classifyItem.dishList, (dishItem: DishModel) => {ListItem() {// 9. TODO: 引用 DishItem,等待细化DishItem({ itemStr: JSON.stringify(dishItem) })}}, (dishItem: DishModel) => `${dishItem.dishId}`)}}, (item: ClassifyModel) => `${item.classifyId}`)}.height(Constants.FULL_PERCENT).width(Constants.FULL_PERCENT).padding({ left: $r('app.float.item_padding_left'), right: $r('app.float.dish_item_padding')}).sticky(StickyStyle.Header).layoutWeight(1).edgeEffect(EdgeEffect.None).onScrollIndex((start: number) => this.classifyChangeAction(start, false))} else {// 3. 延迟加载的话,显示一个loadingText($r('app.string.loading')).fontFamily($r('app.string.hei_ti_medium')).textAlign(TextAlign.Center).height(Constants.FULL_PERCENT).width(Constants.FULL_PERCENT)}}.backgroundColor($r('app.color.base_background'))}
}
6.2. 分类组件
// entry/src/main/ets/views/ClassifyItem.ets
import Constants from '../common/constants/Constants'@Component
export default struct ClassifyItem {classifyName?: string@Prop isSelected: boolean = falseonClickAction = (): void => {}build() {Text(this.classifyName).fontSize($r('app.float.normal_font_size')).fontColor(this.isSelected ? $r('app.color.base_font_color') : $r('app.color.normal_font_color')).fontFamily(this.isSelected ? $r('app.string.hei_ti_medium') : $r('app.string.hei_ti')).fontWeight(this.isSelected ? Constants.TITLE_FONT_WEIGHT : Constants.LABEL_FONT_WEIGHT).textAlign(TextAlign.Center).backgroundColor(this.isSelected ? $r('app.color.base_background') : '').width(Constants.FULL_PERCENT).height($r('app.float.classify_item_height')).onClick(this.onClickAction)}
}
6.3. 菜品组件
// entry/src/main/ets/views/DishItem.ets
import Constants from '../common/constants/Constants'
import DishModel from '../viewModel/DishModel'@Component
export default struct DishItem {@Prop itemStr: string = ''item?: DishModelaboutToAppear() {this.item = JSON.parse(this.itemStr) as DishModel;}build() {Row() {Image(this.item !== undefined ? this.item?.imageUrl : '').height(Constants.FULL_PERCENT).aspectRatio(1)Column() {Text(this.item?.dishName).fontSize($r('app.float.header_font_size')).fontColor($r('app.color.base_font_color')).fontFamily($r('app.string.hei_ti_medium')).maxLines(Constants.TITLE_LINE_NUMBER).textOverflow({ overflow: TextOverflow.Clip }).lineHeight($r('app.float.title_line_height')).width(Constants.FULL_PERCENT)Text() {Span($r('app.string.views_str'))Span(`: ${this.item?.views}`)}.fontSize($r('app.float.normal_font_size')).fontColor($r('app.color.price_color')).fontFamily($r('app.string.hei_ti_medium'))}.padding($r('app.float.dish_item_padding')).layoutWeight(1).alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceBetween).height(Constants.FULL_PERCENT)}.clip(true).borderRadius($r('app.float.normal_border_radius')).backgroundColor($r('app.color.start_window_background')).width('100%').height($r('app.float.dish_item_height'))}
}
6.4. 开启网络访问权限
// entry/src/main/module.json5
{"module": {// ..."requestPermissions": [{"name" : "ohos.permission.INTERNET"}]}
}
7. 代码与视频教程
完整案例代码与视频教程请参见:
代码:Code-05-03.zip。
视频:《实现菜谱二级联动导航》。