时间轨迹第 2 篇:时间地点页源代码拆解,自动水印、手动地址与历史记录如何闭环

时间轨迹第 2 篇:时间地点页源代码拆解,自动水印、手动地址与历史记录如何闭环 时间轨迹第 2 篇时间地点页源代码拆解自动水印、手动地址与历史记录如何闭环这一篇讲的是TimeLocationPage.ets。它表面上像一个设置页实际上是拍照水印的“前置上下文中心”。时间、地点、模板、手动地址、历史地址都会在这里先准备好再交给相机页合成。系列导航第 1 篇首页、路由、登录与启动闭环第 3 篇相机页源代码拆解第 4 篇工作记录页源码导览第 5 篇工程底座源码导览摘要时间地点页的作用不是“让用户随便点几个开关”而是把拍摄时最常用的上下文统一组织起来自动水印是否开启时间是否显示地址是否显示当前模板选哪一个是否允许手动覆盖定位地址地址历史如何保存和回收如果把它压缩成一句话就是先把拍照时要用的上下文准备好再交给CameraPage去落地。目录页面关系状态拆分预览刷新模板卡片历史地址手动地址与相机页联动实操检查清单参考资料一、先看页面关系HomePage 时间地点入口TimeLocationPagewmAutoWatermarkwmShowTimewmShowAddresswmManualLocationwmLocationHistoryCameraPage 读取并合成这张图的重点很简单TimeLocationPage自己不拍照它负责把拍照要用的参数准备好真正生成图片时CameraPage再读取这些状态图 1 说明这张图可以直接告诉读者这个页面不是终点而是拍照之前的上下文编辑器。二、状态为什么要这样拆TimeLocationPage的状态分成两类最合理1. 长期偏好StorageLink(wmAutoWatermark)autoWatermark:booleantrue;StorageLink(cameraWatermarkTemplate)watermarkTemplate:number0;StorageLink(wmShowTime)showTime:booleantrue;StorageLink(wmShowAddress)showAddress:booleantrue;StorageLink(wmLocationHistory)wmLocationHistory:string[];StorageLink(wmManualLocation)manualLocation:string;这些字段属于长期偏好用户不会在一次页面停留里频繁重置。用StorageLink的好处是页面间共享刷新后还能保留其他页面也能直接读取2. 短期预览状态StatepreviewTime:string;StatepreviewDate:string;StatehistoryList:AddressRecord[][];StateeditingAddr:booleanfalse;StateaddrInput:string;这些状态是页面内临时使用的预览时间预览日期输入框编辑状态历史列表渲染结果这样拆开后页面会非常清楚长期偏好进存储短期交互进状态。三、页面打开时先把预览准备好aboutToAppear():void{this.parseHistory();constnownewDate();this.previewTimenow.getHours().toString().padStart(2,0):now.getMinutes().toString().padStart(2,0);constweeks:string[][星期日,星期一,星期二,星期三,星期四,星期五,星期六];this.previewDatenow.getFullYear().(now.getMonth()1).toString().padStart(2,0).now.getDate().toString().padStart(2,0) weeks[now.getDay()];}这段逻辑体现了一个产品细节预览页展示的内容要尽量和拍照后真正写进水印的内容一致。用户在这里看到的时间和日期不是装饰而是后面会进入最终图片的信息。四、模板卡片不是抽象概念而是直接可视化项目里水印模板不是一个字符串而是预先定义好的样式列表。constWM_NAMES:string[][今日现场,工程巡检,考勤打卡,旅行日记,生活记录,巡检记录];constWM_COLORS:string[][#0D47A1,#1B5E20,#E65100,#4A148C,#880E4F,#004D40];这组数据很实用因为它直接决定了页面里模板卡片的视觉差异。用户不是在“选编号”而是在“选拍照语境”现场记录考勤打卡旅行留念生活记录这种语义化设计比单纯的模板 1、模板 2 更容易理解。五、历史地址为什么必须做成列表1. 先解析历史privateparseHistory():void{try{this.historyListJSON.parse(this.wmLocationHistory)asAddressRecord[];}catch(_e){this.historyList[];}}这一步的意义在于页面打开时立即恢复历史地址如果 JSON 异常也不会把页面搞崩让历史地址成为可回收资源而不是一次性输入2. 再保存历史privatesaveHistory(addr:string):void{if(addr.trim().length0){return;}try{constlist:AddressRecord[]JSON.parse(this.wmLocationHistory)asAddressRecord[];list.unshift({address:addr,ts:Date.now()});this.wmLocationHistoryJSON.stringify(list.slice(0,20));}catch(_e){this.wmLocationHistoryJSON.stringify([{address:addr,ts:Date.now()}]);}}这样做的好处是最近常用地址会排在最前面历史不会无限增长用户下次拍照时能快速选回常用位置六、手动地址不是临时输入而是长期覆盖很多人会把手动地址理解成“临时改一下”但这个项目里不是。if(this.editingAddr){TextInput({placeholder:输入自定义地址,text:this.addrInput}).onChange((val:string){this.addrInputval;});Text(确定).onClick((){constaddrthis.addrInput.trim();if(addr.length0){promptAction.showToast({message:请输入地址,duration:1200});return;}this.manualLocationaddr;this.saveHistory(addr);this.editingAddrfalse;});}这里的产品价值很清楚某些场景 GPS 不准某些场景必须写业务地址某些场景需要强制覆盖定位结果也就是说手动地址是为了让水印更可控而不是临时补丁。七、预览卡片是整页的核心页面中间那张预览卡片实际上承载了整个页面的表达能力当前模板当前时间当前日期当前地点当前备注这类页面要尽量让用户在进入相机前就知道“最终照片大概长什么样”。八、和CameraPage的联动才是最终目标TimeLocationPage之所以存在是因为CameraPage会读取这些配置来合成水印。它在整个链路里扮演的是“前置输入管理器”用户在这里切模板用户在这里改时间/地址相关开关用户在这里选择手动地址相机页在拍照时读取这些信息并烧录进图片如果没有这层拆分所有逻辑都堆在相机页里页面会很快变复杂。九、这页最值得写进文章的 3 个点StorageLink让水印偏好跨页面共享预览卡片和最终水印保持语义一致手动地址和历史地址组成了可回收的地址闭环小结表模块作用自动水印控制拍照是否统一烧录信息模板选择决定水印卡片样式手动地址覆盖实时定位适应业务场景历史地址让常用地点可复用预览卡片让用户提前看到最终结果问题 - 方案 - 验证问题拍照前的时间、地点、模板如果分散在相机页里页面会越来越难维护。方案把这些上下文都收口到TimeLocationPage统一通过StorageLink共享。验证切换模板、修改地址、保存历史后再进入相机页时能够立即读取最新配置说明链路是通的。十、实操检查清单打开页面后预览时间是否正确切换模板后预览卡片是否同步变化手动地址保存后是否会出现在历史列表里清空历史后页面是否还能正常使用CameraPage是否能读取到最新的水印配置结语TimeLocationPage的价值不在于“设置项多”而在于它把最容易被忽略的拍摄上下文整理成了一个可维护的入口。它做对了后面的相机页、水印合成、工作记录回流才会顺它如果乱了整个拍摄体验就会跟着乱。常见问题1. 为什么不直接把时间地点逻辑放到相机页因为这会导致相机页同时承担“拍摄”和“上下文配置”两类职责。拆出来之后拍摄页只关心如何烧录水印时间地点页只关心如何组织参数。2. 为什么历史地址只保留最近 20 条因为这是典型的高频低容量数据。保留太多会增加干扰保留太少又失去复用价值。20 条足够覆盖常用场景。3. 为什么手动地址要覆盖实时定位因为业务场景里“定位准”不总是“业务对”。有时施工现场、室内场景或固定工位更需要用户指定地址。发布前检查页面首图是否可见模板、手动地址、历史地址三块内容是否都有解释是否写清了和CameraPage的联动关系是否有边界条件说明是否有可执行的检查清单