!!!鸿蒙 ArkTS 实战!手把手复刻微信全功能页面(含底部导航 / 聊天列表 / 通讯录)--实战教程&保姆级

鸿蒙版微信开发实战教程

  • 1. 环境准备与项目初始化
  • 2. 微信UI框架搭建
  • 3. 通讯录页面实现
  • 4. 聊天页面实现
  • 5. 聊天详情页面实现
  • 6. 发现页面实现
  • 7. "我"页面实现
  • 8. 鸿蒙版微信开发总结

1. 环境准备与项目初始化

首先需要安装鸿蒙开发工具链:

  1. 下载并安装DevEco Studio(建议从华为开发者官网获取最新版本)
  2. 安装完成后配置JDK和SDK路径
  3. 创建新项目,选择"Empty Ability"模板
  4. 项目结构说明:
    • entry/src/main/ets:存放ArkTS代码
    • entry/src/main/resources:存放资源文件
    • entry/config.json:应用配置文件

注释:无基础的情况下,建议优先阅读《0 基础手把手教你鸿蒙开发(ArkTS+ArkUI 从入门到精通)》

2. 微信UI框架搭建

下面是微信主界面的实现代码:

// pages/Index.ets
import router from '@ohos.router';
import { TabBarItem } from '../components/TabBarItem';

@Entry
@Component
struct Index {
  @State currentIndex: number = 0;  // 当前选中的标签页索引
  
  // 标签页数据
  private tabBarItems = [
    { icon: $r('app.media.tab_contacts'), text: '通讯录', page: 'pages/Contacts' },
    { icon: $r('app.media.tab_chats'), text: '聊天', page: 'pages/Chats' },
    { icon: $r('app.media.tab_discover'), text: '发现', page: 'pages/Discover' },
    { icon: $r('app.media.tab_me'), text: '我', page: 'pages/Me' }
  ];
  
