前言导读

各位同学大家,有段时间没有跟大家见面了,因为最近一直在更新鸿蒙的那个实战课程所以就没有去更新文章实在是不好意思, 所以今天就给大家更新一期实战案例 高仿微信案例 希望帮助到各位同学工作和学习

效果图

鸿蒙next 微信重磅来袭_Text

鸿蒙next 微信重磅来袭_Line_02

鸿蒙next 微信重磅来袭_Text_03

鸿蒙next 微信重磅来袭_Line_04

鸿蒙next 微信重磅来袭_Image_05

鸿蒙next 微信重磅来袭_Image_06

特点
  1. 高仿程度80
  2. 目前不支持即时通讯功能
  3. 支持最新的api 12
具体实现
启动页面
/**
 * 创建人:xuqing
 * 创建时间:2024年7月14日22:56:15
 * 类说明:欢迎页面
 *
 */

import router from '@ohos.router';
import { preferences } from '@kit.ArkData';
import CommonConstant from '../common/CommonConstants';
import Logger from '../utils/Logger';
import { httpRequestGet } from '../utils/OkhttpUtils';
import { LoginModel } from '../bean/LoginModel';

let dataPreferences: preferences.Preferences | null = null;


@Entry
@Component
struct Welcome {

   async  aboutToAppear(){
     let options: preferences.Options = { name: 'myStore' };
     dataPreferences = preferences.getPreferencesSync(getContext(), options);
     let getusername=dataPreferences.getSync('username','');
     let getpassword=dataPreferences.getSync('password','');
     if(getusername===''||getpassword===''){
       router.pushUrl({
         url:'pages/LoginPage'
       })
     }else {
       let username:string='username=';
       let password:string='&password=';
       let netloginurl=CommonConstant.LOGIN+username+getusername+password+getpassword;
       httpRequestGet(netloginurl).then((data)=>{
         Logger.error("请求数据--->"+ data.toString());
         let loginmodel:LoginModel=JSON.parse(data.toString());
          if(loginmodel.code===200){
            router.pushUrl({
              url:'pages/Index'
            })
          }else{
            router.pushUrl({
              url:'pages/LoginPage'
            })
          }
       })
     }

  }

