react中使用构建缓存_如何在React中构建密码强度计

react中使用构建缓存

介绍 (Introduction)

Passwords are commonly used for user authentication in most web applications. Because of this, it is important that passwords are stored in a safe way. Over the years, techniques such as one-way password hashing have been employed to hide the real representation of passwords being stored in a database.

在大多数Web应用程序中,密码通常用于用户身份验证。 因此,以安全的方式存储密码非常重要。 多年来,已采用诸如单向密码哈希的技术来隐藏存储在数据库中的密码的真实表示。

Although password hashing is a great step toward securing password, the user still poses a major challenge to password security: a user who uses a common word as a password makes the effort of hashing fruitless, since a brute-force attack can quickly crack such passwords.

尽管密码散列是迈向确保密码安全的重要一步,但用户仍然对密码安全提出了重大挑战:使用普通单词作为密码的用户使散列工作毫无用处,因为蛮力攻击可以很快破解此类密码。 。

To address this, many web applications today insist on users having strong passwords, either by ensuring a minimum password length or some combination of alphanumeric characters and symbols in the password. To measure password strength, Dropbox developed an algorithm for a realistic password strength estimator inspired by password crackers. This algorithm is packaged in a JavaScript library called zxcvbn. In addition, the package contains a dictionary of commonly used English words, names, and passwords.

为了解决这个问题,当今许多Web应用程序都通过确保最小密码长度或密码中字母数字字符和符号的某种组合来要求用户具有强密码。 为了测量密码强度,Dropbox开发了一种算法,用于根据密码破解者的启发来估算真实的密码强度 。 该算法打包在一个名为zxcvbnJavaScript库中。 此外,该软件包还包含常用英语单词,名称和密码的字典。

In this tutorial, we will create a form with fields for full name, email, and password using the React JavaScript framework. We will perform some lightweight form validation and also use the zxcvbn library to estimate the strength of the password in the form while providing visual feedback.

在本教程中,我们将使用React JavaScript框架创建一个包含全名,电子邮件和密码字段的表单。 我们将执行一些轻量级的表单验证,并使用zxcvbn库在提供视觉反馈的同时估算表单中密码的强度。

Check out this CodeSandbox demo of what you will create by the end of this tutorial.

查看此CodeSandbox演示 ,以了解在本教程结束时将创建的内容。

先决条件 (Prerequisites)

Before you begin, ensure that you have a recent version of Node installed on your system.

在开始之前,请确保您的系统上安装了最新版本的Node

To follow this tutorial, you will need the following:

要遵循本教程,您将需要以下内容:

  • A recent version of Node installed on your machine. For more information on how to install this, select your distribution from the How To Install Node.js collection.

    您的计算机上安装了最新版本的Node 。 有关如何安装此组件的更多信息,请从“ 如何安装Node.js”集合中选择您的发行版。

  • yarn installed to run all of your NPM scripts and to install dependencies for the project. You can follow this Yarn installation guide to install yarn on your system.

    已安装yarn来运行所有NPM脚本并安装项目的依赖项。 您可以按照此纱线安装指南在系统上安装yarn

步骤1 —设置应用程序 (Step 1 — Setting Up the Application)

This tutorial will use the create-react-app package to generate your new React application. Run the following command to install create-react-app on your system if you have not installed it already:

本教程将使用create-react-app包生成新的React应用程序。 如果尚未安装create-react-app ,请运行以下命令在系统上安装它:

  • npm install -g create-react-app

    npm install -g create-react-app

Once the installation is complete, start a new React application using the following command:

安装完成后,使用以下命令启动新的React应用程序:

  • create-react-app react-password-strength

    创建React应用程序React密码强度

This command names it react-password-strength, but you can name it whatever you’d like.

该命令将其命名为react-password-strength ,但是您可以根据需要命名。

Note: If you are using npm version 5.2 or higher, it ships with an additional npx binary. Using the npx binary, you don’t need to install create-react-app globally on your system. You can start a new React application with this command: npx create-react-app react-password-strength.

注意:如果您使用的是npm 5.2或更高版本,它将附带一个附加的npx二进制文件。 使用npx二进制文件,您无需在系统上全局安装create-react-app 。 您可以使用以下命令启动新的React应用程序: npx create-react-app react-password-strength

Next, you will install the dependencies needed for the application. Run the following command to install the required dependencies:

接下来,您将安装应用程序所需的依赖项。 运行以下命令以安装所需的依赖项:

  • yarn add zxcvbn isemail prop-types node-sass bootstrap

    纱线添加zxcvbn isemail道具类型node-sass引导程序

This command installs the following dependencies:

此命令将安装以下依赖项:

  • zxcvbn - Aforementioned password-strength estimation library.

    zxcvbn密码强度估计库。

  • isemail - E-mail validation library.

    isemail电子邮件验证库。

  • prop-types - Runtime checking of intended types of properties passed to components.

    prop-types运行时检查传递给组件的属性的预期类型。

  • node-sass - Used to compilie Sass files to CSS.

    node-sass sass-用于将Sass文件编译为CSS。

As you might have noticed, you installed the bootstrap package as a dependency for the application to get some default styling. To include Bootstrap in the application, edit the src/index.js file and add the following line before every other import statement:

您可能已经注意到,您安装了bootstrap软件包作为应用程序的依赖项,以获取一些默认样式。 要将Bootstrap包含在应用程序中,请编辑src/index.js文件,并在所有其他import语句之前添加以下行:

src/index.js
src / index.js
import 'bootstrap/dist/css/bootstrap.min.css';

Finally, start your application:

最后,启动您的应用程序:

  • yarn start

    纱线开始

The application is now started and development can begin. Notice that a browser tab has been opened for you with the live reloading functionality. This will keep in sync with changes in the application as you develop.

现在,该应用程序已启动,可以开始开发了。 请注意,已经为您打开了带有实时重新加载功能的浏览器选项卡。 在开发过程中,这将与应用程序中的更改保持同步。

At this point, your application view will look like the following screenshot:

此时,您的应用程序视图将类似于以下屏幕截图:

第2步-构建组件 (Step 2 — Building the Components)

This application will use a form for full name, email, and password. It will also perform some lightweight form validation on the fields. In this step, you will create the following React components:

此应用程序将使用全名,电子邮件和密码的表单。 它还将在字段上执行一些轻量级的表单验证。 在此步骤中,您将创建以下React组件:

  • FormField - Wraps a form input field with its attributes and change event handler.

    FormField用其属性包装表单输入字段并更改事件处理程序。

  • EmailField - Wraps the email FormField and adds email validation logic to it.

    EmailField包装电子邮件FormField并向其添加电子邮件验证逻辑。

  • PasswordField - Wraps the password FormField and adds the password validation logic to it. Also attaches the password strength meter and some other visual cues to the field.

    PasswordField包装密码FormField并向其添加密码验证逻辑。 还将密码强度计和其他一些视觉提示连接到该字段。

  • JoinForm - The fictitious Join Support Team form that houses the form fields.

    JoinForm虚拟的加入支持团队表单,其中包含表单字段。

Create a components directory inside the src directory of the application to house all of the components.

在应用程序的src目录中创建一个components目录,以容纳所有组件。

FormField组件 (The FormField Component)

Create a new file FormField.js in the src/components directory and add the following code snippet to it:

src/components目录中创建一个新文件FormField.js ,并向其中添加以下代码片段:

src/components/FormField.js
src / components / FormField.js
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';

class FormField extends Component {

  // initialize state
  state = { value: '', dirty: false, errors: [] }

  hasChanged = e => {
    e.preventDefault();

    // destructure props - assign default dummy functions to validator and onStateChanged props
    const { label, required = false, validator = f => f, onStateChanged = f => f } = this.props;

    const value = e.target.value;
    const isEmpty = value.length === 0;
    const requiredMissing = this.state.dirty && required && isEmpty;

    let errors = [];

    if (requiredMissing) {
      // if required and is empty, add required error to state
      errors = [ ...errors, `${label} is required` ];
    } else if ('function' === typeof validator) {
      try {
        validator(value);
      } catch (e) {
        // if validator throws error, add validation error to state
        errors = [ ...errors, e.message ];
      }
    }

    // update state and call the onStateChanged callback fn after the update
    // dirty is only changed to true and remains true on and after the first state update
    this.setState(({ dirty = false }) => ({ value, errors, dirty: !dirty || dirty }), () => onStateChanged(this.state));
  }