  build() {
    Column() {
      // 主内容区域
      Stack() {
        // 根据当前索引显示对应的页面
        ForEach(this.tabBarItems, (item, index) => {
          if (index === this.currentIndex) {
            // 使用router模块加载对应页面
            RouterContainer({
              name: item.page,
              params: {}
            })
            .width('100%')
            .height('100%')
          }
        })
      }
      .width('100%')
      .height('100%')
      .margin({ bottom: 60 })  // 留出底部标签栏的空间
      
      // 底部标签栏
      Row() {
        ForEach(this.tabBarItems, (item, index) => {
          TabBarItem({
            icon: item.icon,
            text: item.text,
            isSelected: index === this.currentIndex,
            onClick: () => {
              this.currentIndex = index;  // 更新当前选中的标签页
            }
          })
          .width('25%')
          .height(60)
        })
      }
      .width('100%')
      .height(60)
      .backgroundColor('#FFFFFF')
      .positionType(PositionType.Absolute)  // 绝对定位到底部
      .bottom(0)
      .shadow({
        offsetX: 0,
        offsetY: -2,
        blurRadius: 10,
        color: '#EEEEEE'
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}
// components/TabBarItem.ets
@Component
struct TabBarItem {
  @Link icon: ResourceStr;  // 图标资源
  @Link text: string;  // 标签文本
  @Link isSelected: boolean;  // 是否选中状态
  @Link onClick: () => void;  // 点击事件回调
  
  build() {
    Column() {
      Image(this.icon)
        .width(24)
        .height(24)
        .objectFit(ImageFit.Contain)
        .margin({ top: 6 })
        .fill(this.isSelected ? '#07C160' : '#999999')  // 根据选中状态改变图标颜色
      
      Text(this.text)
        .fontSize(10)
        .margin({ top: 2 })
        .fontColor(this.isSelected ? '#07C160' : '#999999')  // 根据选中状态改变文本颜色
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .onClick(() => {
      this.onClick();  // 触发外部传入的点击事件
    })
  }
}

3. 通讯录页面实现

下面是通讯录页面的代码实现:

// pages/Contacts.ets
import router from '@ohos.router';

@Entry
@Component
struct Contacts {
  // 模拟通讯录数据
  @State contactList: Array<{ id: number; name: string; avatar: ResourceStr; py: string }> = [
    { id: 1, name: '张三', avatar: $r('app.media.avatar1'), py: 'Zhang San' },
    { id: 2, name: '李四', avatar: $r('app.media.avatar2'), py: 'Li Si' },
    { id: 3, name: '王五', avatar: $r('app.media.avatar3'), py: 'Wang Wu' },
    { id: 4, name: '赵六', avatar: $r('app.media.avatar4'), py: 'Zhao Liu' },
    { id: 5, name: '孙七', avatar: $r('app.media.avatar5'), py: 'Sun Qi' },
    { id: 6, name: '周八', avatar: $r('app.media.avatar6'), py: 'Zhou Ba' },
    { id: 7, name: '吴九', avatar: $r('app.media.avatar7'), py: 'Wu Jiu' },
    { id: 8, name: '郑十', avatar: $r('app.media.avatar8'), py: 'Zheng Shi' },
    { id: 9, name: '钱十一', avatar: $r('app.media.avatar9'), py: 'Qian Shiyi' },
    { id: 10, name: '冯十二', avatar: $r('app.media.avatar10'), py: 'Feng Shi\'er' }
  ];
  
  // 搜索关键词
  @State searchKeyword: string = '';
  
  // 获取过滤后的联系人列表
  getFilteredContacts() {
    if (!this.searchKeyword.trim()) {
      return this.contactList;
    }
    
    return this.contactList.filter(contact => 
      contact.name.includes(this.searchKeyword) || 
      contact.py.toLowerCase().includes(this.searchKeyword.toLowerCase())
    );
  }
  
  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text('通讯录')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .margin({ left: 15 })
        
        Blank()  // 占位符,用于将右侧按钮推到最右边
        
        Button('+')
          .width(30)
          .height(30)
          .fontSize(20)
          .backgroundColor('#07C160')
          .fontColor('#FFFFFF')
          .margin({ right: 15 })
          .onClick(() => {
            // 跳转到添加联系人页面
            router.pushUrl({ url: 'pages/AddContact' });
          })
      }
      .width('100%')
      .height(50)
      .backgroundColor('#FFFFFF')
      .alignItems(VerticalAlign.Center)
      
      // 搜索框
      Row() {
        Image($r('app.media.search'))
          .width(20)
          .height(20)
          .margin({ left: 15 })
          .fill('#999999')
        
        TextField({
          placeholder: '搜索',
          onInput: (value: string) => {
            this.searchKeyword = value;  // 更新搜索关键词
          }
        })
        .width('90%')
        .height(35)
        .margin({ left: 10, right: 15 })
        .backgroundColor('#F0F0F0')
        .borderRadius(17.5)
        .padding({ left: 10 })
      }
      .width('100%')
      .height(50)
      .backgroundColor('#F5F5F5')
      .alignItems(VerticalAlign.Center)
      
      // 联系人列表
      List() {
        // 特殊联系人项 - 新的朋友
        ListItem() {
          Row() {
            Image($r('app.media.new_friends'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('新的朋友')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            // 有新消息提示
            if (true) {  // 这里应该根据实际情况判断是否有新消息
              Text('3')
                .width(20)
                .height(20)
                .backgroundColor('#FF3B30')
                .fontColor('#FFFFFF')
                .fontSize(12)
                .textAlign(TextAlign.Center)
                .borderRadius(10)
                .margin({ right: 15 })
            }
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/NewFriends' });
          })
        }
        
        // 特殊联系人项 - 群聊
        ListItem() {
          Row() {
            Image($r('app.media.group_chat'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('群聊')
              .fontSize(17)
              .margin({ left: 15 })
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/GroupChats' });
          })
        }
        
        // 特殊联系人项 - 标签
        ListItem() {
          Row() {
            Image($r('app.media.tags'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('标签')
              .fontSize(17)
              .margin({ left: 15 })
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Tags' });
          })
        }
        
        // 特殊联系人项 - 公众号
        ListItem() {
          Row() {
            Image($r('app.media.official_accounts'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('公众号')
              .fontSize(17)
              .margin({ left: 15 })
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/OfficialAccounts' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(8)
            .fill('#F5F5F5')
        }
        
        // 联系人列表
        ForEach(this.getFilteredContacts(), (contact) => {
          ListItem() {
            Row() {
              Image(contact.avatar)
                .width(40)
                .height(40)
                .margin({ left: 15 })
                .objectFit(ImageFit.Contain)
                .borderRadius(5)
              
              Text(contact.name)
                .fontSize(17)
                .margin({ left: 15 })
            }
            .width('100%')
            .height(60)
            .alignItems(VerticalAlign.Center)
            .onClick(() => {
              // 跳转到联系人详情页
              router.pushUrl({ 
                url: 'pages/ContactDetail', 
                params: { contactId: contact.id } 
              });
            })
          }
        })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}

4. 聊天页面实现

下面是聊天页面的代码实现:

// pages/Chats.ets
import router from '@ohos.router';

@Entry
@Component
struct Chats {
  // 模拟聊天会话数据
  @State chatList: Array<{ 
    id: number; 
    name: string; 
    avatar: ResourceStr; 
    lastMessage: string; 
    time: string; 
    unreadCount: number 
  }> = [
    { id: 1, name: '张三', avatar: $r('app.media.avatar1'), lastMessage: '在吗?', time: '12:30', unreadCount: 2 },
    { id: 2, name: '李四', avatar: $r('app.media.avatar2'), lastMessage: '我今天下午到', time: '昨天', unreadCount: 0 },
    { id: 3, name: '工作群', avatar: $r('app.media.group_chat'), lastMessage: '明天上午10点开会', time: '周一', unreadCount: 5 },
    { id: 4, name: '产品讨论组', avatar: $r('app.media.group_chat'), lastMessage: '设计稿已经上传', time: '上周', unreadCount: 0 },
    { id: 5, name: '王五', avatar: $r('app.media.avatar3'), lastMessage: '好的,我知道了', time: '上周', unreadCount: 0 }
  ];
  
  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text('聊天')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .margin({ left: 15 })
        
        Blank()
        
        // 搜索按钮
        Image($r('app.media.search'))
          .width(24)
          .height(24)
          .margin({ right: 20 })
          .fill('#333333')
          .onClick(() => {
            // 跳转到搜索页面
            router.pushUrl({ url: 'pages/SearchChats' });
          })
        
        // 更多按钮
        Image($r('app.media.more'))
          .width(24)
          .height(24)
          .margin({ right: 15 })
          .fill('#333333')
          .onClick(() => {
            // 显示更多选项
          })
      }
      .width('100%')
      .height(50)
      .backgroundColor('#FFFFFF')
      .alignItems(VerticalAlign.Center)
      
      // 聊天列表
      List() {
        ForEach(this.chatList, (chat) => {
          ListItem() {
            Row() {
              // 头像
              Image(chat.avatar)
                .width(50)
                .height(50)
                .margin({ left: 15 })
                .objectFit(ImageFit.Contain)
                .borderRadius(5)
              
              Column() {
                // 名称和时间
                Row() {
                  Text(chat.name)
                    .fontSize(17)
                    .fontWeight(FontWeight.Normal)
                  
                  Blank()
                  
                  Text(chat.time)
                    .fontSize(12)
                    .fontColor('#999999')
                    .margin({ right: 15 })
                }
                .width('100%')
                .alignItems(VerticalAlign.Center)
                
                // 最后一条消息和未读计数
                Row() {
                  Text(chat.lastMessage)
                    .fontSize(14)
                    .fontColor('#999999')
                    .width('70%')
                    .maxLines(1)
                    .overflow(TextOverflow.Ellipsis)
                  
                  Blank()
                  
                  // 未读消息计数
                  if (chat.unreadCount > 0) {
                    Text(chat.unreadCount.toString())
                      .width(chat.unreadCount > 9 ? 25 : 20)
                      .height(20)
                      .backgroundColor('#FF3B30')
                      .fontColor('#FFFFFF')
                      .fontSize(chat.unreadCount > 9 ? 10 : 12)
                      .textAlign(TextAlign.Center)
                      .borderRadius(10)
                      .margin({ right: 15 })
                  }
                }
                .width('100%')
                .alignItems(VerticalAlign.Center)
              }
              .width('80%')
              .margin({ left: 10 })
            }
            .width('100%')
            .height(75)
            .alignItems(VerticalAlign.Center)
            .onClick(() => {
              // 跳转到聊天详情页
              router.pushUrl({ 
                url: 'pages/ChatDetail', 
                params: { chatId: chat.id, name: chat.name, avatar: chat.avatar } 
              });
            })
          }
        })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

5. 聊天详情页面实现

下面是聊天详情页面的代码实现:

// pages/ChatDetail.ets
import router from '@ohos.router';
import { MessageItem } from '../components/MessageItem';

@Entry
@Component
struct ChatDetail {
  @Link chatId: number = 0;  // 从路由传递过来的聊天ID
  @Link name: string = '';  // 从路由传递过来的聊天对象名称
  @Link avatar: ResourceStr = $r('app.media.sample');  // 从路由传递过来的聊天对象头像
  
  // 模拟聊天消息数据
  @State messageList: Array<{ 
    id: number; 
    text: string; 
    isSelf: boolean; 
    time: string; 
    type: 'text' | 'image' | 'video' 
  }> = [
    { id: 1, text: '你好!', isSelf: false, time: '12:30', type: 'text' },
    { id: 2, text: '在吗?', isSelf: false, time: '12:31', type: 'text' },
    { id: 3, text: '我在,有什么事吗?', isSelf: true, time: '12:32', type: 'text' },
    { id: 4, text: '我想咨询一下项目的情况', isSelf: false, time: '12:33', type: 'text' },
    { id: 5, text: '项目进展顺利,预计下周可以完成', isSelf: true, time: '12:34', type: 'text' },
    { id: 6, text: '好的,有需要随时联系', isSelf: false, time: '12:35', type: 'text' }
  ];
  
  // 输入框内容
  @State inputText: string = '';
  
  // 显示键盘
  @State showKeyboard: boolean = false;
  
  // 发送消息方法
  sendMessage() {
    if (!this.inputText.trim()) return;
    
    const newMessage = {
      id: Date.now(),
      text: this.inputText,
      isSelf: true,
      time: new Date().toLocaleTimeString().substring(0, 5),
      type: 'text'
    };
    
    this.messageList = [...this.messageList, newMessage];
    this.inputText = '';
    
    // 模拟回复
    setTimeout(() => {
      const reply = {
        id: Date.now(),
        text: '收到,我稍后回复你',
        isSelf: false,
        time: new Date().toLocaleTimeString().substring(0, 5),
        type: 'text'
      };
      
      this.messageList = [...this.messageList, reply];
    }, 1000);
  }
  
  build() {
    Column() {
      // 顶部导航栏
      Row() {
        // 返回按钮
        Image($r('app.media.back'))
          .width(24)
          .height(24)
          .margin({ left: 15 })
          .fill('#333333')
          .onClick(() => {
            router.back();
          })
        
        // 聊天对象名称
        Text(this.name)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .margin({ left: 20 })
        
        Blank()
        
        // 更多按钮
        Image($r('app.media.more'))
          .width(24)
          .height(24)
          .margin({ right: 15 })
          .fill('#333333')
          .onClick(() => {
            // 显示聊天设置
            router.pushUrl({ 
              url: 'pages/ChatSettings', 
              params: { chatId: this.chatId, name: this.name } 
            });
          })
      }
      .width('100%')
      .height(50)
      .backgroundColor('#FFFFFF')
      .alignItems(VerticalAlign.Center)
      
      // 分割线
      Rectangle()
        .width('100%')
        .height(0.5)
        .fill('#E0E0E0')
      
      // 消息列表
      List() {
        ForEach(this.messageList, (message) => {
          ListItem() {
            MessageItem({
              message: message,
              avatar: message.isSelf ? $r('app.media.my_avatar') : this.avatar
            })
          }
        })
      }
      .width('100%')
      .height(this.showKeyboard ? '70%' : '85%')
      .margin({ top: 5 })
      
      // 底部输入区域
      Column() {
        // 工具栏
        Row() {
          // 语音/键盘切换按钮
          Image(this.showKeyboard ? $r('app.media.voice') : $r('app.media.keyboard'))
            .width(28)
            .height(28)
            .margin({ left: 15 })
            .fill('#666666')
            .onClick(() => {
              this.showKeyboard = !this.showKeyboard;
            })
          
          // 输入框
          TextField({
            placeholder: '输入消息',
            text: this.inputText,
            onInput: (value: string) => {
              this.inputText = value;
            },
            onSubmit: () => {
              this.sendMessage();
            }
          })
          .width('70%')
          .height(35)
          .margin({ left: 10, right: 10 })
          .backgroundColor('#F0F0F0')
          .borderRadius(17.5)
          .padding({ left: 15 })
          
          // 表情按钮
          Image($r('app.media.emoji'))
            .width(28)
            .height(28)
            .margin({ right: 10 })
            .fill('#666666')
            .onClick(() => {
              // 显示表情面板
            })
          
          // 更多按钮
          Image($r('app.media.add'))
            .width(28)
            .height(28)
            .margin({ right: 15 })
            .fill('#666666')
            .onClick(() => {
              // 显示更多选项面板
            })
        }
        .width('100%')
        .height(50)
        .backgroundColor('#FFFFFF')
        .alignItems(VerticalAlign.Center)
        
        // 发送按钮(当有内容时显示)
        if (this.inputText.trim()) {
          Row() {
            Button('发送')
              .width(60)
              .height(30)
              .fontSize(14)
              .backgroundColor('#07C160')
              .fontColor('#FFFFFF')
              .margin({ right: 15 })
              .onClick(() => {
                this.sendMessage();
              })
            
            Blank()
          }
          .width('100%')
          .height(40)
          .backgroundColor('#FFFFFF')
          .alignItems(VerticalAlign.Center)
        }
      }
      .width('100%')
      .height(this.showKeyboard ? '30%' : '15%')
      .backgroundColor('#FFFFFF')
      .positionType(PositionType.Absolute)
      .bottom(0)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}
// components/MessageItem.ets
@Component
struct MessageItem {
  @Link message: { 
    id: number; 
    text: string; 
    isSelf: boolean; 
    time: string; 
    type: 'text' | 'image' | 'video' 
  };  // 消息内容
  @Link avatar: ResourceStr;  // 头像资源
  
  build() {
    Column() {
      // 时间显示(当消息与上一条消息的时间间隔超过5分钟时显示)
      if (true) {  // 这里应该根据实际消息时间判断
        Text(this.message.time)
          .fontSize(12)
          .fontColor('#999999')
          .margin({ top: 10, bottom: 10 })
      }
      
      Row() {
        // 对方消息
        if (!this.message.isSelf) {
          // 头像
          Image(this.avatar)
            .width(40)
            .height(40)
            .margin({ left: 15 })
            .objectFit(ImageFit.Contain)
            .borderRadius(5)
          
          // 消息气泡
          Column() {
            Text(this.message.text)
              .fontSize(16)
              .padding({ left: 15, right: 15, top: 10, bottom: 10 })
              .backgroundColor('#FFFFFF')
              .borderRadius(5)
          }
          .margin({ left: 10 })
          
          Blank()
        }
        
        // 自己的消息
        if (this.message.isSelf) {
          Blank()
          
          // 消息气泡
          Column() {
            Text(this.message.text)
              .fontSize(16)
              .padding({ left: 15, right: 15, top: 10, bottom: 10 })
              .backgroundColor('#07C160')
              .fontColor('#FFFFFF')
              .borderRadius(5)
          }
          .margin({ right: 10 })
          
          // 头像
          Image(this.avatar)
            .width(40)
            .height(40)
            .margin({ right: 15 })
            .objectFit(ImageFit.Contain)
            .borderRadius(5)
        }
      }
      .width('100%')
      .margin({ bottom: 10 })
    }
    .width('100%')
  }
}

6. 发现页面实现

下面是发现页面的代码实现:

// pages/Discover.ets
import router from '@ohos.router';

@Entry
@Component
struct Discover {
  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text('发现')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .margin({ left: 15 })
        
        Blank()
        
        // 更多按钮
        Image($r('app.media.more'))
          .width(24)
          .height(24)
          .margin({ right: 15 })
          .fill('#333333')
          .onClick(() => {
            // 显示更多选项
          })
      }
      .width('100%')
      .height(50)
      .backgroundColor('#FFFFFF')
      .alignItems(VerticalAlign.Center)
      
      // 朋友圈
      List() {
        // 朋友圈项
        ListItem() {
          Row() {
            Image($r('app.media.moments'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('朋友圈')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Moments' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(0.5)
            .fill('#E0E0E0')
            .margin({ left: 70 })
        }
        
        // 扫一扫
        ListItem() {
          Row() {
            Image($r('app.media.scan'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('扫一扫')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Scan' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(0.5)
            .fill('#E0E0E0')
            .margin({ left: 70 })
        }
        
        // 摇一摇
        ListItem() {
          Row() {
            Image($r('app.media.shake'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('摇一摇')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Shake' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(8)
            .fill('#F5F5F5')
        }
        
        // 看一看
        ListItem() {
          Row() {
            Image($r('app.media.watch'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('看一看')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            // 有新内容提示
            Text('新')
              .width(18)
              .height(18)
              .backgroundColor('#FF3B30')
              .fontColor('#FFFFFF')
              .fontSize(10)
              .textAlign(TextAlign.Center)
              .borderRadius(9)
              .margin({ right: 5 })
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Watch' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(0.5)
            .fill('#E0E0E0')
            .margin({ left: 70 })
        }
        
        // 搜一搜
        ListItem() {
          Row() {
            Image($r('app.media.search'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('搜一搜')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Search' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(8)
            .fill('#F5F5F5')
        }
        
        // 小程序
        ListItem() {
          Row() {
            Image($r('app.media.miniprogram'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('小程序')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/MiniPrograms' });
          })
        }
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

7. "我"页面实现

下面是"我"页面的代码实现:

// pages/Me.ets
import router from '@ohos.router';

@Entry
@Component
struct Me {
  build() {
    Column() {
      // 用户信息区域
      Stack() {
        // 背景图
        Image($r('app.media.profile_bg'))
          .width('100%')
          .height(200)
          .objectFit(ImageFit.Cover)
        
        // 用户信息
        Row() {
          // 头像
          Image($r('app.media.my_avatar'))
            .width(70)
            .height(70)
            .margin({ left: 15 })
            .objectFit(ImageFit.Contain)
            .borderRadius(5)
            .border({ width: 2, color: '#FFFFFF' })
          
          Column() {
            // 昵称
            Text('我的昵称')
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#FFFFFF')
              .margin({ left: 15, top: 10 })
            
            // 微信号
            Row() {
              Text('微信号: wxid_123456')
                .fontSize(14)
                .fontColor('#FFFFFF')
                .margin({ left: 15, top: 5 })
              
              Image($r('app.media.qrcode'))
                .width(18)
                .height(18)
                .margin({ left: 10, top: 5 })
                .fill('#FFFFFF')
            }
          }
          
          Blank()
          
          // 更多按钮
          Image($r('app.media.more_white'))
            .width(24)
            .height(24)
            .margin({ right: 15 })
            .fill('#FFFFFF')
        }
        .width('100%')
        .height(200)
        .alignItems(VerticalAlign.Center)
      }
      
      // 功能列表
      List() {
        // 支付
        ListItem() {
          Row() {
            Image($r('app.media.payment'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('支付')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Payment' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(8)
            .fill('#F5F5F5')
        }
        
        // 收藏
        ListItem() {
          Row() {
            Image($r('app.media.favorites'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('收藏')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Favorites' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(0.5)
            .fill('#E0E0E0')
            .margin({ left: 70 })
        }
        
        // 表情
        ListItem() {
          Row() {
            Image($r('app.media.emojis'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('表情')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Emojis' });
          })
        }
        
        // 分隔线
        ListItem() {
          Rectangle()
            .width('100%')
            .height(0.5)
            .fill('#E0E0E0')
            .margin({ left: 70 })
        }
        
        // 设置
        ListItem() {
          Row() {
            Image($r('app.media.settings'))
              .width(40)
              .height(40)
              .margin({ left: 15 })
              .objectFit(ImageFit.Contain)
            
            Text('设置')
              .fontSize(17)
              .margin({ left: 15 })
            
            Blank()
            
            Image($r('app.media.arrow_right'))
              .width(20)
              .height(20)
              .margin({ right: 15 })
              .fill('#999999')
          }
          .width('100%')
          .height(60)
          .alignItems(VerticalAlign.Center)
          .onClick(() => {
            router.pushUrl({ url: 'pages/Settings' });
          })
        }
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

8. 鸿蒙版微信开发总结

以上代码实现了微信的主要功能和界面,包括:

  1. 底部标签栏导航系统
  2. 通讯录页面(包括联系人列表、搜索功能)
  3. 聊天页面(包括会话列表、未读消息提示)
  4. 聊天详情页面(包括消息展示、输入框、发送消息)
  5. 发现页面(包括朋友圈、扫一扫等功能入口)
  6. "我"页面(包括个人信息、功能入口)

这个实现使用了鸿蒙的ArkTS语言和ArkUI框架,遵循了微信的UI设计风格和交互模式。每个页面都有详细的代码注释,方便理解和学习。


希望这个教程对你学习鸿蒙前端开发有所帮助!

你可能感兴趣的:(前端,harmonyos,微信,华为,鸿蒙系统,鸿蒙)