返回博客首页
← 所有文章

使用 NativeScript 构建炫酷的登录界面

2018年2月13日 — 作者:TJ VanToll

登录和注册界面是许多移动应用程序不可避免的一部分。在本文中,您将学习如何在 NativeScript 应用程序中快速构建基本的登录界面,以及如何添加更高级的功能。

以下是我们将要构建的表单的最终版本。

login-android login-ios
signup-android signup-ios

注意:此示例的完整代码可在 NativeScript Playground 中找到。值得花点时间从 iOS App Store 或 Google Play 下载“NativeScript Playground”应用程序,以便您在阅读本文时可以在设备上查看此表单。

让我们从了解构成此页面的用户界面组件开始,深入了解其工作原理。

构建 UI

登录表单的主要部分使用 NativeScript 核心主题的类名 来渲染页面的输入和按钮。例如,以下标记创建了两个文本字段和提交按钮——请注意使用核心类名,如 forminput-fieldinputbtnbtn-primary

<StackLayout class="form">
  <StackLayout class="input-field">
    <TextField class="input"></TextField>
  </StackLayout>

  <StackLayout class="input-field">
    <TextField class="input"></TextField>
  </StackLayout>

  <Button text="Log In" class="btn btn-primary"></Button>
</StackLayout>

您可以将此相同的标记复制到您自己的登录表单中,或者尝试使用 NativeScript 核心主题中的其他输入显示选项

完成表单的标记后,接下来需要将表单放置在屏幕上。在讨论解决方案之前,请花点时间查看此登录页面的布局,并注意表单是如何垂直居中的,以及“还没有账号?”标签是如何停靠在屏幕底部的。

login-android 


您可以使用 NativeScript 的 <DockLayout> 控件 来停靠底部的 <Label>,从而解决此布局问题。但是,我个人非常喜欢使用 flexbox 来解决我的布局需求,因为我从 Web 开发时代就熟悉它的 API。以下是此示例用于垂直居中表单和停靠底部标签的标记。

<FlexboxLayout class="page">
  <StackLayout class="form">
    ...
  </StackLayout>

  <Label text="Don’t have an account?"></Label>
</FlexboxLayout>

接下来,您需要一些 CSS 来配置 flexbox 以对齐这些组件。

.page {
  align-items: center;
  flex-direction: column;
}
.form {
  margin-left: 30;
  margin-right: 30;
  flex-grow: 2;
  vertical-align: middle;
}

此 CSS 将 <StackLayout><Label> 组件垂直堆叠 (flex-direction: column),并在屏幕中央对齐 (align-items: center)。最后,将 flex-grow: 2 添加到 <StackLayout> 会告诉 NativeScript 将所有可用的垂直空间分配给表单,确保 <Label> 只占用屏幕底部所需的空间。

提示:CSS Tricks 有一个关于所有 flexbox 属性的 优秀的参考。最好将其添加为书签,因为很容易忘记 align-itemsflex-grow 等属性的确切作用——尤其是在处理非简单示例时。

现在我们已经将登录组件放置在适当的位置,其余的视觉外观可以通过在 CSS 中配置边距、颜色和尺寸来完成。如果您好奇此示例使用的具体值,可以参考 NativeScript Playground 中的 login/login.component.css 文件。

在我们继续使此登录屏幕真正起作用之前,还有一件事我们需要讨论,那就是在 NativeScript 中构建登录表单 UI 时如何配置文本字段。

配置文本字段

默认情况下,如果您在 NativeScript 应用程序中使用 <TextField>,当用户将文本字段聚焦时,他们会看到以下 UI。

default-keyboard 


请注意,键盘没有针对输入电子邮件地址进行优化,并且 iOS 尝试建议一些不太有帮助的自动完成短语。

本文示例使用多个属性来改善用户使用电子邮件文本字段时的体验。

<TextField class="input" hint="Email" keyboardType="email" autocorrect="false" autocapitalizationType="none"></TextField>

keyboardType 属性告诉 iOS 和 Android 提供一个针对电子邮件输入优化的键盘,而 autocorrectautocapitalizationType 属性告诉原生平台不要自动更正和不要自动大写用户输入。结果是一个更容易输入电子邮件地址的文本字段。

optimized-keyboard 

提示:NativeScript 支持 五种不同的键盘类型

现在您已经构建了登录屏幕的用户界面,让我们继续了解如何使表单真正发挥作用。

添加用户交互

登录和注册屏幕通常非常相似。两者通常都要求用户输入电子邮件地址和密码,并且两者通常都具有一些提交按钮。

对于开发人员来说,这意味着您可以选择将登录和注册实现为两个完全独立的页面,或者您可以添加一些 UI 逻辑来为这两个工作流创建一个页面。本文的表单采用了后一种策略,并包含一些逻辑来更改用户与页面交互时的 UI。

