#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个简单图册展示app(一) 原创

RandomBoolean
发布于 2024-7-27 17:15
浏览
0收藏

登录页面

设计一个简单的登录页面,包含logo、文字名称、手机输入框、验证码输入框、发送验证码按钮、登录按钮。这是一个页面包含的元素。 要实现的效果如图片所示。
#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个简单图册展示app(一)-鸿蒙开发者社区

以下是UI层的布局。
可以看到app.media还有app.float等变量,这些是定义在float.json文件的公共变量。可以写死也可以使用变量来进行定义使用。

如下在第一个Image和第一个Text组件没有使用变量定义属性,可以作为参考使用。$r(‘app.media.huihua’)为图片的路径,这里可以使用自己的图片。

build() {
    Column() {
      Image($r('app.media.huihua'))
        .width('78vp')
        .height('78vp')
        .margin({ top: '100vp', bottom: '8vp' })
      Text('彩绘工坊')
        .fontSize('24vp')
        .fontWeight(FontWeight.Medium)
        .fontColor('#182431')

      Text($r('app.string.login_more'))
        .fontSize($r('app.float.normal_text_size'))
        .fontColor($r('app.color.login_more_text_color'))
        .margin({ bottom: $r('app.float.login_more_margin_bottom'), top: $r('app.float.login_more_margin_top') })

      TextInput({ placeholder: $r('app.string.account') })
        .maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)
        .type(InputType.Number)
        .inputStyle()
        .onChange((value: string) => {
          this.account = value;
        })
      Line().lineStyle()


      Flex({ alignItems: ItemAlign.Center }) {
        TextInput({ placeholder: '验证码' })
          .type(InputType.Number)
          .inputStyle()
          .onChange((value: string) => {
            this.code = value;
          })
        Button(this.isSendSms ? this.sendText : '获取验证码')
          .onClick(() => {
            this.sendSms()
          })
          // .width('20vp')
      }
      Line().lineStyle()


      Button($r('app.string.login'), { type: ButtonType.Capsule })
        .width(CommonConstants.BUTTON_WIDTH)
        .height($r('app.float.login_button_height'))
        .fontSize($r('app.float.normal_text_size'))
        .fontWeight(FontWeight.Medium)
        .backgroundColor($r('app.color.login_button_color'))
        .margin({ top: $r('app.float.login_button_margin_top'), bottom: $r('app.float.login_button_margin_bottom') })
        .clickEffect({
          level: ClickEffectLevel.MIDDLE,
          scale: 0.8
        })
        .onClick(() => {
          this.login();
        })

      if (this.isShowProgress) {
        LoadingProgress()
          .color($r('app.color.loading_color'))
          .width($r('app.float.login_progress_size'))
          .height($r('app.float.login_progress_size'))
          .margin({ top: $r('app.float.login_progress_margin_top') })
      }

      Blank()
    }
    .backgroundColor($r('app.color.background'))
    .height(CommonConstants.FULL_PARENT)
    .width(CommonConstants.FULL_PARENT)
    .padding({
      left: $r('app.float.page_padding_hor'),
      right: $r('app.float.page_padding_hor'),
      bottom: $r('app.float.login_page_padding_bottom')
    })
  }

创建公共变量

接下来是在如下的路径中创建一个公共变量CommonConstants文件
#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个简单图册展示app(一)-鸿蒙开发者社区

文件内代码如下

export default class CommonConstants {
  /*
   * 接口地址
   * */
  static readonly API_URL = 'https://fc-mp-fd1357e1-2f29-4c06-a2a0-ce40a5f54704.next.bspapp.com';


  /**
   * Input length of the account.
   */
  static readonly INPUT_ACCOUNT_LENGTH = 11;

  /**
   *  Input length of the password.
   */
  static readonly INPUT_PASSWORD_LENGTH = 8;

  /**
   *  Left padding of the input box
   */
  static readonly INPUT_PADDING_LEFT = 0;

