前言之前的 3D 拆解分析是完全开放的——打开就能用不需要任何身份验证。这在 demo 阶段没问题但一旦要接入网络功能发现页、AI 分析、历史记录就需要知道当前用户是谁。这次迭代做了两件事接入 AuthService未登录用户强制跳转登录页全面引入毛玻璃frosted glass视觉风格——半透明背景 全局渐变登录守卫AuthService 接入import{isLoggedIn}from../services/AuthService新增AuthService的isLoggedIn方法——返回当前用户是否已登录。aboutToAppear 的守卫aboutToAppear():void{if(!isLoggedIn()){router.pushUrl({url:pages/LoginPage})return}this.loadDiscover()}App 启动时先检查登录状态未登录 → 跳转 LoginPagereturn不执行后续逻辑已登录 → 正常加载发现页数据onPageShow 的二次检查onPageShow():void{if(!isLoggedIn()){router.pushUrl({url:pages/LoginPage})}}除了启动时检查每次页面重新显示时也检查。这防止了一种情况用户在 App 运行期间退出登录比如在设置页点了退出回到首页时应该被踢到登录页。为什么用 router.pushUrl 而不是 router.replaceUrlrouter.pushUrl({url:pages/LoginPage})pushUrl会把 LoginPage 压入导航栈。用户登录成功后可以router.back()回到首页。如果用replaceUrlLoginPage 会替换首页。用户登录后无法返回——因为首页已经不在导航栈里了。登录状态对功能的影响StateloggedIn:booleanfalse虽然定义了loggedIn状态变量但当前代码没有用它做条件渲染。所有功能发现页、AI 分析在登录后都可以使用。后续如果要做未登录只能看 3 个发现项登录后看全部可以用loggedIn控制。全局渐变背景旧版纯色背景.width(100%).height(100%).backgroundColor(BG)// BG #E6E0F0新版全局渐变.width(100%).height(100%).linearGradient({angle:160,colors:[[#F0EDF8,0],[#E8F0FE,0.5],[#FFF5EE,1]]})三色渐变起点0%#F0EDF8—— 淡紫中间50%#E8F0FE—— 淡蓝终点100%#FFF5EE—— 淡橙角度 160°——从左上到右下不是正上方到正下方。为什么是 160° 而不是 180°180° 是正上方到正下方渐变会显得太规整。160° 稍微偏一点让渐变方向和用户阅读方向从左到右更一致视觉上更自然。三种颜色的搭配逻辑紫色#F0EDF8→ 蓝色#E8F0FE→ 橙色#FFF5EE是色轮上的相邻色。从冷色到暖色的过渡给用户一种从理性到感性的心理暗示——左边是数据紫色科技右边是体验橙色温暖。毛玻璃视觉体系核心概念毛玻璃frosted glass的本质是半透明白色背景 极淡边框 微弱阴影。// 统一的毛玻璃样式.backgroundColor(rgba(255,255,255,0.65))// 65% 不透明度.border({width:1,color:rgba(138,93,250,0.08)})// 极淡紫色边框.shadow({radius:18,color:rgba(138,93,250,0.06),offsetY:3})// 紫色阴影各组件的毛玻璃实现统计卡片// 旧版.backgroundColor(CW)// 纯白// 新版.backgroundColor(rgba(255,255,255,0.70))// 70% 白控制面板// 旧版.backgroundColor(CW)// 新版.backgroundColor(rgba(255,255,255,0.80)).border({width:1,color:rgba(138,93,250,0.06)}).shadow({radius:10,color:rgba(138,93,250,0.04),offsetY:2})功能按钮// 旧版.backgroundColor(this.list?AL:#F5F5F7)// 新版FeatureBtn.backgroundColor(active?bgColor:#F5F5F7)部件清单// 旧版.backgroundColor(CW)// 新版.backgroundColor(rgba(255,255,255,0.60)).border({width:0.5,color:rgba(138,93,250,0.06)})透明度的层次不同组件用了不同的透明度组件透明度为什么统计卡片70%需要足够不透明才能看清文字控制面板80%滑块和按钮需要高对比度工作区65%需要透出背景渐变部件清单60%内容密度高需要更多透明度减轻视觉重量越需要看清内容的组件透明度越高越接近纯白。越需要融入背景的组件透明度越低越透明。点阵网格回归旧版的点阵之前有过 DotData 的点阵模式后来被粒子场替代。这次又加回来了——但实现方式不同。新版的点阵// 生成点阵数据constdlist:DotData[][]for(letr:number0;r12;r){for(letc:number0;c8;c){dlist.push({x:(c*12.56).toString()%,y:(r*8.34).toString()%})}}this.dotsdlist8 列 × 12 行 96 个点用百分比定位。点阵的渲染ForEach(this.dots,(d:DotData){Circle({width:2,height:2}).fill(rgba(138,93,250,0.15)).position({x:d.x,y:d.y})})每个点是 2×2 的紫色圆形15% 透明度。为什么点阵比粒子场更适合性能点阵是静态的不消耗 CPU 做动画可控点的位置和密度可以精确控制简洁不会干扰用户对内容的注意力粒子场虽然酷炫但作为工作区背景太吵了——用户需要专注看爆炸效果不需要背景在动。FeatureBtn功能按钮的统一旧版三个独立按钮Row(){// AI 分析按钮Row(){Text().fontSize(13).margin({right:2})Text(this.aiLoading?分析中...:AI 分析).fontSize(11)...}.padding(...).backgroundColor(...).onClick(...)// 部件清单按钮Row(){Text(☰).fontSize(12).fontColor(...)Text( 部件).fontSize(11)...}.padding(...).backgroundColor(...).onClick(...)Blank()// 重置按钮Row(){Text( 重置).fontSize(11)...}.padding(...).backgroundColor(...).onClick(...)}每个按钮的样式都手写一遍代码重复。新版FeatureBtn BuilderBuilderFeatureBtn(icon:string,label:string,active:boolean,bgColor:string,action:()void){Row(){Text(icon).fontSize(12)Text( label).fontSize(10).fontWeight(FontWeight.Medium).fontColor(active?A:T2)}.padding({left:10,right:10,top:6,bottom:6}).backgroundColor(active?bgColor:#F5F5F7).borderRadius(12).layoutWeight(1).justifyContent(FlexAlign.Center).onClick(action)}调用方式Row({space:6}){this.FeatureBtn(,this.aiLoading?分析中:AI 识别,this.aiLoading,AL,(){if(!this.aiLoading){this.runAiAnalysis()}})this.FeatureBtn(,部件清单,this.list,AL,(){this.list!this.list})this.FeatureBtn(,重置,false,#F5F5F7,(){this.setV(0);this.cg(3,3)})}FeatureBtn 的设计layoutWeight(1)—— 三个按钮等宽active控制颜色——激活时用主题色背景否则用灰色bgColor参数——不同按钮可以有不同的激活背景色重置按钮的特殊处理this.FeatureBtn(,重置,false,#F5F5F7,(){this.setV(0);this.cg(3,3)})重置按钮的active永远是false——它不会处于激活状态。bgColor传#F5F5F7灰色因为重置不需要强调色。拆解页 Header 的变化Tag 新增爆炸状态Row({space:6}){this.Tag(#8A5DFA,#F4F1FC,this.count部件)this.Tag(#00B894,#E8F8F5,this.cols×this.rows)if(this.on){this.Tag(#FF6B6B,#FFF0F0,Math.round(this.val*100)%)}}爆炸时新增第三个 Tag红色背景 百分比数字。用户一眼就能看到当前爆炸力度是多少。空状态的数字放大// 旧版Text(this.count.toString()).fontSize(44)// 新版Text(this.count.toString()).fontSize(48)从 44px 增大到 48px——空状态的数字是视觉焦点大一点更有冲击力。网格预览的样式微调// 旧版.backgroundColor(rgba(138,93,250,0.08)).border({width:1.5,color:rgba(138,93,250,0.15)})// 新版.backgroundColor(rgba(138,93,250,0.06)).border({width:1.5,color:rgba(138,93,250,0.12)})背景和边框都降低了约 25% 的不透明度——点阵网格已经提供了背景纹理网格预览不需要那么显眼。踩坑记录1. isLoggedIn 的调用时机aboutToAppear():void{if(!isLoggedIn()){router.pushUrl({url:pages/LoginPage})return}this.loadDiscover()}isLoggedIn()是同步调用——它读取本地存储的登录状态。如果后续改成异步比如需要验证 token 有效性需要用async/awaitaboutToAppear():asyncvoid{constloggedInawaitisLoggedIn()if(!loggedIn){router.pushUrl({url:pages/LoginPage})return}this.loadDiscover()}2. onPageShow 的重复检查onPageShow在每次页面显示时都会调用。如果用户快速切换 TabisLoggedIn()会被频繁调用。优化方案在aboutToAppear中缓存登录状态onPageShow只在状态变化时检查。3. 毛玻璃在低端设备上的性能半透明背景rgba(255,255,255,0.65)需要 GPU 做 alpha 混合。在低端设备上如果同时有多个半透明层叠可能导致掉帧。建议在性能敏感的场景比如爆炸动画进行中可以把工作区背景改成纯白减少 alpha 混合的层数。4. 点阵的 ForEach 性能96 个点用ForEach渲染——每个点都是一个独立的Circle组件。如果点阵更密比如 20×20 400 个点可能影响渲染性能。优化方案把点阵画在一张 Canvas 上而不是用 96 个独立组件。写在最后登录守卫让 App 从公开工具变成了用户产品。用户需要注册才能使用这意味着后续可以做个性化功能——保存分析历史、分享到发现页、AI 分析的调用次数限制。毛玻璃视觉体系让整个 App 的视觉语言统一了。从首页的统计卡片到拆解页的控制面板所有组件都用同样的半透明白色 极淡紫色边框。用户在不同页面之间切换时视觉感受是一致的。点阵网格的回归说明了一个道理酷炫的动效粒子场不一定比静态的纹理点阵好。在需要用户专注的场景安静的背景比吵闹的背景更合适。