本篇案例主要介绍如何基于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 = 400
static readonly TITLE_FONT_WEIGHT: number = 500
static readonly COURSE_ITEM_PADDING: number = 12
static readonly LOADING_DURATION: number = 2000
static readonly TITLE_LINE_NUMBER: number = 2
static 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: number
dishId: number
dishName: string
imageUrl: string
views: string
constructor(
classifyId: number, dishId: number, dishName: string,
imageUrl: string, views: string
) {
this.classifyId = classifyId
this.dishId = dishId
this.dishName = dishName
this.imageUrl = imageUrl
this.views = views
}
}
5.2. 分类模型:ClassifyModel
// entry/src/main/ets/viewModel/ClassifyModel.ets
import DishModel from './DishModel'
export default class ClassifyModel {
classifyId: number
classifyName: string
dishList: Array<DishModel>
constructor(
classifyId: number, classifyName: string, dishList: Array<DishModel>
) {
this.classifyId = classifyId
this.classifyName = classifyName
this.dishList = dishList
}
}
5.3. 数据初始化模型:LinkDataModel
// entry/src/main/ets/viewModel/LinkDataModel.ets
export default class LinkDataModel {
superId: number
superName: string
id: number
dishName: string
imageUrl: string
views: string
constructor(superId: number, superName: string, id: number,
dishName: string, imageUrl: string, views: string) {
this.superId = superId
this.superName = superName
this.id = id
this.dishName = dishName
this.imageUrl = imageUrl
this.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 = 0
LINK_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 ClassifyViewModel
const 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. 初始化数据-2
private classifyList: Array<ClassifyModel> = []
private classifyScroller: Scroller = new Scroller()
private scroller: Scroller = new Scroller()
aboutToAppear() {
setTimeout(() => {
// 5. 初始化数据-3
this.classifyList = ClassifyViewModel.getLinkData()
// 2. 模拟延迟加载-2
this.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. 模拟延迟加载-1
if (this.requestSuccess) {
// 4. 渲染左边的分类列表
List({ scroller: this.classifyScroller }) {
// 5. 初始化数据-1
ForEach(this.classifyList, (item: ClassifyModel, index?: number) => {
ListItem() {
ClassifyItem({
// 6. TODO:定义ClassifyItem,只要一个classifyName
classifyName: 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 @Builder
header: 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. 延迟加载的话,显示一个loading
Text($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 = false
onClickAction = (): 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?: DishModel
aboutToAppear() {
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。