  render() {
    const { value, dirty, errors } = this.state;
    const { type, label, fieldId, placeholder, children } = this.props;

    const hasErrors = errors.length > 0;
    const controlClass = ['form-control', dirty ? hasErrors ? 'is-invalid' : 'is-valid' : '' ].join(' ').trim();

    return (
      <Fragment>
        <div className="form-group px-3 pb-2">
          <div className="d-flex flex-row justify-content-between align-items-center">
            <label htmlFor={fieldId} className="control-label">{label}</label>
            {/** Render the first error if there are any errors **/}
            { hasErrors && <div className="error form-hint font-weight-bold text-right m-0 mb-2">{ errors[0] }</div> }
          </div>
          {/** Render the children nodes passed to component **/}
          {children}
          <input type={type} className={controlClass} id={fieldId} placeholder={placeholder} value={value} onChange={this.hasChanged} />
        </div>
      </Fragment>
    );
  }

}

FormField.propTypes = {
  type: PropTypes.oneOf(["text", "password"]).isRequired,
  label: PropTypes.string.isRequired,
  fieldId: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  required: PropTypes.bool,
  children: PropTypes.node,
  validator: PropTypes.func,
  onStateChanged: PropTypes.func
};

export default FormField;

We are doing a handful of stuff in this component. Let’s break it down a little bit:

我们在此组件中做了一些工作。 让我们分解一下:

Input State: First, you initialized state for the form field component to keep track of the current value of the input field, the dirty status of the field, and any existing validation errors. A field becomes dirty the moment its value first changes and remains dirty.

输入状态 :首先,为表单字段组件初始化state ,以跟踪输入字段的当前value ,该字段的dirty状态以及任何现有的验证errors 。 字段在其值第一次更改时即变并保持脏状态。

Handle Input Change: Next, you added the hasChanged(e) event handler to update the state value to the current input value on every change to the input. In the handler, you also resolve the dirty state of the field. You check if the field is a required field based on props, and add a validation error to the state errors array if the value is empty.

处理输入更改 :接下来,添加了hasChanged(e)事件处理程序,以在每次输入更改时将状态value更新为当前输入值。 在处理程序中,您还可以解决字段的dirty状态。 您检查该字段是否为基于prop的required字段,如果该值为空,则将验证错误添加到状态errors数组。

However, if the field is not a required field or is required but not empty, then you delegate to the validation function passed in the optional validator prop, calling it with the current input value, and adding the thrown validation error to the state errors array (if there is any error).

但是,如果该字段不是必填字段,也不是必填字段,则为空,那么您将委派给可选validator prop中传递的验证函数,并使用当前输入值对其进行调用,并将抛出的验证错误添加到状态errors数组(如果有任何错误)。

Finally, you update the state and pass a callback function to be called after the update. The callback function calls the function passed in the optional onStateChanged prop, passing the updated state as its argument. This will become handy for propagating state changes outside the component.

最后,您更新状态并传递在更新后要调用的回调函数。 回调函数调用在可选的onStateChanged传递的函数,并将更新后的状态作为其参数传递。 这对于在组件外部传播状态更改将变得很方便。

Rendering and Props: Here you are rendering the input field and its label. You also conditionally render the first error in the state errors array (if there are any errors). Notice how you dynamically set the classes for the input field to show validation status using built-in classes from Bootstrap. You also render any children nodes contained in the component.

渲染和道具 :在这里渲染输入字段及其标签。 您还可以有条件地在状态errors数组中呈现第一个错误(如果存在任何错误)。 注意,如何使用Bootstrap中的内置类动态设置输入字段的类以显示验证状态。 您还可以渲染组件中包含的所有子节点。

As seen in the component’s propTypes, the required props for this component are type ('text' or 'password'), label, placeholder, and fieldId. The remaining components are optional.

从组件的propTypes可以看出,该组件所需的props是type ( 'text''password' ), labelplaceholderfieldId 。 其余组件是可选的。

EmailField组件 (The EmailField Component)

Create a new file EmailField.js in the src/components directory and add the following code snippet to it:

src/components目录中创建一个新文件EmailField.js ,并向其中添加以下代码片段:

src/components/EmailField.js
src / components / EmailField.js
import React from 'react';
import PropTypes from 'prop-types';
import { validate } from 'isemail';

import FormField from './FormField';

const EmailField = props => {

  // prevent passing type and validator props from this component to the rendered form field component
  const { type, validator, ...restProps } = props;

  // validateEmail function using the validate() method of the isemail package
  const validateEmail = value => {
    if (!validate(value)) throw new Error('Email is invalid');
  };

  // pass the validateEmail to the validator prop
  return <FormField type="text" validator={validateEmail} {...restProps} />
};