  /**
   * Delay time of simulated login
   */
  static readonly LOGIN_DELAY_TIME = 2000;

  /**
   * Common Spacing of Components
   */
  static readonly COMMON_SPACE = 12;

  /**
   * Title text of the home page
   */
  static readonly HOME_TITLE = '首页';

  /**
   * Title text of the setting page
   */
  static readonly MINE_TITLE = '我的';

  /**
   * Spacing of other login methods
   */
  static readonly LOGIN_METHODS_SPACE = 44;

  /**
   * The width or height of the component is spread across the parent component.
   */
  static readonly FULL_PARENT = '100%';

  /**
   * The width of button
   */
  static readonly BUTTON_WIDTH = '90%';

  /**
   * The width of setting list
   */
  static readonly SET_LIST_WIDTH = '45%';

  /**
   * Home tab index
   */
  static readonly HOME_TAB_INDEX = 0;

  /**
   * Mine tab index
   */
  static readonly MINE_TAB_INDEX = 1;



  /**
   * Component opacity value: 1.
   */
  static readonly FULL_OPACITY: number = 1;

  /**
   * Component opacity value: 0.6.
   */
  static readonly SIXTY_OPACITY: number = 0.6;

  /**
   * Component opacity value: 0.8.
   */
  static readonly EIGHTY_OPACITY: number = 0.8;

  /**
   * Font weight value: five.
   */
  static readonly FONT_WEIGHT_FIVE: number = 500;

  /**
   * Water flow layout weight value:1.
   */
  static readonly WATER_FLOW_LAYOUT_WEIGHT: number = 1;

  /**
   * Water flow layout columns template.
   */
  static readonly WATER_FLOW_COLUMNS_TEMPLATE: string = '1fr 1fr';

  /**
   * Width the percentage of the 100.
   */
  static readonly FULL_WIDTH: string = '100%';

  /**
   * Height the percentage of the 100.
   */
  static readonly FULL_HEIGHT: string = '100%';

  /**
   * Invalid Index.
   */
  static readonly INVALID_INDEX: number = -1;
}

接着在utils目录中定义一个数据缓存的公共方法preferences
#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个简单图册展示app(一)-鸿蒙开发者社区

该方法用到了dataPreferences数据持久化

import dataPreferences from '@ohos.data.preferences';
import { ValueType } from '@kit.ArkData';

class Preferences {
  private options: dataPreferences.Options;
  private preferences: dataPreferences.Preferences | null = null;


  constructor(name: string) {
    this.options = {
      name
    }
    this.preferences = dataPreferences.getPreferencesSync(getContext(), this.options)
  }

  get(key: string, defValue: ValueType) {
    return this.preferences?.getSync(key, defValue);
  }

  getObj(key: string): ESObject {
    const data = this.preferences?.getSync(key, '').toString()
    return data ? JSON.parse(data) : {}
  }

  put(key: string, value: ESObject) {
    return this.preferences?.putSync(key, value)
  }

  putObj(key: string, value: ESObject) {
    let str = ''
    if (value) {
      str = JSON.stringify(value)
    }
    return this.preferences?.putSync(key, str)
  }

  hasSync(key: string) {
    return this.preferences?.hasSync(key);
  }

  deleteSync(key: string) {
    return this.preferences?.deleteSync(key)
  }



}

export default Preferences

最后一项准备工作是定义一个接口请求方法,因篇幅限制这里暂时不做赘述。最后来看一下登录页面所包含的方法

import { promptAction, router } from '@kit.ArkUI';
import CommonConstants from '../common/constants/CommonConstants';
import Preferences from '../common/utils/preferences';
import LoginViewModel from '../viewmodel/LoginViewModel'


@Extend(TextInput)
function inputStyle() {
  .placeholderColor($r('app.color.placeholder_color'))
  .height($r('app.float.login_input_height'))
  .fontSize($r('app.float.big_text_size'))
  .backgroundColor($r('app.color.background'))
  .width(CommonConstants.FULL_PARENT)
  .padding({ left: CommonConstants.INPUT_PADDING_LEFT })
  .margin({ top: $r('app.float.input_margin_top') })
}

