HarmonyOS 应用 · 室友评价评价页深度解析:四维星级打分与不可变更新
HarmonyOS 应用 · 室友评价评价页深度解析:四维星级打分与不可变更新
项目编号:50-roommate-rate 技术栈:HarmonyOS ArkTS · ArkUI 声明式 UI · Stage 模型 本篇页面:评价页
Func1Tab.ets(104 行) 系列导航:(一)首页 · (二)评价 · (三)数据 · (四)我的

一、RateDim interface 与 scores 数组状态
interface RateDim {
id: number;
emoji: string;
name: string;
score: number;
}
四个字段:id 是 key 锚点,emoji 是维度图标,name 是维度名,score 是默认分值。
@State activeMate: number = 0;
@State scores: number[] = [5, 4, 5, 4];
private mates: string[] = ['阿强', '小明', '大伟'];
private dims: RateDim[] = [
{ id: 1, emoji: '🧹', name: '卫生习惯', score: 5 },
{ id: 2, emoji: '🌙', name: '作息规律', score: 4 },
{ id: 3, emoji: '🤝', name: '相处融洽', score: 5 },
{ id: 4, emoji: '🔊', name: '安静程度', score: 4 }
];
两个 @State:activeMate(选中室友索引)+ scores(四维评分数组 [5,4,5,4])。mates 是被评价室友(不含自己),dims 是四个评价维度:卫生习惯/作息规律/相处融洽/安静程度。scores 数组与 dims 数组索引对应——scores[0] 是 dims[0] 的评分。
二、setScore:不可变更新触发星级刷新
private setScore(idx: number, s: number): void {
this.scores[idx] = s;
this.scores = this.scores.slice();
}
setScore(idx, s) 两步不可变更新——先赋值 scores[idx] = s,再 slice() 生成新引用触发 @State 刷新。与班级任务首页的 toggle 同款模式:直接修改数组元素不触发刷新,必须 slice() 换引用。
三、页面骨架:MateSelect + RateCard + CommentCard + Button
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 16 }) {
this.MateSelect()
this.RateCard()
this.CommentCard()
Button('提交评价').fontSize(15).fontColor('#FFFFFF').backgroundColor(C.primary)
.width('100%').height(48).borderRadius(D.rMd)
.onClick(() => { promptAction.showToast({ message: '评价已提交' }); })
}
.width('100%')
.padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad + this.safeBottom + 20 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
}
.width('100%').height('100%').backgroundColor(C.bg)
}
Header 在 Scroll 外固定,Scroll 内四块:MateSelect(室友选择)+ RateCard(评分卡)+ CommentCard(留言卡)+ Button(提交)。
四、MateSelect:activeMate 驱动的等分胶囊
@Builder
MateSelect() {
Row({ space: 10 }) {
ForEach(this.mates, (m: string, idx: number) => {
Text(m).fontSize(13)
.fontColor(this.activeMate === idx ? '#FFFFFF' : C.textSub)
.textAlign(TextAlign.Center).layoutWeight(1).padding({ top: 10, bottom: 10 })
.backgroundColor(this.activeMate === idx ? C.primary : C.card).borderRadius(D.rSm)
.border({ width: 1, color: this.activeMate === idx ? C.primary : C.stroke })
.onClick(() => { this.activeMate = idx; })
}, (m: string) => m)
}.width('100%')
}
activeMate === idx 驱动选中态:靛蓝底白字 + 靛蓝描边 vs 白底灰字 + 浅灰描边。三个室友等分,onClick 设 this.activeMate = idx 切换被评价对象。

五、RateCard:嵌套 ForEach 星级打分
@Builder
RateCard() {
Column({ space: 16 }) {
Text('评分维度').fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
ForEach(this.dims, (d: RateDim, dimIdx: number) => {
Row({ space: 10 }) {
Text(d.emoji).fontSize(20)
Text(d.name).fontSize(14).fontColor(C.text).layoutWeight(1)
Row({ space: 4 }) {
ForEach([1, 2, 3, 4, 5], (star: number) => {
Text(this.scores[dimIdx] >= star ? '⭐' : '☆').fontSize(16)
.onClick(() => { this.setScore(dimIdx, star); })
}, (star: number) => star.toString())
}
}.width('100%')
}, (d: RateDim) => d.id.toString())
}
.width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}
嵌套 ForEach——外层遍历维度,内层遍历 [1,2,3,4,5] 星级:
// 外层:4 个评价维度
ForEach(this.dims, (d: RateDim, dimIdx: number) => {
// 内层:5 颗星
ForEach([1, 2, 3, 4, 5], (star: number) => {
// scores[dimIdx] >= star → 实心星,否则空心星
Text(this.scores[dimIdx] >= star ? '⭐' : '☆')
.onClick(() => { this.setScore(dimIdx, star); })
})
})
scores[dimIdx] >= star 驱动实心/空心星——scores[0] = 5 时 5 颗全实心,scores[1] = 4 时前 4 颗实心 + 第 5 颗空心。点击第 3 颗星调 setScore(dimIdx, 3)——scores[dimIdx] 变 3,前 3 颗实心 + 后 2 颗空心。这是星级打分的经典实现:比较驱动渲染,点击驱动赋值。

六、CommentCard:TextArea 留言
@Builder
CommentCard() {
Column({ space: 10 }) {
Text('评价留言').fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
TextArea({ placeholder: '写下对室友的评价...' })
.backgroundColor(C.cardSoft).borderRadius(D.rSm).height(90)
}
.width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}
TextArea 多行输入,height(90) 容纳多行评价文字。cardSoft 浅灰底 + rSm 小圆角。

七、可演进方向
| 方向 | 现状 | 改法 | 收益 |
|---|---|---|---|
| 评价提交 | Toast 模拟 | 写入评价记录 + 评分更新 | 评价真实保存 |
| 室友切换 | scores 不重置 | 切换时加载该室友已有评分 | 切换不丢失数据 |
| 评分校验 | 无 | 至少一个维度打分才能提交 | 评价完整性 |
| 留言绑定 | TextArea 无 onChange | 绑定 remark 状态 | 留言随提交保存 |
| 多轮评价 | 单次 | 记录评价时间 + 历史追溯 | 评价可回溯 |
评价页是室友评价的核心交互——activeMate 驱动室友切换、嵌套 ForEach 实现星级打分、setScore 的不可变更新触发星级刷新。从比较驱动的实心/空心星到 slice() 的数组刷新,每一层都有明确的职责边界。

更多推荐



所有评论(0)