EmailField.propTypes = {
  label: PropTypes.string.isRequired,
  fieldId: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  required: PropTypes.bool,
  children: PropTypes.node,
  onStateChanged: PropTypes.func
};

export default EmailField;

In the EmailField component, you are rendering a FormField component and passing an email validation function to the validator prop. You are using the validate() method of the isemail package for the email validation.

EmailField组件中,您正在呈现FormField组件,并将电子邮件验证功能传递给validator prop。 您正在使用isemail包的validate()方法进行电子邮件验证。

You may also notice that all other props except the type and validator props are transferred from the EmailField component to the FormField component.

您可能还会注意到,除typevalidator道具以外的所有其他道具都已从EmailField组件传输到FormField组件。

PasswordField组件 (The PasswordField Component)

Create a new file PasswordField.js in the src/components directory and add the following code snippet to it:

src/components目录中创建一个新文件PasswordField.js ,并向其中添加以下代码片段:

src/components/PasswordField.js
src / components / PasswordField.js
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import zxcvbn from 'zxcvbn';

import FormField from './FormField';

class PasswordField extends Component {

  constructor(props) {

    super(props);
    const { minStrength = 3, thresholdLength = 7 } = props;

    // set default minStrength to 3 if not a number or not specified
    // minStrength must be a a number between 0 - 4

    this.minStrength = typeof minStrength === 'number'
      ? Math.max( Math.min(minStrength, 4), 0 )
      : 3;

    // set default thresholdLength to 7 if not a number or not specified
    // thresholdLength must be a minimum value of 7

    this.thresholdLength = typeof thresholdLength === 'number'
      ? Math.max(thresholdLength, 7)
      : 7;

    // initialize internal component state
    this.state = { password: '', strength: 0 };
  };

  stateChanged = state => {

    // update the internal state using the updated state from the form field

    this.setState({
      password: state.value,
      strength: zxcvbn(state.value).score
    }, () => this.props.onStateChanged(state));

  };

  validatePasswordStrong = value => {
    // ensure password is long enough
    if (value.length <= this.thresholdLength) throw new Error("Password is short");

    // ensure password is strong enough using the zxcvbn library
    if (zxcvbn(value).score < this.minStrength) throw new Error("Password is weak");
  };

  render() {
    const { type, validator, onStateChanged, children, ...restProps } = this.props;
    const { password, strength } = this.state;

    const passwordLength = password.length;
    const passwordStrong = strength >= this.minStrength;
    const passwordLong = passwordLength > this.thresholdLength;

    // dynamically set the password length counter class
    const counterClass = ['badge badge-pill', passwordLong ? passwordStrong ? 'badge-success' : 'badge-warning' : 'badge-danger'].join(' ').trim();

    // password strength meter is only visible when password is not empty
    const strengthClass = ['strength-meter mt-2', passwordLength > 0 ? 'visible' : 'invisible'].join(' ').trim();

    return (
      <Fragment>
        <div className="position-relative">
          {/** Pass the validation and stateChanged functions as props to the form field **/}
          <FormField type="password" validator={this.validatePasswordStrong} onStateChanged={this.stateChanged} {...restProps}>
            <span className="d-block form-hint">To conform with our Strong Password policy, you are required to use a sufficiently strong password. Password must be more than 7 characters.</span>
            {children}
            {/** Render the password strength meter **/}
            <div className={strengthClass}>
              <div className="strength-meter-fill" data-strength={strength}></div>
            </div>
          </FormField>
          <div className="position-absolute password-count mx-3">
            {/** Render the password length counter indicator **/}
            <span className={counterClass}>{ passwordLength ? passwordLong ? `${this.thresholdLength}+` : passwordLength : '' }</span>
          </div>
        </div>
      </Fragment>
    );
  }

}

PasswordField.propTypes = {
  label: PropTypes.string.isRequired,
  fieldId: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  required: PropTypes.bool,
  children: PropTypes.node,
  onStateChanged: PropTypes.func,
  minStrength: PropTypes.number,
  thresholdLength: PropTypes.number
};

export default PasswordField;

This component is using the zxcvbn JavaScript password strength estimator package. The package exports a zxcvbn() function that takes a password string as its first argument and returns an object with several properties for the password strength estimation. In this tutorial, we would be concerned only with the score property, which is an integer from 0 - 4, which can be useful for implementing a visual strength bar.