@Extend(Line)
function lineStyle() {
  .width(CommonConstants.FULL_PARENT)
  .height($r('app.float.line_height'))
  .backgroundColor($r('app.color.line_color'))
}

@Extend(Text)
function blueTextStyle() {
  .fontColor($r('app.color.login_blue_text_color'))
  .fontSize($r('app.float.small_text_size'))
  .fontWeight(FontWeight.Medium)
}



/**
 * Login page
 */
@Entry
@Component
export default struct LoginPage {
  @State account: string = '';
  @State code: string = '';
  @State isShowProgress: boolean = false;
  @State isSendSms: boolean = false;
  @State second: number = 60
  @State sendText: string = `${this.second}秒后再次获取验证码`

  private timeOutId: number = -1;
  private sendSmsInterval: number = -1
  private preferences = new Preferences('app_db')

  aboutToAppear(): void {
    if (this.preferences.getObj('userInfo').token) {
      router.replaceUrl({ url: 'pages/MainPage' });
    }
  }

  @Builder
  imageButton(src: Resource) {
    Button({ type: ButtonType.Circle, stateEffect: true }) {
      Image(src)
    }
    .height($r('app.float.other_login_image_size'))
    .width($r('app.float.other_login_image_size'))
    .backgroundColor($r('app.color.background'))
  }

  login(): void {
    if (!this.isValidate()) {
      return
    }
    if (this.code === '') {
      promptAction.showToast({
        message: '请填写验证码'
      })
      return
    }
    this.isShowProgress = true;

    LoginViewModel.login(this.account, this.code).then((res: ESObject) => {
      this.isShowProgress = false;

      if (res.code === 200) {
        this.preferences.putObj('userInfo', res.data)
        router.replaceUrl({ url: 'pages/MainPage' });
      }
    })
  }

  sendSms(): void {
    if (this.isSendSms) {
      promptAction.showToast({
        message: this.sendText
      })
      return
    }
    if (this.isValidate()) {
      LoginViewModel.getCode(this.account).then((res: ESObject) => {
        console.log(JSON.stringify(res.data))
        if (res.code === 200) {
          promptAction.showToast({
            message: '发送验证码'
          })

          this.isSendSms = true
          this.sendSmsInterval = setInterval(() => {
            if (this.second <= 0) {
              this.isSendSms = false
              this.second = 60
              clearInterval(this.sendSmsInterval)
            }
            this.second--
            this.sendText = `${this.second}秒后再次获取验证码`
          }, 1000)
        }

      })

    }
  }

  /*
   * 验证方法
   * */
  isValidate(): boolean {
    if (!this.account) {
      promptAction.showToast({
        message: '请填写手机号'
      })
      return false
    }

    const rex = /^[1][3,4,5,6.7,8,9][0-9]{9}$/
    if (!rex.test(this.account)) {
      promptAction.showToast({
        message: '手机号格式错误'
      })
      return false
    }

    // if (!this.code) {
    //   promptAction.showToast({
    //     message: '请填写验证码'
    //   })
    //   return false
    // }


    return true
  }

  aboutToDisappear() {
    clearTimeout(this.timeOutId);
    this.timeOutId = -1;
    clearInterval(this.sendSmsInterval)
    this.sendSmsInterval = -1
  }

  build() {...这里是上方的ui层 }
}

其中import LoginViewModel from '../viewmodel/LoginViewModel'为导入的接口请求,可以使用settimeout作为模拟登录接口。

输入正确的手机号,点击“获取验证码”按钮执行sendSms方法进行验证,通过之后发送验证码,按钮进入倒计时状态。
输入验证码之后,点击登录,调用接口获取到用户信息,存储到缓存中登录完成。

下一篇文章将介绍首页瀑布流列表和相册图片的展示。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2024-7-27 18:11:49修改
收藏
回复
举报
回复
    相关推荐