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开发了一种算法,用于根据密码破解者的启发来估算真实的密码强度 。 该算法打包在一个名为zxcvbn
JavaScript库中。 此外,该软件包还包含常用英语单词,名称和密码的字典。
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 installyarn
on your system.
步骤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
语句之前添加以下行:
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 emailFormField
and adds email validation logic to it.EmailField
包装电子邮件FormField
并向其添加电子邮件验证逻辑。PasswordField
- Wraps the passwordFormField
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
,并向其中添加以下代码片段:
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'
), label
, placeholder
和fieldId
。 其余组件是可选的。
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
,并向其中添加以下代码片段:
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.
您可能还会注意到,除type
和validator
道具以外的所有其他道具都已从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
,并向其中添加以下代码片段:
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属性,该属性是0
到4
的整数,对于实现视觉强度条很有用。
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()
,您从传递给组件的对应属性创建了两个实例属性thresholdLangth
和minStrength
。 thresholdLength
是可以认为足够长的最小密码长度。 它的默认值为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.
密码强度计根据状态指示当前password
的strength
,并配置为在密码长度为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
组件接受两个附加的可选字段minStrength
和thresholdLength
,这在组件的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
,并向其中添加以下代码片段:
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
组件包装构成表单的表单字段组件。 我们初始化状态以保持三个表单字段的有效性: fullname
, email
和password
。 最初它们都是false
或invalid
。
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
,并将该字段的表单内部状态更新为true
或valid
。 然后,将这些监视功能分配给每个表单字段组件的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
文件将类似于以下片段:
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
tosrc/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
文件如下:
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
文件中的现有内容,以格式化应用程序:
/** 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中使用构建缓存