boss直聘鸿蒙版 来了

2,959 阅读4分钟

前言:

之前写过一个demo 但是那个是本地数据 现在我改成网络的 接口是我本地服务的 就想着分享给大家

作者:徐庆

团队:坚果派 公众号:“大前端之旅” 润开鸿生态技术专家,华为HDE,CSDN博客专家,CSDN超级个体,CSDN特邀嘉宾,InfoQ签约作者,OpenHarmony布道师,电子发烧友专家博客,51CTO博客专家,擅长HarmonyOS/OpenHarmony应用开发、熟悉服务卡片开发。欢迎合作。

效果图:

image.png image.png

image.png

image.png

具体实现:

添加权限

image.png

启动本地服务

拿到项目里面的bosstabservice 配置好数据库 启动服务 image.png

客户端实现;

  • 1 底部导航器实现
import CompanylistComponent from '../view/CompanylistComponent';
import MessageListComponent from '../view/MessageListComponent';
import My from '../view/My';
import PositionListComponent from '../view/PositionListComponent';

@Entry
@Component
struct ListIndex {
 private controller: TabsController = new TabsController()
 @State SelectPos:number=0;
 public IndexClick(){
   this.SelectPos=0;
   this.controller.changeIndex(0)
 }
 public messageClick(){
   this.SelectPos=1;
   this.controller.changeIndex(1)
 }
 public myClick(){
   this.SelectPos=2;
   this.controller.changeIndex(2)
 }

 public meClick(){
   this.SelectPos=3;
   this.controller.changeIndex(3)
 }

 build() {
   Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {

     Tabs({ controller: this.controller }) {
       TabContent() {
         PositionListComponent()
       }
       TabContent() {
         CompanylistComponent()
       }
       TabContent() {
          MessageListComponent()
      }
       TabContent() {
         My()
       }
     }
     .scrollable(false)
     .barHeight(0)
     .animationDuration(0)

     Row() {
       Column(){
         Image((this.SelectPos==0?$r('app.media.ic_main_tab_company_pre'):$r('app.media.ic_main_tab_company_nor')))
           .width(30).height(30)
         Text('职位')
           .size({ width: '100%', height: 30 }).textAlign(TextAlign.Center)
           .fontSize(15)
           .fontColor((this.SelectPos==0?Color.Green:Color.Black))
       }
       .layoutWeight(1)
       .backgroundColor($r('app.color.gray2'))
       .height("100%")
       .onClick(this.IndexClick.bind(this))

       Column(){
         Image((this.SelectPos==1?$r('app.media.ic_main_tab_find_pre'):$r('app.media.ic_main_tab_find_nor')))
           .width(30).height(30)
         Text('公司')
           .size({ width: '100%', height: 30 }).textAlign(TextAlign.Center)
           .fontSize(15)
           .fontColor((this.SelectPos==1?Color.Green:Color.Black))
       }
       .layoutWeight(1)
       .backgroundColor($r('app.color.gray2'))
       .height("100%")
       .onClick(this.messageClick.bind(this))

       Column(){
         Image((this.SelectPos==2?$r('app.media.ic_main_tab_contacts_pre'):$r('app.media.ic_main_tab_contacts_nor')))
           .width(30).height(30)
         Text('消息')
           .size({ width: '100%', height: 30 }).textAlign(TextAlign.Center)
           .fontSize(15)
           .fontColor((this.SelectPos==2?Color.Green:Color.Black))
       }
       .layoutWeight(1)
       .backgroundColor($r('app.color.gray2'))
       .height("100%")
       .onClick(this.myClick.bind(this))

       Column(){
         Image((this.SelectPos==3?$r('app.media.ic_main_tab_my_pre'):$r('app.media.ic_main_tab_my_nor')))
           .width(30).height(30)
         Text('我的')
           .size({ width: '100%', height: 30 }).textAlign(TextAlign.Center)
           .fontSize(15)
           .fontColor((this.SelectPos==3?Color.Green:Color.Black))
       }
       .layoutWeight(1)
       .backgroundColor($r('app.color.gray2'))
       .height("100%")
       .onClick(this.meClick.bind(this))


     }.alignItems(VerticalAlign.Bottom).width('100%').height(65).margin({top:0,right:0,bottom:10,left:0})
   }
   .width('100%')
   .height('100%')
 }
}

底部导航使用 Row组件配合 Column 组件实现底导航器 然后配置 Tabs组件实现我们上门的碎片也和底部导航器点击切换效果