让我们看看如何实现这一点。

注意:本文示例使用 Angular,但您绝对可以使用 NativeScript Core 或 NativeScript 与 Vue 来实现完全相同的应用程序。事实上,亲爱的读者,如果您是第一个使用这些架构重新创建此示例并在评论中留下 Playground 链接的人,您可能会在将来收到一些 NativeScript 赠品 😄

此页面的后端组件使用布尔值 isLoggingIn 属性来跟踪用户是否正在尝试登录(而不是注册)。

import { Component } from "@angular/core";

@Component({ ...})
export class LoginComponent {
  isLoggingIn = true;

  toggleForm() {
    this.isLoggingIn = !this.isLoggingIn;
  }

  submit() {
    if (this.isLoggingIn) {
        // Perform the login
    } else {
        // Perform the registration
    }
  }
}

该布尔属性在 UI 中用于切换各种 UI 控件的显示。

<FlexboxLayout class="page">
  <StackLayout class="form">
    <StackLayout class="input-field">
      <TextField hint="Email" ...></TextField>
    </StackLayout>

    <StackLayout class="input-field">
      <TextField hint="Password" ...></TextField>
    </StackLayout>

    <StackLayout *ngIf="!isLoggingIn" class="input-field">
      <TextField hint="Confirm password" ...></TextField>
    </StackLayout>

    <Button [text]="isLoggingIn ? 'Log In' : 'Sign Up'" (tap)="submit()"></Button>
    <Label *ngIf="isLoggingIn" text="Forgot your password?"></Label>
  </StackLayout>

  <Label (tap)="toggleForm()">
    <FormattedString>
      <Span [text]="isLoggingIn ? 'Don’t have an account? ' : 'Back to Login'"></Span>
      <Span [text]="isLoggingIn ? 'Sign up' : ''" class="bold"></Span>
    </FormattedString>
  </Label>
</FlexboxLayout>

布尔属性以两种不同的方式使用。第一种是使用 Angular 的 *ngIf 指令显示和隐藏元素。例如,确认密码字段仅应在注册工作流中显示,并且以下代码中使用 *ngIf="!isLoggingIn 确保确认密码的父容器仅在这种情况存在时才存在。

<StackLayout *ngIf="!isLoggingIn" class="input-field">
  <TextField hint="Confirm password" ...></TextField>
</StackLayout>

isLoggingIn 属性还用于控制屏幕上的一些文本。例如,以下代码根据用户当前是登录还是注册来更改提交按钮的文本。

<Button [text]="isLoggingIn ? 'Log In' : 'Sign Up'" (tap)="submit()"></Button>

此 UI 逻辑的结果在实际操作中如下所示。

switch

UI 的最后一部分是忘记密码功能。尽管您可以通过多种方式实现此类界面,但此示例出于简单起见使用了提示对话框。

忘记密码 UI 的标记是一个绑定到点击事件上的 forgotPassword() 方法的 <Label>

<Label *ngIf="loggingIn" text="Forgot your password?" (tap)="forgotPassword()"></Label>

这是该 tap 处理程序的实现。

import { alert, prompt } from "tns-core-modules/ui/dialogs";

forgotPassword() {
  prompt({
    title: "Forgot Password",
    message: "Enter the email address you used to register for APP NAME to reset your password.",
    defaultText: "",
    okButtonText: "Ok",
    cancelButtonText: "Cancel"
  }).then((data) => {
    if (data.result) {
      // Call the backend to reset the password
      alert({
        title: "APP NAME",
        message: "Your password was successfully reset. Please check your email for instructions on choosing a new password.",
        okButtonText: "Ok"
      })
    }
  });
}

提示是 NativeScript 提供的 众多对话框 之一,使您可以轻松地从用户那里收集单个输入。以下是此功能在实际操作中的样子。

password

当 UI 完全就位后,让我们继续添加一些表单验证并使登录功能正常工作。

处理验证

几乎所有表单都需要验证用户输入,但验证数据的方式和位置可能会有很大差异。此示例仅执行最少的前端验证,依靠后端来验证一些更复杂的事情。

但是,确实有一些验证代码。例如,submit() 方法具有一些逻辑来确保用户同时输入了电子邮件地址和密码。