该组件正在使用zxcvbn JavaScript密码强度估算器软件包。 程序包导出一个zxcvbn()函数,该函数将密码字符串作为第一个参数,并返回一个具有多个属性的对象,用于估计密码强度。 在本教程中,我们将只关注score属性,该属性是04的整数,对于实现视觉强度条很有用。

Here is a breakdown of what is happening in the PasswordField component:

这是PasswordField组件中发生的情况的细分:

Initialization: In the constructor(), you created two instance properties, thresholdLangth and minStrength, from their corresponding prop passed to the component. The thresholdLength is the minimum password length before it can be considered sufficiently long. It defaults to 7 and cannot be lower. The minStrength is the minimum zxcvbn score before the password is considered to be strong enough. Its value ranges from 0-4. It defaults to 3 if not specified.

初始化 :在constructor() ,您从传递给组件的对应属性创建了两个实例属性thresholdLangthminStrengththresholdLength是可以认为足够长的最小密码长度。 它的默认值为7 ,并且不能更低。 minStrength是密码被认为足够强之前的最低zxcvbn分数。 其值的范围是0-4 。 如果未指定,则默认为3

You also initialized the internal state of the password field to store the current password and password strength.

您还初始化了密码字段的内部状态以存储当前password和密码strength

Handling Password Changes: You defined a password validation function that will be passed to the validator prop of the underlying FormField component. The function ensures that the password length is longer than the thresholdLength and also has a minimum zxcvbn() score of the specified minStrength.

处理密码更改 :您定义了一个密码验证功能,该功能将传递给基础FormField组件的validator支持。 该函数可确保密码长度大于thresholdLength ,并且具有指定minStrength的最小zxcvbn()分数。

You also defined a stateChanged() function, which will be passed to the onStateChanged prop of the FormField component. This function retrieves the updated state of the FormField component and uses it to compute and update the new internal state of the PasswordField component.

您还定义了一个stateChanged()函数,该函数将传递给FormField组件的onStateChanged属性。 此函数检索FormField组件的更新状态,并使用它来计算和更新PasswordField组件的新内部状态。

The callback function will be called after the internal state update. The callback function calls the function passed in the optional onStateChanged prop of the PasswordField component, passing the updated FormField state as its argument.

内部状态更新后将调用回调函数。 回调函数调用在PasswordField组件的可选onStateChanged传递的函数,并将更新的FormField状态作为其参数传递。

Rendering and Props: Here you rendered the underlying FormField component alongside some elements for input hint, password strength meter, and password length counter.

渲染和道具 :在这里,您将基础FormField组件与输入提示密码强度计密码长度计数器的某些元素一起呈现。

The password strength meter indicates the strength of the current password based on the state and is configured to be dynamically invisible if the password length is 0. The meter will indicate different colors for different strength levels.

密码强度计根据状态指示当前passwordstrength ,并配置为在密码长度为0动态invisible 。 仪表将针对不同的强度级别指示不同的颜色。

The password length counter indicates when the password is long enough. It shows the password length if the password is not longer than the thresholdLength, otherwise it shows the thresholdLength followed by a plus(+).

密码长度计数器指示密码何时足够长。 如果密码不超过thresholdLength ,则显示密码长度;否则,显示thresholdLength后跟plus(+)

The PasswordField component accepts two additional optional fields, minStrength and thresholdLength, as defined in the component’s propTypes.

PasswordField组件接受两个附加的可选字段minStrengththresholdLength ,这在组件的propTypes定义。

JoinForm组件 (The JoinForm Component)

Create a new file JoinForm.js in the src/components directory and add the following code snippet to it:

src/components目录中创建一个新文件JoinForm.js ,并向其中添加以下代码片段:

src/components/JoinForm.js
src / components / JoinForm.js
import React, { Component } from 'react';

import FormField from './FormField';
import EmailField from './EmailField';
import PasswordField from './PasswordField';

class JoinForm extends Component {

  // initialize state to hold validity of form fields
  state = { fullname: false, email: false, password: false }

  // higher-order function that returns a state change watch function
  // sets the corresponding state property to true if the form field has no errors
  fieldStateChanged = field => state => this.setState({ [field]: state.errors.length === 0 });

  // state change watch functions for each field
  emailChanged = this.fieldStateChanged('email');
  fullnameChanged = this.fieldStateChanged('fullname');
  passwordChanged = this.fieldStateChanged('password');

