# 智能家居 **Repository Path**: viktor028/smart-home ## Basic Information - **Project Name**: 智能家居 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-02 - **Last Updated**: 2025-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 第三天 ### 1. 鸿蒙项目介绍 ![1751421167023](./assets/1751421167023.png) #### 演示效果 ![screenshots](./assets/screenshots.gif) ### 2. 登录界面 - 创建项目 ![1751421458561](./assets/1751421458561.png) ![1751421481853](./assets/1751421481853.png) - 登录界面 ![1751421430877](./assets/1751421430877.png) - 组件拆分 ### 3. 主界面自定义tab ![1751424162942](./assets/1751424162942.png) ```ts @Preview @Component struct Main { @State currentIndex:number = 0 // 当前选中状态 @Builder tabBuilder(title:string,icon:Resource,activeIcon:Resource,index:number){ Column(){ Image(this.currentIndex == index?activeIcon:icon) .width(20) .height(20) .margin({top:5}) Text(title) .fontSize(12) .fontColor(this.currentIndex == index?'#20b2aa': '#8d949d') .margin({top:5}) } } build() { Tabs({barPosition:BarPosition.End}){ TabContent(){ Text('Home') }.tabBar(this.tabBuilder('发现',$r('app.media.tab_find'),$r('app.media.tab_find_selector'),0)) TabContent(){ Text('首页') }.tabBar(this.tabBuilder('首页',$r('app.media.tab_home'),$r('app.media.tab_home_selector'),1)) TabContent(){ Text('我的') }.tabBar(this.tabBuilder('我的',$r('app.media.tab_my'),$r('app.media.tab_my_selector'),2)) }.onChange((index)=>{ this.currentIndex = index }) .divider({ color: '#eff1f3', strokeWidth: 2 }) } } ``` ### 4. 组件导航 组件导航(Navigation)和页面路由(@ohos.router)均支持应用内的页面跳转,但组件导航支持在组件内部进行跳转,使用更灵活。组件导航具备更强的一次开发多端部署能力,可以进行更加灵活的页面栈操作,同时支持更丰富的动效和生命周期。因此,推荐使用组件导航(Navigation)来实现页面跳转以及组件内的跳转,以获得更佳的使用体验。 ![导航组件Navigation](./assets/导航组件Navigation.png) ![导航组件代码实现](./assets/导航组件代码实现.png) 使用navigation组件导航启动项目进入登录界面 **实现步骤:** 1. 在Index页面实现如下代码: ```ts @Entry @Component struct Index { pathStack:NavPathStack = new NavPathStack() // 页面栈对象,作用:组件导航跳转的方法 build() { Navigation(this.pathStack){ } .hideNavBar(true) // 隐藏导航栏 .hideTitleBar(true) // 隐藏标题栏 .onAppear(()=>{ this.pathStack.pushPathByName("Login",null,false) // 添加登录页面 }) } } ``` 2. 在resources/profile目录创建route_map.json配置文件 route_map.json配置文件配置组件导航跳转信息 ```ts { "routerMap": [ { "name": "Login", "pageSourceFile": "src/main/ets/views/Login.ets", "buildFunction": "LoginBuilder" } ] } ``` 3. 在module.json5模块配置文件中引用route_map.json文件 ```ts "routerMap": "$profile:route_map", ``` 4. Login组件实现Builder方法 ```ts import { LoginForm, LoginWeiQQ,LoginTitle } from '../views/LoginView' @Builder function LoginBuilder(){ Login() } @Component struct Login { build() { NavDestination(){ Column() { LoginTitle() LoginForm() LoginWeiQQ() } .width('100%') .height('100%') } .hideTitleBar(true) } } ``` 5. 跳转的目标组件最外层根组件使用 NavDestination包裹并隐藏默认的标题栏 .hideTitleBar(true) ###5. 主界面tab切换 ![1751447842112](./assets/1751447842112.png) ### 6. 任务 - 使用组件导航navigation从登录注册跳转到主界面. - 完成登录注册页面效果 ## 第四天 ### 1. 个人中心 ![我的@1x](./assets/我的@1x.png) ### 2. 组件封装与组件通讯 - 需求: 封装一个组件,要求:右边是图标+文本 右边是箭头 例如:父组件 My 传值 到子组件 SetListItemCom 实现方式: ``` 1. 在子组件定义使用@Prop装饰的变量用于接收父组件传入值 @Prop item: ISetItem 2. 父组件调用子组件时传入值 SetListItemCom({item:item}) ``` ![1751510679924](./assets/1751510679924.png) - 练习: 需求: 封装一个通用标题组件,左边是标题名称,右边是图标,右边图标有可能没有。 ![1751510712714](./assets/1751510712714.png) ### 3. 标题组件封装 ![1751533382394](./assets/1751533382394.png) ```ts /** * 通用标题组件 * 左边标题名称 右边是可选图标 * [标题 图标] * [标题 ] */ @Preview @Component export struct CommonTitle { @Prop title: string; @Prop icon?: Resource; onTitleClick: () => void = () => {}; build() { Row() { Text(this.title) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor('#171717') Blank() if (this.icon) { Image(this.icon) .width(13) .height(4) .onClick(()=>this.onTitleClick()) } } .width('100%') .height(50) .backgroundColor('#fff') .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.SpaceBetween) .padding({ left: 16, right: 16 }) .borderWidth({bottom:1}) .borderColor('#ffe0dede') } } ``` ### 4. 数据分离 ```ts export class SetItemBean { title: string; // 标题 icon: Resource; // 图标 constructor(title: string, icon: Resource) { this.title = title; this.icon = icon; } } export class SetItemList { list: SetItemBean[]; constructor() { this.list = [ new SetItemBean('设备管理', $r('app.media.my_set_icon')), new SetItemBean('个人信息', $r('app.media.my_person_icon')), new SetItemBean('帮助中心', $r('app.media.my_help_icon')), new SetItemBean('反馈与建议', $r('app.media.my_sbgl_icon')), new SetItemBean('设置', $r('app.media.my_set_icon')), ] } getList(): SetItemBean[] { return this.list; } } ``` ### 5. 首页 ![1751533483852](./assets/1751533483852.png) ```ts export class DeviceBean { name: string; // 名称 icon: Resource; // 图标 status: boolean; // 状态 statusOpenDesc: string; // 状态描述 statusCloseDesc: string; // 状态描述 constructor(name: string, icon: Resource, status: boolean, statusOpenDesc: string, statusCloseDesc: string) { this.name = name; this.icon = icon; this.status = status; this.statusOpenDesc = statusOpenDesc; this.statusCloseDesc = statusCloseDesc; } } export class DeviceBeanList { list: DeviceBean[] = [] constructor() { this.list = [ new DeviceBean('吊灯', $r('app.media.h_diaoden'), true, '灯光已打开','灯光已关闭'), new DeviceBean('电视', $r('app.media.h_tv'), false, '电视已打开','电视已关闭'), new DeviceBean('监控', $r('app.media.h_vedio'), false, '监控已打开','监控已关闭'), new DeviceBean('路由器', $r('app.media.h_wifi'), true, '网络已打开','网络已关闭'), ] } getList(): DeviceBean[] { return this.list; } } ``` ```ts /** * 智能设备列表 */ @Component struct DeviceListCom { @State list:DeviceBean[] = new DeviceBeanList().getList() build(){ Grid(){ ForEach(this.list, (item:DeviceBean, index:number) => { GridItem(){ Column(){ Row(){ Image(item.icon) .width(12) .height(14) Text(item.name) .fontSize(16) .margin({left:4}) Blank() Toggle({type:ToggleType.Switch,isOn:item.status}) .width(40) .selectedColor('#20b2aa') .onChange(()=>{ item.status = !item.status console.log('item.status >> ',item.status) }) } .width('100%') Text(item.status?item.statusOpenDesc:item.statusCloseDesc) .fontColor('#8d949d') .fontSize(14) .margin({top:5}) .width('100%') } } .backgroundColor('#fff') .padding(16) .borderRadius(8) }) } .height(200) .rowsTemplate('1fr 1fr') .columnsTemplate('1fr 1fr') .rowsGap(10) .columnsGap(10) .margin(16) } } ``` ### 6 任务 1. 完成课堂讲解内容 2. 小组会议,明确成员情况 3. 完成操作设备开关,控制界面刷新显示已打开或已关闭 ![1751533645710](./assets/1751533645710.png) ## 第五天 ### 1. 状态变量 #### 1.1 监听对象属性 @Observer @ObjectLink @State @Observer @ObjectLink 示例: ```ts @Observed export class DeviceBean { name: string; // 名称 icon: Resource; // 图标 status: boolean; // 状态 statusOpenDesc: string; // 状态描述 statusCloseDesc: string; // 状态描述 constructor(name: string, icon: Resource, status: boolean, statusOpenDesc: string, statusCloseDesc: string) { this.name = name; this.icon = icon; this.status = status; this.statusOpenDesc = statusOpenDesc; this.statusCloseDesc = statusCloseDesc; } } ``` 组件 ```ts @Component struct DeviceGridItem { @ObjectLink item: DeviceBean; build() { Column(){ Row(){ Image(this.item.icon) .width(12) .height(14) Text(this.item.name) .fontSize(16) .margin({left:4}) Blank() Toggle({type:ToggleType.Switch,isOn:this.item.status}) .width(40) .selectedColor('#20b2aa') .onChange(()=>{ this.item.status = !this.item.status console.log('item.status >> ',this.item.status) }) } .width('100%') Text(this.item.status?this.item.statusOpenDesc:this.item.statusCloseDesc) .fontColor('#8d949d') .fontSize(14) .margin({top:5}) .width('100%') } } } ``` #### #### 监听对象属性 @ComponentV2 组件使用 @ComponentV2 ```ts @ComponentV2 struct DeviceListCom { } ``` 对象class 使用 @ObservedV2 属性使用 @Trace ```ts @ObservedV2 export class DeviceBean { @Trace name: string; // 名称 @Trace icon: Resource; // 图标 @Trace status: boolean; // 状态 @Trace statusOpenDesc: string; // 状态描述 @Trace statusCloseDesc: string; // 状态描述 ``` ### 2. 设备切换 ```ts .onClick(()=>{ this.currentIndex = index switch(index){ case 0: // 全部 this.deviceList = new DeviceBeanList().getList() break; case 1: // 客厅 this.deviceList = new DeviceBeanList().getList().filter(item=>item.name == '电视' || item.name == '吊灯') break; case 2: this.deviceList = new DeviceBeanList().getList().filter(item=>item.name == '吊灯') break; case 3: this.deviceList = new DeviceBeanList().getList().filter(item=>item.name == '路由器') break; case 4: this.deviceList = new DeviceBeanList().getList().filter(item=>item.name == '监控') break; } }) ``` ![1751598770083](./assets/1751598770083.png) ### 3. 发现 ![发现@1x](./assets/发现@1x.png) ```ts @Component export struct Find { build() { Column() { // 标题 CommonTitle({ title: '智慧家居', icon: $r('app.media.more') }) // 有根组件 Scroll() { FindView() }.layoutWeight(1) .edgeEffect(EdgeEffect.Spring) .scrollBar(BarState.Off) }.width('100%') .height('100%') .backgroundColor('#f9fafb') } } ``` ### 4. 跨组件通讯 ```ts @Provide('pathStack') pathStack:NavPathStack = new NavPathStack() @Consume('pathStack') pathStack: NavPathStack | undefined // 页面栈对象 ``` ### 5. 设备管理 ![1751618932405](./assets/1751618932405.png) ### 6. 修改APP图标名称 ![1751618729770](/assets/1751618729770.png)