职位页面实现:

初始化生命接口 网络请求

async  aboutToAppear(){
  Logger.error(this.TAG+' aboutToAppear  --- > ');
  let networkurl=CommonConstant.DISH;
  await httpRequestGet(networkurl).then((data)=>{
    console.log("data --- > "+data);
    Logger.error("登录请求回调结果 ---> " +data.toString());
    let positionmodel : PositionModel = JSON.parse(data.toString())
    this.JokeList = positionmodel.data

  });
}

解析服务端响应数据创建数据model


export class PositionModel {
  msg: string = ""
  data: Array<Positiondata> = []
  code:number=0
}

export class Positiondata {
  id: string = ""
  name: string = ""
  cname: string = ""
  size: string = ""
  salary: string = ""
  username: string = ""
  title: string = ""
}

解析数据

let positionmodel : PositionModel = JSON.parse(data.toString())
this.JokeList = positionmodel.data

网络请求工具类



import http from '@ohos.net.http';
import Constants, { ContentType } from '../common/Constants';

import Logger from './Logger';

export function httpRequestGet(url: string) {
  return httpRequest(url, http.RequestMethod.GET);
}
/*export function httpRequestGet(url: string, params?:string) {
  return httpRequest(url, http.RequestMethod.GET,params);
}*/

export function httpRequestPost(url: string, params?:string ) {
  return httpRequest(url, http.RequestMethod.POST, params);
}

function httpRequest(url: string, method: http.RequestMethod,params?: string){
  let httpRequest = http.createHttp();
  let responseResult = httpRequest.request(url, {
    method: method,
    readTimeout: Constants.HTTP_READ_TIMEOUT,//读取超时时间 可选,默认为60000ms
    header: {
      'Content-Type': ContentType.JSON
    },
    connectTimeout: Constants.HTTP_READ_TIMEOUT,//连接超时时间  可选,默认为60000ms
    extraData: params // 请求参数
  });
  return responseResult.then((value: http.HttpResponse)=>{
      Logger.error("请求状态 --> "+value.responseCode)
     if(value.responseCode===200){
       Logger.error("请求成功");
       let getresult = value.result;
       Logger.error('请求返回数据', JSON.stringify(getresult));
       return getresult;
     }
  }).catch((err)=>{
    httpRequest.off('headersReceive');
    // 当该请求使用完毕时,调用destroy方法主动销毁
    httpRequest.destroy();
    return "";
  });
}

日志工具类



import hilog from '@ohos.hilog';

class Logger {
  private domain: number;
  private prefix: string;
  private format: string = '%{public}s, %{public}s';

  /**
   * constructor.
   *
   * @param Prefix Identifies the log tag.
   * @param domain Domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF.
   */
  constructor(prefix: string = 'MyApp', domain: number = 0xFF00) {
    this.prefix = prefix;
    this.domain = domain;
  }

  debug(...args: string[]): void {
    hilog.debug(this.domain, this.prefix, this.format, args);
  }

  info(...args: string[]): void {
    hilog.info(this.domain, this.prefix, this.format, args);
  }

  warn(...args: string[]): void {
    hilog.warn(this.domain, this.prefix, this.format, args);
  }

  error(...args: string[]): void {
    hilog.error(this.domain, this.prefix, this.format, args);
  }
}

export default new Logger('HTTPS', 0xFF00)

职位页面布局实现