  build() {
    RelativeContainer(){
      Image($r('app.media.weixinbg'))
        .width('100%')
        .height('100%')

    }.height('100%')
    .width('100%')
    .backgroundColor(Color.Green)

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
登录页面
import CommonConstant, * as commonConst from '../common/CommonConstants';
import Logger from '../utils/Logger';
import { httpRequestGet } from '../utils/OkhttpUtils';
import  { LoginData, LoginModel}  from '../bean/LoginModel';
import prompt from '@ohos.promptAction';
import router from '@ohos.router';
import { preferences } from '@kit.ArkData';
let dataPreferences: preferences.Preferences | null = null;



/**
 * 创建人:xuqing
 * 创建时间:2024年7月14日17:00:03
 * 类说明:登录页面
 *
 */
//输入框样式
@Extend(TextInput) function  inputStyle(){
  .placeholderColor($r('app.color.placeholder_color'))
  .height(45)
  .fontSize(18)
  .backgroundColor($r('app.color.background'))
  .width('100%')
  .padding({left:0})
  .margin({top:12})
}
//线条样式
@Extend(Line) function  lineStyle(){
  .width('100%')
  .height(1)
  .backgroundColor($r('app.color.line_color'))
}
//黑色字体样式
@Extend(Text) function  blackTextStyle(size?:number ,height?:number){
  .fontColor($r('app.color.black_text_color'))
  .fontSize(18)
  .fontWeight(FontWeight.Medium)
}

@Entry
@Component
struct LoginPage {

  @State accout:string='';
  @State password:string='';
  async  login(){
    let username:string='username=';
    let password:string='&password=';
    let netloginurl=CommonConstant.LOGIN+username+this.accout+password+this.password;
      Logger.error("请求url"+netloginurl);
      await httpRequestGet(netloginurl).then((data)=>{
        Logger.error("请求结果"+data.toString());
        let loginModel:LoginModel=JSON.parse(data.toString());
        let msg=loginModel.msg;
        let logindata:LoginData=loginModel.user;
        let token=loginModel.token;
        let userid=logindata.id;
        let options: preferences.Options = { name: 'myStore' };
        dataPreferences = preferences.getPreferencesSync(getContext(), options);

        if(loginModel.code===200){
          Logger.error("登录成功");
          dataPreferences.putSync('token',token);
          dataPreferences.putSync('id',userid);
          dataPreferences.putSync('username',this.accout);
          dataPreferences.putSync('password',this.password);
          dataPreferences!!.flush()
         router.pushUrl({
           url:'pages/Index'
         })
        }else {
          prompt.showToast({
            message:msg
          })
        }
      })
  }


  build() {
     Column(){
       Image($r('app.media.weixinicon'))
         .width(48)
         .height(48)
         .margin({top:100,bottom:8})
         .borderRadius(8)
         Text('登录界面')
           .fontSize(24)
           .fontWeight(FontWeight.Medium)
           .fontColor($r('app.color.title_text_color'))
       Text('登录账号以使用更多服务')
         .fontSize(16)
         .fontColor($r('app.color.login_more_text_color'))
         .margin({bottom:30,top:8})

       Row(){
         Text('账号').blackTextStyle()
         TextInput({placeholder:'请输入账号'})
           .maxLength(12)
           .type(InputType.Number)
           .inputStyle()
           .onChange((value:string)=>{
             this.accout=value;
           }).margin({left:20})

       }.justifyContent(FlexAlign.SpaceBetween)
       .width('100%')
       .margin({top:8})
       Line().lineStyle().margin({left:80})



       Row(){
         Text('密码').blackTextStyle()
         TextInput({placeholder:'请输入密码'})
           .maxLength(12)
           .type(InputType.Password)
           .inputStyle()
           .onChange((value:string)=>{
             this.password=value;
           }).margin({left:20})
       }.justifyContent(FlexAlign.SpaceBetween)
       .width('100%')
       .margin({top:8})
       Line().lineStyle().margin({left:80})

       Button('登录',{type:ButtonType.Capsule})
         .width('90%')
         .height(40)
         .fontSize(16)
         .fontWeight(FontWeight.Medium)
         .backgroundColor($r('app.color.login_button_color'))
         .margin({top:47,bottom:12})
         .onClick(()=>{
           this.login()
         })
       Text('注册账号').onClick(()=>{
         router.pushUrl({
           url:'pages/RegisterPage'
         })
       }).fontColor($r('app.color.login_blue_text_color'))
         .fontSize(12)
         .fontWeight(FontWeight.Medium)
     }.backgroundColor($r('app.color.background'))
    .height('100%')
    .width('100%')
    .padding({
      left:12,
      right:12,
      bottom:24
    })

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
主页index
import home from './Home/Home';
import contacts from './Contact/Contacts';
import Discover from './Discover/Discover';
import My from './My/My';
import common from '@ohos.app.ability.common';
import prompt from '@ohos.promptAction';


@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  private backTime :number=0;
  @State fontColor: string = '#182451'
  @State selectedFontColor: string = 'rgb(0,196,104)'
  private controller:TabsController=new TabsController();
  showtoast(msg:string){
    prompt.showToast({
      message:msg
    })
  }



  @State SelectPos:number=0;
  private  positionClick(){
    this.SelectPos=0;
    this.controller.changeIndex(0);

  }

  private  companyClick(){
    this.SelectPos=1;
    this.controller.changeIndex(1);
  }
  private  messageClick(){
    this.SelectPos=2;
    this.controller.changeIndex(2);

  }

  private  myClick(){
    this.SelectPos=3;
    this.controller.changeIndex(3);

  }

  onBackPress(): boolean | void {
    let nowtime=Date.now();
    if(nowtime-this.backTime<1000){
      const  mContext=getContext(this) as common.UIAbilityContext;
      mContext.terminateSelf()
    }else{
      this.backTime=nowtime;
      this.showtoast("再按一次将退出当前应用")
    }
    return true;
  }


 // ['微信','通讯录','发现','我']
  build() {
    Flex({direction:FlexDirection.Column,alignItems:ItemAlign.Center,justifyContent:FlexAlign.Center}){
      Tabs({controller:this.controller}){
        TabContent(){
          home();
        }
        TabContent(){
          contacts();
        }
        TabContent(){
          Discover();
        }
        TabContent(){
          My()
        }
      }.scrollable(false)
      .barHeight(0)
      .animationDuration(0)

      Row(){
        Column(){
          Image((this.SelectPos==0?$r('app.media.wetab01'):$r('app.media.wetab00')))
            .width(20).height(20)
            .margin({top:5})
          Text('微信')
            .size({width:'100%',height:30}).textAlign(TextAlign.Center)
            .fontSize(15)
            .fontColor((this.SelectPos==0?this.selectedFontColor:this.fontColor))
        }.layoutWeight(1)
        .backgroundColor($r('app.color.gray2'))
        .height('100%')
        .onClick(this.positionClick.bind(this))



        Column(){
          Image((this.SelectPos==1?$r('app.media.wetab11'):$r('app.media.wetab10')))
            .width(20).height(20)
            .margin({top:5})
          Text('通讯录')
            .size({width:'100%',height:30}).textAlign(TextAlign.Center)
            .fontSize(15)
            .fontColor((this.SelectPos==1?this.selectedFontColor:this.fontColor))
        }.layoutWeight(1)
        .backgroundColor($r('app.color.gray2'))
        .height('100%')
        .onClick(this.companyClick.bind(this))


        Column(){
          Image((this.SelectPos==2?$r('app.media.wetab21'):$r('app.media.wetab20')))
            .width(20).height(20)
            .margin({top:5})
          Text('发现')
            .size({width:'100%',height:30}).textAlign(TextAlign.Center)
            .fontSize(15)
            .fontColor((this.SelectPos==2?this.selectedFontColor:this.fontColor))
        }.layoutWeight(1)
        .backgroundColor($r('app.color.gray2'))
        .height('100%')
        .onClick(this.messageClick.bind(this))


        Column(){
          Image((this.SelectPos==5?$r('app.media.wetab31'):$r('app.media.wetab30')))
            .width(20).height(20)
            .margin({top:5})
          Text('我')
            .size({width:'100%',height:30}).textAlign(TextAlign.Center)
            .fontSize(15)
            .fontColor((this.SelectPos==5?this.selectedFontColor:this.fontColor))
        }.layoutWeight(1)
        .backgroundColor($r('app.color.gray2'))
        .height('100%')
        .onClick(this.myClick.bind(this))
      }.alignItems(VerticalAlign.Bottom).width('100%').height(60).margin({top:0,right:0,bottom:0,left:0})

    }.width('100%')
    .height('100%')


  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
后续目标
  1. 微信朋友圈
  2. 聊天菜单(相册,拍摄...)组件栏
  3. 语音|视频页面
  4. 支持群聊头像
  5. 支持图片,红包等聊天内容类型(现已支持图片类型)
  6. 二维码扫描


团队介绍

团队介绍:坚果派由坚果等人创建,团队由12位华为HDE以及若干热爱鸿蒙的开发者和其他领域的三十余位万粉博主运营。专注于分享 HarmonyOS/OpenHarmony,ArkUI-X,元服务,仓颉,团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙 原生应用,三方库60+,欢迎进行课程,项目等合作。