v0.8.3 头像显示 / 主题色标签 / 右侧贴边 / 简要卡片 / 浮层分离
用户 2026-10-18 第二批五条: ①「右上角的个人头像没显示。」 🔴 真根因:`/me` 与 `/login` 返回的 `avatar_url` 是**相对地址** (`media.php?k=avatars%2Fxxx.jpg` —— 不带域名、不带令牌), 那是给**浏览器**用的(同源 + cookie);`Image()` 要完整 URL ⇒ 加载失败。 真机日志:`GetAsset failed: media.php?k=avatars%2F20261002_...jpg` ⇒ 新增 `fbMediaUrl(raw, token)` 归一化,**三种形态都认** (绝对地址 / media.php 相对式 / 裸 key)—— 少认一种就会出现 "有的头像能显示、有的不能",那类 bug 最难查。 ⚠️ 不能复用 `fbImageSrc()`:那是"附件 key → 本地缓存"的通道, 把整条 URL 当 key 传进去会得到一个必然 404 的地址。 ②「名册、家谱这两个标签,用的不是主题色。」 🔴 两个调用点**各硬编码 `'#A84A28'`**(品牌砖红),而名册模块主题色是 `#4A7C82`(青)⇒ 与整页不在一个色系。 ⇒ `segBtn` 不再由调用方传色,内部取 `fbThemeVars(fbModuleOf('people').color).brand`; 顺手消掉"两处各写一遍字面量"这个漂移源。 ③「名册列表,左侧有空隙了……怎么右侧不是呢?右侧还是紧贴屏幕。」 🔴 实测(像素扫描):左米色 50~72px、**右米色 0px**。 根因是 `Row` 内 `layoutWeight(1)` 的子项默认 `min-width: auto` (按内容最小宽度)⇒ 长名字/多标签把**卡片布局盒撑破** ⇒ 右边越界贴屏幕 (左边先被 margin 占位、所以还留着空隙)。 ⇒ 弹性子项开 `flexShrink(1)`,姓名那行连同 `width('100%')`。 ④「点击列表,不打电话了,容易误触。而是弹出一个卡片,卡片中是头像、名称、 电话号码、邮箱等简要信息,下面三个按钮,详情、编辑和删除。…… 列表页面中,也不要详情按钮了。」 ⇒ 新建 `FbPersonQuickSheet`(@ComponentV2): 头像 / 姓名+称谓 / 电话(主号 + 其他)/ 邮箱 / 单位 / 生日 + 三个等宽按钮「详情 / 编辑 / 删除」。 ⇒ 点整行走 `openQuick()`(**不再拨号**);列表里的「详情」按钮**删除**。 ⇒ 删除走 `AlertDialog` **二次确认**(服务端物理删除、无回收站 ⇒ 误触不可逆), 文案带姓名("确定把「老杨」…")—— 误触时最需要"是不是点错了人"这个信息。 ⚠️ 两级浮层分开两个状态(`quickPerson` / `detailPerson`);详情关掉**回到简要卡**, 而不是一路退回列表。 ⑤「这个卡片,弹出来之后,是白色的,和下面的列表中的白色,都融合在一起, 根本看不出是弹框。」 🔴 原来只靠 `#00000066` 遮罩区分 —— 而本应用**列表本身就是大面积白底**, 白卡压在"被压暗的白"上边界仍发飘。 ⇒ **三层分离**:① 遮罩(宿主)② 卡片**阴影**(抬起来)③ 极浅**描边** (同色背景上仍有一条可见界线;只靠阴影在浅底上不够稳)。 ⚠️ 三个浮层(简要卡 / 详情 / 编辑)**同手段** —— 否则从简要卡切到编辑会突然"变平"。 验证:hvigor BUILD SUCCESSFUL;_fb_arkts_guard.js 377/0(新增 28 条, 另修 3 条旧判据);_fb_v59c_falsify.py 16 项注入 ⇒ 16/0。 ⚠️ 本轮反向验证又抓出 2 条假绿 + 1 条"没真注入",已逐条收紧(记入 pitfalls): · `flexShrink(1)` 在本页有**两处**(姓名 Text / 整个 Column)⇒ "出现过"型判据 删掉关键那处仍绿;改成锚"相邻关系"(`.layoutWeight(1)` 之后 220 字符内); · `showAlertDialog` 被 `if (false)` 包起来(确认框永不弹)⇒ 字符串还在、判据仍绿; 改成查因果(窗口内有 `value: '删除'` + `this.doDelete(who)`); · 有一条注入只改了注释、没删那行代码 ⇒ 报 [MISS],那是"注入没打到点上"。
This commit is contained in:
@@ -1033,6 +1033,11 @@ export struct FbPersonEditSheet {
|
||||
.padding(18)
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius(FbMetric.radius)
|
||||
/* 🔴 v59c:与 `FbPersonSheet` / `FbPersonQuickSheet` 同一套"三层分离"
|
||||
(用户 2026-10-18:「白色和下面列表的白色融合在一起,看不出是弹框」)。
|
||||
⚠️ 三个浮层必须**同手段**,否则从简要卡 → 编辑切过去会突然"变平"。 */
|
||||
.shadow({ radius: 24, color: '#00000033', offsetX: 0, offsetY: 6 })
|
||||
.border({ width: 1, color: '#00000014' })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* 家书 FamilyBook · 名册「简要卡片」(鸿蒙端)
|
||||
*
|
||||
* 🔴🔴 用户 2026-10-18 原话:
|
||||
* 「点击列表,不打电话了,容易误触。而是弹出一个卡片,卡片中是头像、
|
||||
* 名称、电话号码、邮箱等简要信息,下面三个按钮,详情、编辑和删除。」
|
||||
*
|
||||
* 为什么要单独一个组件(而不是在名册页里再写一个 `@Builder`):
|
||||
* · 它是**一张自己的卡**(与"完整详情"是两级),有自己的按钮组与布局;
|
||||
* · 名册页那个文件已经 1300+ 行,再往里塞会失控;
|
||||
* · 将来"从日程里点参会人"也可能要弹同一张卡 ⇒ 组件化才复用得上。
|
||||
*
|
||||
* 🔴 关于「弹框与下面列表都是白的、看不出是弹框」(用户同一条反馈里提的):
|
||||
* 本卡片的解法是**三层分离**(缺一层就会"糊在一起"):
|
||||
* ① 宿主给**深色遮罩**(见调用点,`#00000066`)—— 把下面的列表压暗;
|
||||
* ② 卡片自己**加阴影**(`shadow`)—— 与遮罩拉开"浮起来"的层次;
|
||||
* ③ 卡片底色用**纸白**、并给一圈**极浅描边** —— 即使在同色背景上,
|
||||
* 边缘也有一条可见的界线(只靠阴影在浅底上是不够的)。
|
||||
* ⚠️ 只做①(很多地方只做遮罩)在"背景也是大面积白"时效果最弱:
|
||||
* 白卡压在"被压暗的白"上,边界仍然发飘 —— 用户说的就是这种观感。
|
||||
*
|
||||
* ⚠️ 「删除」是**破坏性操作**,必须二次确认(见调用点的 `AlertDialog`)。
|
||||
* 卡片这里**只负责发事件**,不自己做确认也不自己调接口 ——
|
||||
* 与 `FbPersonSheet` 的做法一致(浮层之间不互相引用,免得成环)。
|
||||
*/
|
||||
|
||||
import { FbColors, FbMetric, fbTint, FbTint } from '../common/Theme';
|
||||
import { FbModuleDef, fbModuleOf, fbThemeVars } from '../model/Modules';
|
||||
import { FbRosterPerson } from '../data/FbPersonRepo';
|
||||
import { FbAvatar, FbTag } from './Widgets';
|
||||
import { fbMediaUrl } from '../data/FbHttp';
|
||||
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
||||
|
||||
/** 卡片阴影半径(与详情浮层同一档观感) */
|
||||
const CARD_SHADOW: number = 24;
|
||||
|
||||
/**
|
||||
* 「删除」用的红 —— 与 `resources/base/element/color.json` 的 `red` **同值**。
|
||||
*
|
||||
* ⚠️ 不能直接用 `FbColors.red`(那是 `Resource`):本文件要拿它拼
|
||||
* `RED + '1A'`(透明度后缀)做底色,`Resource` 拼不了字符串。
|
||||
* ⇒ 凡是要参与**颜色运算**的地方都用 hex(本项目已有 `FbTint` 这组先例)。
|
||||
* ⚠️ color.json 改色时这里要同步改(只有这一个值,风险可控)。
|
||||
*/
|
||||
const RED: string = '#C0533F';
|
||||
|
||||
@ComponentV2
|
||||
export struct FbPersonQuickSheet {
|
||||
/** 要看的人(null = 没打开) */
|
||||
@Param person: FbRosterPerson | null = null;
|
||||
|
||||
/** 关闭(点「关闭」或点遮罩) */
|
||||
@Event onClose: () => void = (): void => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 「详情」:进完整详情浮层。
|
||||
*
|
||||
* ⚠️ 本组件**不自己切浮层**:切法是"关掉简要卡、打开详情卡",
|
||||
* 那是页面的编排(它还管着遮罩/返回关系)。见调用点。
|
||||
*/
|
||||
@Event onDetail: () => void = (): void => {
|
||||
};
|
||||
|
||||
/** 「编辑」:进编辑浮层(同上,由页面编排) */
|
||||
@Event onEdit: () => void = (): void => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 「删除」:只发事件。
|
||||
* ⚠️ 二次确认与调接口都在页面侧 —— 那里才知道"删完怎么刷新列表"。
|
||||
*/
|
||||
@Event onDelete: () => void = (): void => {
|
||||
};
|
||||
|
||||
/** 名册模块的主题色(按钮配色与整个名册页同一个色系) */
|
||||
private brand(): string {
|
||||
const m: FbModuleDef | undefined = fbModuleOf('people');
|
||||
return fbThemeVars(m !== undefined ? m.color : '#A84A28').brand;
|
||||
}
|
||||
|
||||
/** 姓名(昵称优先,与列表一致) */
|
||||
private title(): string {
|
||||
return this.person !== null
|
||||
? (this.person.shown !== '' ? this.person.shown : this.person.name)
|
||||
: '';
|
||||
}
|
||||
|
||||
/** 头像地址(**必须是完整 URL**,见 fbMediaUrl 的说明) */
|
||||
private avatarSrc(): string {
|
||||
if (this.person === null) {
|
||||
return '';
|
||||
}
|
||||
return fbMediaUrl(this.person.avatar, FB_TOKEN_STORE.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 主电话(`phones` 由服务端保证「主号排第一」)。
|
||||
* ⚠️ 用 `phones` 而不是 `phone`:后者只是 `phones[0]` 的便捷别名,
|
||||
* 而这里要显示**这一条能不能点**,显式用数组语义更清楚。
|
||||
*/
|
||||
private mainPhone(): string {
|
||||
if (this.person === null) {
|
||||
return '';
|
||||
}
|
||||
const arr: string[] = this.person.phones;
|
||||
return arr.length > 0 ? arr[0] : '';
|
||||
}
|
||||
|
||||
/** 其余电话(第 2 个起,逗号连接;没有就给空串) */
|
||||
private otherPhones(): string {
|
||||
if (this.person === null) {
|
||||
return '';
|
||||
}
|
||||
const arr: string[] = this.person.phones;
|
||||
if (arr.length <= 1) {
|
||||
return '';
|
||||
}
|
||||
const rest: string[] = [];
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
rest.push(arr[i]);
|
||||
}
|
||||
return rest.join(' / ');
|
||||
}
|
||||
|
||||
/** 生日显示串(阳历优先,其次农历;都没有给空串) */
|
||||
private birthdayText(): string {
|
||||
if (this.person === null) {
|
||||
return '';
|
||||
}
|
||||
if (this.person.birthdaySolar !== '') {
|
||||
return this.person.birthdaySolar;
|
||||
}
|
||||
return this.person.birthdayLunar;
|
||||
}
|
||||
|
||||
/** 单位 + 职务合成一行(都没有给空串) */
|
||||
private jobText(): string {
|
||||
if (this.person === null) {
|
||||
return '';
|
||||
}
|
||||
const org: string = this.person.org;
|
||||
const title: string = this.person.title;
|
||||
if (org !== '' && title !== '') {
|
||||
return org + ' · ' + title;
|
||||
}
|
||||
return org !== '' ? org : title;
|
||||
}
|
||||
|
||||
/** 一行「图标 + 标签 + 值」 */
|
||||
@Builder
|
||||
infoRow(icon: Resource, label: string, value: string) {
|
||||
Row({ space: 10 }) {
|
||||
Image(icon)
|
||||
.width(16)
|
||||
.height(16)
|
||||
/* ⚠️ 本工程图标是 PNG ⇒ 必须 colorFilter(fillColor 只对 SVG 生效) */
|
||||
.colorFilter(fbTint(FbTint.faint))
|
||||
Text(label)
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.faint)
|
||||
.width(52)
|
||||
Text(value)
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.ink)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个动作按钮。
|
||||
*
|
||||
* ⚠️ 三个按钮等宽平分(`layoutWeight(1)`)—— 用户要"下面三个按钮",
|
||||
* 等宽是最不容易出错、也最像"选择"的排法。
|
||||
*/
|
||||
/**
|
||||
* 一个动作按钮。
|
||||
*
|
||||
* ⚠️ `fg`/`bg` 必须是 **hex 字符串**(不是 `Resource`):
|
||||
* 这里要拿它做**颜色运算**(`bg + '1A'` 加透明度后缀),
|
||||
* `Resource` 参与不了字符串拼接。红色那个因此用与
|
||||
* `color.json` 的 `red` **同值**的字面量(见 `RED`)。
|
||||
*/
|
||||
@Builder
|
||||
actionBtn(label: string, fg: string, bg: string, fire: () => void) {
|
||||
Text(label)
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(fg)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.textAlign(TextAlign.Center)
|
||||
.height(38)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor(bg)
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
.onClick((): void => {
|
||||
fire();
|
||||
})
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Column({ space: 14 }) {
|
||||
// ---- 头像 + 姓名 + 称谓 ----
|
||||
Row({ space: 14 }) {
|
||||
FbAvatar({
|
||||
name: this.person !== null ? this.person.name : '',
|
||||
color: this.person !== null ? this.person.avatarColor : '#A84A28',
|
||||
dia: 54,
|
||||
fontSizeVp: 22,
|
||||
imageUrl: this.avatarSrc()
|
||||
})
|
||||
Column({ space: 5 }) {
|
||||
Row({ space: 8 }) {
|
||||
Text(this.title())
|
||||
.fontSize(FbMetric.fontTitle)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.fontColor(FbColors.ink)
|
||||
.maxLines(1)
|
||||
.flexShrink(1)
|
||||
if (this.person !== null && this.person.label !== '') {
|
||||
FbTag({ text: this.person.label, tone: 'muted' })
|
||||
}
|
||||
}
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.width('100%')
|
||||
|
||||
if (this.person !== null && this.person.name !== this.title()) {
|
||||
Text('本名 ' + this.person.name)
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.muted)
|
||||
}
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.layoutWeight(1)
|
||||
.flexShrink(1)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// ---- 简要信息(电话 / 邮箱 / 单位 / 生日;有才显示)----
|
||||
Column({ space: 10 }) {
|
||||
if (this.mainPhone() !== '') {
|
||||
this.infoRow($r('app.media.fb_ic_user'), '电话', this.mainPhone())
|
||||
}
|
||||
if (this.otherPhones() !== '') {
|
||||
this.infoRow($r('app.media.fb_ic_user'), '其他', this.otherPhones())
|
||||
}
|
||||
if (this.person !== null && this.person.email !== '') {
|
||||
this.infoRow($r('app.media.fb_ic_notes'), '邮箱',
|
||||
this.person !== null ? this.person.email : '')
|
||||
}
|
||||
if (this.jobText() !== '') {
|
||||
this.infoRow($r('app.media.fb_ic_people'), '单位', this.jobText())
|
||||
}
|
||||
if (this.birthdayText() !== '') {
|
||||
this.infoRow($r('app.media.fb_ic_days'), '生日', this.birthdayText())
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
// ---- 三个动作:详情 / 编辑 / 删除 ----
|
||||
//
|
||||
// ⚠️ 「删除」用红色(语义色),其余两个是主题色的深浅两档:
|
||||
// 同一组按钮里,"哪个是破坏性的"必须一眼看出来。
|
||||
Row({ space: 10 }) {
|
||||
this.actionBtn('详情', FbTint.white, this.brand(), (): void => {
|
||||
this.onDetail();
|
||||
})
|
||||
this.actionBtn('编辑', this.brand(), this.brand() + '1A', (): void => {
|
||||
this.onEdit();
|
||||
})
|
||||
this.actionBtn('删除', RED, RED + '1A', (): void => {
|
||||
this.onDelete();
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
// ---- 关闭 ----
|
||||
Text('关闭')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.muted)
|
||||
.textAlign(TextAlign.Center)
|
||||
.width('100%')
|
||||
.height(38)
|
||||
.backgroundColor(FbColors.inputBg)
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
.onClick((): void => {
|
||||
this.onClose();
|
||||
})
|
||||
}
|
||||
/* 🔴 卡片本体:见文件头「三层分离」的说明。
|
||||
⚠️ `width('92%')` + 四角圆角 + 居中 —— 与 `FbPersonSheet` 同一套观感
|
||||
(用户 2026-10-16 定:"圆角浮窗式、不占满宽、浮在屏幕中间")。 */
|
||||
.width('92%')
|
||||
.constraintSize({ maxHeight: '72%' })
|
||||
.padding({ left: 18, right: 18, top: 18, bottom: 18 })
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius(FbMetric.radius)
|
||||
/* ② 阴影:把卡片从"被压暗的列表"上抬起来 */
|
||||
.shadow({ radius: CARD_SHADOW, color: '#00000033', offsetX: 0, offsetY: 6 })
|
||||
/* ③ 极浅描边:同色背景上仍有一条可见界线(只靠阴影在浅底上不够) */
|
||||
.border({ width: 1, color: '#00000014' })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
/* ⚠️ 透明命中:让点击"卡片以外的区域"能穿透到宿主的遮罩上(点遮罩关卡片)。
|
||||
不设的话这一层会把空白处也吃掉,点空白关不掉(很别扭)。 */
|
||||
.hitTestBehavior(HitTestMode.Transparent)
|
||||
}
|
||||
}
|
||||
@@ -501,6 +501,19 @@ export struct FbPersonSheet {
|
||||
})
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius(FbMetric.radius)
|
||||
/* 🔴 v59c(用户 2026-10-18):「这个卡片弹出来之后是白色的,和下面列表
|
||||
* 中的白色都融合在一起,根本看不出是弹框。」
|
||||
*
|
||||
* 原因:原来只靠宿主那层 `#00000066` 遮罩区分 —— 而本应用**列表本身
|
||||
* 就是大面积白底**,白卡压在"被压暗的白"上,边界仍然发飘。
|
||||
* ⇒ 补两手(与 `FbPersonQuickSheet` 完全同一套,两级浮层观感一致):
|
||||
* ① 阴影:把卡片从背景上**抬起来**(有投影才有"浮在空中"的暗示);
|
||||
* ② 极浅描边:同色背景上仍然有一条**可见的界线**。
|
||||
* ⚠️ 只加阴影是不够的:浅色底上的投影很淡,真机上常常看不出来;
|
||||
* 描边才是"稳"的那一手(它不依赖光照假设)。
|
||||
*/
|
||||
.shadow({ radius: 24, color: '#00000033', offsetX: 0, offsetY: 6 })
|
||||
.border({ width: 1, color: '#00000014' })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
/* 🔴 embedded(宿主自己就是 sheet)时**不能再铺满 + 居中**:
|
||||
|
||||
@@ -26,6 +26,7 @@ import { FbPersonSheet } from './FbPersonSheet';
|
||||
// `FB_TOKEN_STORE` 在 **FbTokenStore.ets** 里(不是在 FbDeviceStore)。
|
||||
import { FbPersonRepo, FbRosterPerson } from '../data/FbPersonRepo';
|
||||
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
||||
import { fbMediaUrl } from '../data/FbHttp';
|
||||
import { syncAll } from '../data/FbSyncAll';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
@@ -221,9 +222,21 @@ export struct FbTopBar {
|
||||
color: this.app.session.me.avatarColor,
|
||||
dia: 32,
|
||||
fontSizeVp: 14,
|
||||
imageUrl: this.app.session.me.avatarUrl !== undefined
|
||||
? this.app.session.me.avatarUrl
|
||||
: ''
|
||||
/* 🔴🔴 v59c(用户 2026-10-18):「右上角的个人头像没显示。」
|
||||
*
|
||||
* 真根因:`/me` 与 `/login` 返回的 `avatar_url` 是
|
||||
* **相对地址**(`media.php?k=avatars%2Fxxx.jpg` —— 不带域名)——
|
||||
* 那是给浏览器用的(同源 + cookie),而 `Image()` 要完整 URL
|
||||
* ⇒ 直接加载失败。真机日志:`GetAsset failed: media.php?k=...`
|
||||
*
|
||||
* ⇒ 用 `fbMediaUrl()` 归一化成本机可访问的完整地址
|
||||
* (它同时认"绝对地址 / media.php 相对式 / 裸 key"三种形态)。
|
||||
*
|
||||
* ⚠️ 不要用 `fbImageSrc()`(那是给**附件 key** 用的,走本地缓存):
|
||||
* 这里拿到的是 URL,不是 key —— 传进去会把整条 URL 当 key 编码,
|
||||
* 变成必然 404 的地址。
|
||||
*/
|
||||
imageUrl: fbMediaUrl(this.myAvatarRaw(), FB_TOKEN_STORE.get())
|
||||
})
|
||||
}
|
||||
.width(40)
|
||||
@@ -307,6 +320,19 @@ export struct FbTopBar {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的原始头像地址(服务端给的那个,可能是相对式)。
|
||||
*
|
||||
* ⚠️ 单独抽成方法而不是在组件参数里写三目:`@Builder`/组件参数的括号里
|
||||
* 塞多行表达式会让 ArkTS 编译器解析错乱(本项目踩过,报的却是无关的
|
||||
* `comma operator` / `standalone this`)。
|
||||
*/
|
||||
private myAvatarRaw(): string {
|
||||
return this.app.session.me.avatarUrl !== undefined
|
||||
? this.app.session.me.avatarUrl
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开「我」的详情浮层(点右上角头像触发)。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user