if (!this.user.email || !this.user.password) {
    alert({ message: "Please provide both an email address and password.", ... );
    return;
}
error1 


register() 方法则检查以确保用户输入的两个密码匹配。

if (this.user.password != this.user.confirmPassword) {
  this.alert("Your passwords do not match.");
  return;
}
error2 


您可以根据应用程序的要求添加更多此类检查。例如,您可以使用 “email-validator”之类的 npm 模块 来检查有效的电子邮件地址,并在用户输入错误的电子邮件地址时提示用户。

如果您正在寻找更全面的解决方案,NativeScript UI DataForm 插件 具有完整的验证框架,包括能够自动在用户界面中直接显示验证消息的功能。

dataform

提示:作为另一个选项,Nic Raboy 撰写了一篇关于如何在 NativeScript 应用程序中利用 Angular 的内置表单验证器 的优秀文章。

现在您已经有了 UI,并且所有必要的视图逻辑都已就位,让我们讨论登录体验的最后一块——后端。

使登录正常工作

NativeScript 是一个支持您想要使用的任何后端的平台,并且许多流行的后端服务的 NativeScript SDK,例如 FirebaseCouchbaseAzure更多

由于您可能希望使用大量服务,因此此示例具有一个用于处理登录任务的通用接口,您可以根据需要实现它。以下是示例的 user.service.ts 文件的高级视图。

import { Injectable } from "@angular/core";
import { User } from "./user.model";

@Injectable()
export class UserService {
    register(user: User) {}

    login(user: User) {}

    resetPassword(email) {}
}

此示例还使用 Kinvey 提供了此通用接口的实现,因为 Kinvey 提供了一个 优秀的 NativeScript SDK,并且 Kinvey 直接在 NativeScript Playground 中受支持。实现如下所示。

import { Injectable } from "@angular/core";
import { Kinvey } from "kinvey-nativescript-sdk";
import { User } from "./user.model";

@Injectable()
export class UserService {
  register(user: User) {
    return new Promise((resolve, reject) => {
      Kinvey.User.logout()
        .then(() => {
          Kinvey.User.signup({ username: user.email, password: user.password })
            .then(resolve)
            .catch((error) => { this.handleErrors(error); reject(); })
        })
        .catch((error) => { this.handleErrors(error); reject(); })
    });
  }

  login(user: User) {
    return new Promise((resolve, reject) => {
      Kinvey.User.logout()
        .then(() => {
          Kinvey.User.login(user.email, user.password)
            .then(resolve)
            .catch((error) => { this.handleErrors(error); reject(); })
        })
        .catch((error) => { this.handleErrors(error); reject(); })
      });
  }

  resetPassword(email) {
    return Kinvey.User.resetPassword(email)
      .catch(this.handleErrors);
  }

  handleErrors(error: Kinvey.BaseError) {
    console.error(error.message);
    return error.message;
  }
}

提示:如果您正在寻找使用 RESTful API 而不是 Kinvey SDK 的此用户服务的实现,请查看 此 Playground 示例

使用 Kinvey,用户管理就像对 login()logout()register()resetPassword() 等方法进行一些调用一样简单。Kinvey 甚至提供了 通过 Facebook 或 Google 帐户登录用户 的方法,以及连接您可能已经在使用的身份服务(如 Active Directory)的功能。如果您想了解有关在 NativeScript 中使用 Kinvey 的更多信息,请查看 Kinvey 的 NativeScript 开发人员中心

现在您已经涵盖了应用程序的后端,让我们用最后一些提示来结束此表单对话。

最终建议

不同的移动应用程序具有不同的登录要求。如果您的登录表单具有本文讨论未涵盖的要求,以下是一些您可能想要考虑使用的 NativeScript 插件。

警告:以下插件在 NativeScript Playground 中不起作用。要将这些插件添加到您自己的应用程序中,您需要 设置本地 NativeScript 开发环境 或使用 NativeScript Sidekick

  • nativescript-IQKeyboardManager——IQKeyboardManager 是一个流行的 iOS 框架,用于开箱即用地提供良好的键盘 UX,包括防止 iOS 键盘覆盖 <TextField> 控件的解决方案。
  • nativescript-fingerprint-auth——nativescript-fingerprint-auth 插件使向您的应用程序添加指纹身份验证变得像安装插件和实现 易于使用的 API 一样简单。该插件还支持 iPhone X 上的 Face ID。
face-id 
  • nativescript-facebook——NativeScript Facebook 插件使您可以轻松地允许用户使用其 Facebook 帐户进行身份验证。
facebook-plugin 
  • nativescript-loading-indicatornativescript-loading-indicator 插件显示一个动画模态框并阻止用户与屏幕交互。该插件非常适合在登录过程中执行后端调用时向用户显示活动指示器。
loading-plugin 
  • nativescript-feedbacknativescript-feedback 插件提供了一种简单的方式来在您的应用中显示外观漂亮的非阻塞消息。您可以使用它来显示比警报更美观的验证消息。
feedback 

希望通过这些提示,您拥有构建出色的用户登录屏幕所需的一切。本文的最终代码再次可在 NativeScript Playground 中获取;请随意使用该代码来启动您自己的 NativeScript 应用。

如果您有任何自己的登录屏幕构建技巧,请随时在评论中分享!