build() {
     Column(){
       Row(){
         Text('职位')
           .fontSize(30)
           .fontColor(Color.White)
           .textAlign(TextAlign.Center)
       } .width('100%')
       .height(50)
       .backgroundColor(Color.Green)
       .justifyContent(FlexAlign.Center)
       List({ space: commonConst.LIST_ITEM_SPACE }) {

         ForEach(this.JokeList , (item) => {
           ListItem() {
             Row() {
               Column() {
                 Row() {
                   Text(item?.name).fontSize(14).fontColor($r('app.color.gray'))
                   Text(item?.salary).fontSize(20).fontColor($r('app.color.freshRed'))
                     .margin({left:220})
                     .align(Alignment.BottomStart)
                 }.justifyContent(FlexAlign.SpaceAround)
                 .width(commonConst.GOODS_LIST_WIDTH)

                 Text(item?.cname)
                   .fontSize(25)
                   .margin({ left: 10 })
                 Divider().width('80%')
                 Text(item?.username)
                   .fontColor($r('app.color.greentext'))
                   .fontSize(12)
                   .margin({ left:10, top: 10 })
               }
               //.padding(commonConst.GOODS_LIST_PADDING)
               .width(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
               .height(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
               .justifyContent(FlexAlign.Start)
             }
             .justifyContent(FlexAlign.Center)
             .height(commonConst.GOODS_LIST_HEIGHT)
             .width(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
           }
         })
       }
       .width(commonConst.GOODS_LIST_WIDTH)

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

其他的company 公司页面 和message 消息页面和职位页面实现方式类似 我这边就不展开讲了 都是进去页面第一个生命周期进行网络请求 然后解析数据赋值给数组然后渲染在我们的list组件上面

个人页面实现:

@Entry
@Component
export default  struct Discover {
 @State message: string = 'Hello World'

 @Builder NavigationTitle() {
   Row(){
     Text("发现")
       .width('100')
   }
   .width('100%')
   .justifyContent(FlexAlign.Center)
 }

 build() {
   Navigation(){
     List({space:10}){
       ListItemGroup(){
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_0'),titleString:'朋友圈'})
         }
         .backgroundColor(Color.White)
       }
       ListItemGroup(){
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_1'),titleString:'直播'})
         }
         .backgroundColor(Color.White)
       }
       ListItemGroup(){
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_2'),titleString:'扫一扫'})
         }
         .backgroundColor(Color.White)
       }
       ListItemGroup(){
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_3'),titleString:'看一看'})

         }
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_4'),titleString:'搜一搜'})

         }

       }
       .divider({ strokeWidth: 1, color: 'rgb(247,247,247)', startMargin: 0, endMargin: 0 }) // 每行之间的分界线
       .backgroundColor(Color.White)

       ListItemGroup(){
         ListItem(){
           DiscoverRow({imagePath:$r('app.media.discover_5'),titleString:'小程序'})
         }
         .backgroundColor(Color.White)
       }

     }
     .backgroundColor('rgb(237,237,237)')
   }
   .title(this.NavigationTitle())
   .mode(NavigationMode.Stack)
   .titleMode(NavigationTitleMode.Mini)
   .hideBackButton(true)
   // .menus(this.NavigationMenus())
   .size({ width: '100%', height: '100%' })
   .backgroundColor('rgb(237,237,237)')
 }
}

@Component
export  struct DiscoverRow {

 imagePath:Resource
 titleString:string
 build(){
   Flex({direction:FlexDirection.Row,justifyContent:FlexAlign.SpaceBetween,alignItems:ItemAlign.Center}){
     Flex({direction:FlexDirection.Row,alignItems:ItemAlign.Center}){
       Image(this.imagePath)
         .width(22)
         .height(22)
       Text(this.titleString)
         .fontSize(17)
         .margin({left:10})
     }
     .height(50)

     Image($r('app.media.arrow_right'))
       .width(20)
       .height(20)

   }
   .height(50)
   .padding({left:12,right:12})
 }
}

中间部分布局封装

image.png

@Component
export  struct DiscoverRow {

  imagePath:Resource
  titleString:string
  build(){
    Flex({direction:FlexDirection.Row,justifyContent:FlexAlign.SpaceBetween,alignItems:ItemAlign.Center}){
      Flex({direction:FlexDirection.Row,alignItems:ItemAlign.Center}){
        Image(this.imagePath)
          .width(22)
          .height(22)
        Text(this.titleString)
          .fontSize(17)
          .margin({left:10})
      }
      .height(50)

      Image($r('app.media.arrow_right'))
        .width(20)
        .height(20)

    }
    .height(50)
    .padding({left:12,right:12})
  }
}

最后总结:

鸿蒙的 ark ui 非常类似flutter 这种声明式ui 所有的布局都是代码编写的和传统的布局和逻辑分开有些区别 刚开始上手的时候可能不适应,慢慢就习惯了 还有一点 代码嵌套 这个其实可以把每个组件抽离出来就可以解决鸿蒙的ark ui 网络部分也是类似前端的http 请求 解析json和前端也比较像 也有面向对象编程的思想, 对前端和移动端同学来说也比较好理解和学习。 今天的文章就讲到这里有兴趣的 可以自行下载代码学习。 如果你觉得文章还不错麻烦给我三连 关注点赞和转发 如果了解更多鸿蒙开发的知识 可以关注坚果派公众号 。 谢谢