
第46篇引导页组件——首次引导与驾照选择一、引言引导页是用户首次打开应用时的第一印象它决定了用户是否能快速上手。DriverLicenseExam 项目的引导页涵盖了城市选择、驾照类型选择、学车阶段选择三个核心步骤并通过GuideService单例管理引导状态。本文将深入解析引导页组件的完整实现。二、引导页整体架构2.1 组件结构guide/ ├──src/main/ets/ │ ├── components/ │ │ ├── GuideView.ets← 引导主视图 │ │ └── SelectCard.ets← 可复用的选择卡片 │ ├── constants/ │ │ └── CommonContants.ets← 常量配置 │ └── model/ │ ├── GuideService.ets← 引导服务单例 │ └── model.ets← 数据模型2.2 引导流程应用首次启动 │ ▼ SplashPage开屏广告 │ ▼ 判断是否已完成引导 │ ├── 是 → 进入主页面HomeView │ └── 否 → 进入引导页 │ ├── 步骤1城市选择 ├── 步骤2驾照类型选择 └── 步骤3学车阶段选择 │ ▼ 完成引导 → 进入主页面三、引导页入口逻辑3.1 引导状态判断引导页的入口逻辑在SplashPage中广告关闭后根据引导状态决定跳转目标// SplashPage.etsComponentV2struct SplashPage { guideService: GuideService GuideService.instance; build() { NavDestination() { AdServicePage({ channelType: ChannelType.HUAWEI_AD, adId:testq6zq98hecj, adType: AdType.SPLASH_AD, closeCallBack: () {// 广告关闭后判断引导状态if(!this.guideService.isCompleteGuidance()) {// 未完成引导 → 进入引导页this.vm.navStack.replacePathByName(guidePage,true); }else{// 已完成引导 → 进入主页面this.vm.navStack.pop(); } }, }); } .height(100%) .width(100%) .hideTitleBar(true) .hideToolBar(true); } }3.2 引导页面注册// GuidePage.ets - 引导页路由注册BuilderexportfunctionGuidePageBuilder() {GuidePage(); }ComponentV2exportstructGuidePage{vm:CommonModelCommonModel.instance;guideService:GuideServiceGuideService.instance;aboutToAppear():void{// 自动定位Utils.applyLocationPermission().then((city) {if(city) {this.guideService.updateCity(city); } }); }build() {NavDestination() {GuideView({goCitySelectPage:() {this.vm.navStack.pushPathByName(selectCityView,true); },completed:() {this.vm.navStack.pop(); }, }); } .height(100%) .width(100%) .hideTitleBar(true) .hideToolBar(true); } }四、GuideService 单例服务4.1 单例模式实现// GuideService.etsObservedV2exportclassGuideService{privatestatic_instance:GuideService;guideData:GuideDataGuideData.instance;publicstaticgetinstance():GuideService{if(!GuideService._instance) {GuideService._instancenewGuideService(); }returnGuideService._instance; }isCompleteGuidance():boolean{// 判断引导是否完成驾照类型已选择表示引导完成returnthis.guideData.licenseType!undefined; }updateCity(city:string) {this.guideData.city city; }getGuideData():GuideData{returnthis.guideData; } }4.2 GuideData 数据模型// model.etsObservedV2exportclassGuideData{privatestatic_instance:GuideData;Tracecity:string北京;TracelicenseType?:number;TracedriveStage?:number;publicstaticgetinstance():GuideData{if(!GuideData._instance) {GuideData._instancenewGuideData(); }returnGuideData._instance; } }GuideData 使用ObservedV2和Trace装饰器确保数据变化时 UI 自动更新。五、选择卡片组件5.1 SelectCard 设计SelectCard是一个可复用的选择卡片组件被用于驾照类型和学车阶段的选择// SelectCard.etsComponentV2exportstructSelectCard{Paramlabel:string;Paramdescription:string;ParamisSelected:booleanfalse;Paramicon?:Resource;EventonSelect:() void() {};build() {Column() {if(this.icon) {Image(this.icon).width(40).height(40); }Text(this.label).fontSize(16).fontWeight(FontWeight.Medium);Text(this.description).fontSize(12).fontColor(#999); } .width(100%) .padding(16) .borderRadius(12) .backgroundColor(this.isSelected?#E8F5E9:#FFF) .border({width:this.isSelected?2:1,color:this.isSelected?#64BB5C:#E0E0E0, }) .onClick(() {this.onSelect(); }); } }这个组件的设计体现了Param接收外部传入的参数标签、描述、选中状态Event通过事件回调通知父组件选中状态变化响应式样式根据 isSelected 自动切换边框颜色和背景六、城市选择与定位6.1 城市选择页面// SelectCityView.etsComponentV2struct SelectCityView { controller: CitySearchController new CitySearchController(); guideService: GuideService GuideService.instance;LocalcurrentCity: string this.guideService.getGuideData().city ||北京; build() { NavDestination() { Column() { UICitySelect({ currentCity:this.currentCity, recentVisitList: [北京,上海,深圳,广西], controller:this.controller, emitUpdateCityLocation: (city: string) {this.currentCity city;this.guideService.updateCity(city); }, goBack: (citySelected?: string) {constmessage citySelected ?选择了 citySelected 并返回:直接返回;this.getUIContext().getPromptAction().showToast({ message });this.vm.navStack.pop(); }, emitUpdateRecentCityList: (city: string) {this.currentCity city;this.guideService.updateCity(city); }, }); } .width(100%) .padding({ top:this.getUIContext().px2vp(AppStorage.get(topRectHeight) ||0), bottom:this.getUIContext().px2vp(AppStorage.get(bottomRectHeight) ||0), }); } .title(城市选择); } }城市选择组件支持的功能当前城市展示最近访问城市列表城市搜索热门城市城市列表索引6.2 定位功能// GuidePage 中自动定位aboutToAppear(): void {Utils.applyLocationPermission().then((city) {if(city) { this.guideService.updateCity(city); } }); }定位功能通过PermissionUtil申请定位权限成功后自动获取当前城市并更新到 GuideService 中。七、引导完成后的数据流转7.1 引导数据的使用引导完成后用户选择的城市、驾照类型、学车阶段等信息被存储到 GuideData 中后续页面通过 GuideService 获取// HomeView 中使用引导数据this.guideService.getGuideData().city// 获取城市this.guideData.driveStage// 获取学车阶段// MineView 中切换题库this.guideService.guideData.licenseType// 获取驾照类型7.2 切换题库功能// MineView.etsBuilderExamSwitchModule(){Row(){Text(切换题库).fontSize(14).maxFontScale(1);Text(licenseTypeName[this.guideService.guideData.licenseType]).fontSize(14).fontColor(#64BB5C).maxFontScale(1);Image($r(app.media.right_triangle)).width(16).height(16); } .width(100%) .onClick(() { this.vm.navStack.pushPathByName(guidePage,true); }); }八、总结引导页组件通过 GuideService 单例 GuideData 数据模型 GuideView 视图的组合实现了完整的首次引导流程引导流程城市选择 → 驾照类型 → 学车阶段状态管理ObservedV2 Trace 响应式数据组件复用SelectCard 组件用于多种选择场景定位集成自动定位 城市选择数据共享GuideData 全局共享引导结果关键源码文件components/guide/src/main/ets/components/GuideView.ets— 引导视图components/guide/src/main/ets/model/GuideService.ets— 引导服务components/guide/src/main/ets/model/model.ets— 数据模型products/entry/src/main/ets/pages/guide/GuidePage.ets— 引导页面products/entry/src/main/ets/pages/SelectCityView.ets— 城市选择页面products/entry/src/main/ets/pages/SplashPage.ets— 开屏广告页