  render() {
    const { fullname, email, password } = this.state;
    const formValidated = fullname && email && password;

    // validation function for the fullname
    // ensures that fullname contains at least two names separated with a space
    const validateFullname = value => {
      const regex = /^[a-z]{2,}(\s[a-z]{2,})+$/i;
      if (!regex.test(value)) throw new Error('Fullname is invalid');
    };

    return (
      <div className="form-container d-table-cell position-relative align-middle">
        <form action="/" method="POST" noValidate>

          <div className="d-flex flex-row justify-content-between align-items-center px-3 mb-5">
            <legend className="form-label mb-0">Support Team</legend>
            {/** Show the form button only if all fields are valid **/}
            { formValidated && <button type="button" className="btn btn-primary text-uppercase px-3 py-2">Join</button> }
          </div>

          <div className="py-5 border-gray border-top border-bottom">
            {/** Render the fullname form field passing the name validation fn **/}
            <FormField type="text" fieldId="fullname" label="Full Name" placeholder="Enter Full Name" validator={validateFullname} onStateChanged={this.fullnameChanged} required />

            {/** Render the email field component **/}
            <EmailField fieldId="email" label="Email" placeholder="Enter Email Address" onStateChanged={this.emailChanged} required />

            {/** Render the password field component using thresholdLength of 7 and minStrength of 3 **/}
            <PasswordField fieldId="password" label="Password" placeholder="Enter Password" onStateChanged={this.passwordChanged} thresholdLength={7} minStrength={3} required />
          </div>

        </form>
      </div>
    );
  }

}

export default JoinForm;

The JoinForm component wraps the form field components that make up our form. We initialized state to hold the validity of the three form fields: fullname, email, and password. They are all false, or invalid, initially.

JoinForm组件包装构成表单的表单字段组件。 我们初始化状态以保持三个表单字段的有效性: fullnameemailpassword 。 最初它们都是falseinvalid

We also defined state change watch functions for each field to update the form state accordingly. The watch function checks if there are no errors in a field and updates the form internal state for that field to true, or valid. These watch functions are then assigned to the onStateChanged prop of each form field component to monitor state changes.

我们还为每个字段定义了状态更改监视功能,以相应地更新表单状态。 watch函数检查字段中是否没有errors ,并将该字段的表单内部状态更新为truevalid 。 然后,将这些监视功能分配给每个表单字段组件的onStateChanged属性,以监视状态更改。

Finally, the form is rendered. Notice that you added a validation function to the fullname field to ensure that at least two names, separated by a space and containing only alphabet characters, are provided.

最后,呈现表单。 请注意,您已在fullname名字段中添加了一个验证功能,以确保至少提供两个用空格分隔并且仅包含字母字符的名称。

App组件 (The App Component)

Up until this point, the browser still renders the boilerplate React application. Now you will modify the App.js file in the src directory to render the JoinForm inside the AppComponent.

到目前为止,浏览器仍然呈现样板React应用程序。 现在,您将修改src目录中的App.js文件,以在JoinForm呈现AppComponent

The App.js file will look like the following snippet:

App.js文件将类似于以下片段:

src/App.js
src / App.js
import React from 'react';
import JoinForm from './components/JoinForm';
import './App.css';

function App() {
  return (
    <div className="main-container d-table position-absolute m-auto">
      <JoinForm />
    </div>
  );
}

export default App;

步骤3 —用Sass样式 (Step 3 — Styling with Sass)

You are one step away from the final look and feel of your application. At the moment, everything may seem a little out of place. In this step, you will go ahead and define some style rules to style the form.

您距离应用程序的最终外观只有一步之遥。 目前,一切似乎都不合时宜。 在这一步中,您将继续定义一些样式规则以样式化表单。

In order to take advantage of powerful Sass variables, nesting, and loops, we have previously installed the dependency of node-sass. You are using Sass to generate a CSS file that browsers can understand.

为了利用强大的Sass变量,嵌套和循环,我们之前已经安装了node-sass的依赖项。 您正在使用Sass生成浏览器可以理解CSS文件。

There are two things you will need to change to utilize Sass in your application after installing the dependency:

安装依赖项后,需要更改两件事以在应用程序中使用Sass:

  • Rename the file src/App.css to src/App.scss.

    将文件src/App.css重命名为src/App.scss

  • Edit the import line in src/App.js to reference the renamed file.

    编辑src/App.js的导入行以引用重命名的文件。

After renaming the src/App.css file, update your src/App.js file to the following:

重命名后src/App.css文件,更新你src/App.js文件如下:

src/App.js
src / App.js
import './App.scss';

Save and close the file.

保存并关闭文件。

Next, replace the existing content in the App.scss file with the following code to format the application:

接下来,用以下代码替换App.scss文件中的现有内容,以格式化应用程序:

src/App.scss
src / App.scss
/** Declare some variables **/
$primary: #007bff;

// Password strength meter color for the different levels
$strength-colors: (darkred, orangered, orange, yellowgreen, green);

// Gap width between strength meter bars
$strength-gap: 6px;

body {
  font-size: 62.5%;
}

.main-container {
  width: 400px;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.form-container {
  bottom: 100px;
}

legend.form-label {
  font-size: 1.5rem;
  color: desaturate(darken($primary, 10%), 60%);
}

.control-label {
  font-size: 0.8rem;
  font-weight: bold;
  color: desaturate(darken($primary, 10%), 80%);
}

.form-control {
  font-size: 1rem;
}

.form-hint {
  font-size: 0.6rem;
  line-height: 1.4;
  margin: -5px auto 5px;
  color: #999;

  &.error {
    color: #C00;
    font-size: 0.8rem;
  }
}

button.btn {
  letter-spacing: 1px;
  font-size: 0.8rem;
  font-weight: 600;
}

.password-count {
  bottom: 16px;
  right: 10px;
  font-size: 1rem;
}

.strength-meter {
  position: relative;
  height: 3px;
  background: #DDD;
  margin: 7px 0;
  border-radius: 2px;

  // Dynamically create the gap effect
  &:before,
  &:after {
    content: '';
    height: inherit;
    background: transparent;
    display: block;
    border-color: #FFF;
    border-style: solid;
    border-width: 0 $strength-gap 0;
    position: absolute;
    width: calc(20% + #{$strength-gap});
    z-index: 10;
  }

  // Dynamically create the gap effect
  &:before {
    left: calc(20% - #{($strength-gap / 2)});
  }

  // Dynamically create the gap effect
  &:after {
    right: calc(20% - #{($strength-gap / 2)});
  }
}

.strength-meter-fill {
  background: transparent;
  height: inherit;
  position: absolute;
  width: 0;
  border-radius: inherit;
  transition: width 0.5s ease-in-out, background 0.25s;

  // Dynamically generate strength meter color styles
  @for $i from 1 through 5 {
    &[data-strength='#{$i - 1}'] {
      width: (20% * $i);
      background: nth($strength-colors, $i);
    }
  }
}

You have succeeded in adding the styles required by your application. Notice the use of generated CSS content in the .strength-meter:before and .strength-meter:after pseudo-elements to add gaps to the password strength meter.

您已成功添加了应用程序所需的样式。 请注意,在.strength-meter:before.strength-meter:after伪元素中使用了生成CSS内容,以向密码强度表添加空白。

You also used the Sass @for directive to dynamically generate fill colors for the strength meter at different password strength levels.

您还使用Sass @for指令为强度计在不同的密码强度级别下动态生成填充颜色。

The final app screen will look like this:

最终的应用程序屏幕将如下所示:

With validation errors, the screen will look like this:

出现验证错误时,屏幕将如下所示:

Without any errors, when all fields are valid, the screen will look like this:

没有任何错误,当所有字段均有效时,屏幕将如下所示:

结论 (Conclusion)

In this tutorial, you created a password strength meter based on the zxcvbn JavaScript library in your React application. For a detailed usage guide and documentation of the zxcvbn library, see the zxcvbn repository on GitHub. For a complete code sample of this tutorial, checkout the password-strength-react-demo repository on GitHub. You can also get a live demo of this tutorial on Code Sandbox.

在本教程中,您基于React应用程序中的zxcvbn JavaScript库创建了密码强度计。 有关zxcvbn库的详细使用指南和文档,请参阅GitHub上的zxcvbn存储库。 有关本教程的完整代码示例,请检出GitHub上的password-strength-react-demo存储库。 您还可以在Code Sandbox上获得本教程实时演示

If you are interested in the AngularJS version of this article, you can take a look at: Password Strength Meter in AngularJS.

如果您对本文的AngularJS版本感兴趣,可以看一下: AngularJS中的Password Strength Meter

翻译自: https://www.digitalocean.com/community/tutorials/how-to-build-a-password-strength-meter-in-react

react中使用构建缓存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值