ReactNative 密码生成器实战

效果展示图

在这里插入图片描述

使用插件

  • Formik

    负责表单校验、监听表单提交、数据校验错误信息展示

  • Yup

    负责表单校验规则

分析页面

从上述的展示图我们可以看到的主要元素有:输入框、单选按钮和按钮。其中生成的密码长度不可能很大也不可能为负数和 0,所以我们可以限定密码长度输入框的规则,即密码长度最小 4 位,最大 16 位,所以我们需要进行表单数据校验操作。

因为我们生产的密码包含大小写、数字和特殊字符,所以我们需要有辅助的功能函数来帮我们来支撑业务。而密码生产的业务功能函数可以划分这几个部分:

  • 生成密码字符串

    存放大小写、数字和特殊字符变量,并且判断用户是否勾选了对应的生成条件,例如是否勾选了是否包含小写字母,并且调用创建密码的功能函数

  • 创建密码

    通过用户制定的规则生成对应的密码并返回

  • 重置密码状态

    重置密码生成器中所有数据的状态

构建页面

根据页面分析和页面展示,我们可以首先实现页面的整体搭建和样式名称的定义,具体代码如下:

export default function PasswordCheck() {
    
    
  return (
    <ScrollView keyboardShouldPersistTaps="handled">
      <SafeAreaView style={
    
    styles.appContainer}>
        <View style={
    
    styles.formContainer}>
          <Text style={
    
    styles.title}>密码生产器</Text>
          <View style={
    
    styles.inputWrapper}>
            <View style={
    
    styles.inputColumn}>
              <Text style={
    
    styles.heading}>密码长度</Text>
            </View>
            <TextInput
              style={
    
    styles.inputStyle}
              placeholder="Ex. 8"
              keyboardType="numeric"
            />
          </View>
          <View style={
    
    styles.inputWrapper}>
            <Text style={
    
    styles.heading}>是否包含小写字母</Text>
            <BouncyCheckbox
              disableBuiltInState
              isChecked={
    
    lowerCase}
              fillColor="#29AB87"
            />
          </View>
          <View style={
    
    styles.inputWrapper}>
            <Text style={
    
    styles.heading}>是否包括大写字母</Text>
            <BouncyCheckbox
              disableBuiltInState
              isChecked={
    
    upperCase}
              fillColor="#FED85D"
            />
          </View>
          <View style={
    
    styles.inputWrapper}>
            <Text style={
    
    styles.heading}>是否包括数字</Text>
            <BouncyCheckbox
              disableBuiltInState
              isChecked={
    
    numbers}
              onPress={
    
    () => setNumbers(!numbers)}
              fillColor="#C9A0DC"
            />
          </View>
          <View style={
    
    styles.inputWrapper}>
            <Text style={
    
    styles.heading}>是否包含符号</Text>
            <BouncyCheckbox
              disableBuiltInState
              isChecked={
    
    symbols}
              fillColor="#FC80A5"
            />
          </View>
          <View style={
    
    styles.formActions}>
            <TouchableOpacity style={
    
    styles.primaryBtn}>
              <Text style={
    
    styles.primaryBtnTxt}>生成密码</Text>
            </TouchableOpacity>
            <TouchableOpacity style={
    
    styles.secondaryBtn}>
              <Text style={
    
    styles.secondaryBtnTxt}>重置</Text>
            </TouchableOpacity>
          </View>
        </View>
        {
    
    isPassGenerated ? (
          <View style={
    
    [styles.card, styles.cardElevated]}>
            <Text style={
    
    styles.subTitle}>生成结果:</Text>
            <Text style={
    
    styles.description}>长按密码进行复制</Text>
            <Text selectable={
    
    true} style={
    
    styles.generatedPassword}>
              {
    
    password}
            </Text>
          </View>
        ) : null}
      </SafeAreaView>
    </ScrollView>
  );
}

编写样式

定义好框架后,我们也有对应的样式名称,那么我们就可以逐步实现样式。

const styles = StyleSheet.create({
    
    
  appContainer: {
    
    
    flex: 1,
  },
  formContainer: {
    
    
    margin: 8,
    padding: 8,
  },
  title: {
    
    
    fontSize: 32,
    fontWeight: "600",
    marginBottom: 15,
  },
  subTitle: {
    
    
    fontSize: 26,
    fontWeight: "600",
    marginBottom: 2,
  },
  description: {
    
    
    color: "#758283",
    marginBottom: 8,
  },
  heading: {
    
    
    fontSize: 15,
  },
  inputWrapper: {
    
    
    marginBottom: 15,
    alignItems: "center",
    justifyContent: "space-between",
    flexDirection: "row",
  },
  inputColumn: {
    
    
    flexDirection: "column",
  },
  inputStyle: {
    
    
    padding: 8,
    width: "30%",
    borderWidth: 1,
    borderRadius: 4,
    borderColor: "#16213e",
  },
  errorText: {
    
    
    fontSize: 12,
    color: "#ff0d10",
  },
  formActions: {
    
    
    flexDirection: "row",
    justifyContent: "center",
  },
  primaryBtn: {
    
    
    width: 120,
    padding: 10,
    borderRadius: 8,
    marginHorizontal: 8,
    backgroundColor: "#5DA3FA",
  },
  primaryBtnTxt: {
    
    
    color: "#fff",
    textAlign: "center",
    fontWeight: "700",
  },
  secondaryBtn: {
    
    
    width: 120,
    padding: 10,
    borderRadius: 8,
    marginHorizontal: 8,
    backgroundColor: "#CAD5E2",
  },
  secondaryBtnTxt: {
    
    
    textAlign: "center",
  },
  card: {
    
    
    padding: 12,
    borderRadius: 6,
    marginHorizontal: 12,
  },
  cardElevated: {
    
    
    backgroundColor: "#ffffff",
    elevation: 1,
    shadowOffset: {
    
    
      width: 1,
      height: 1,
    },
    shadowColor: "#333",
    shadowOpacity: 0.2,
    shadowRadius: 2,
  },
  generatedPassword: {
    
    
    fontSize: 22,
    textAlign: "center",
    marginBottom: 12,
    color: "#000",
  },
});

编写对应功能函数

我们完成了页面的布局,接下来就是实现生产密码的功能,我这里拆解成生成密码字符串创建密码重置密码状态三个功能函数,具体的功能函数如下:

/**
   * 生成密码字符串
   * @param passwordLength 密码长度
   */
  const generatePasswordString = (passwordLength: number) => {
    let characterList = ''; // 生产密码的所有相关字符

    const upperCaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const lowerCaseChars = 'abcdefghijklmnopqrstuvwxyz';
    const digitChars = '0123456789';
    const specialChars = '!@#$%^&*()_+';

    // 根据用户的选择,把相关字符拼接到characterList中
    if (upperCase) {
      characterList += upperCaseChars
    }
    if (lowerCase) {
      characterList += lowerCaseChars
    }
    if (numbers) {
      characterList += digitChars
    }
    if (symbols) {
      characterList += specialChars
    }

    const passwordResult = createPassword(characterList, passwordLength)

    setPassword(passwordResult)
    setIsPassGenerated(true)
  }

  /**
   * 根据密码总字符串和密码长度生产随机字符串
   *
   * @param characters 生产密码的所有相关字符
   * @param passwordLength 密码长度
   * @returns 生成的随机密码
   */
  const createPassword = (characters: string, passwordLength: number) => {
    let result = ''
    for (let i = 0; i < passwordLength; i++) {
      const characterIndex = Math.round(Math.random() * characters.length)
      result += characters.charAt(characterIndex)
    }
    return result
  }

  /**
   * 密码重置
   */
  const resetPasswordState = () => {
    setPassword('')
    setIsPassGenerated(false)
    setLowerCase(true)
    setUpperCase(false)
    setNumbers(false)
    setSymbols(false)
  }

表单校验

简单介绍 React Native 整合 Formik 实现表单校验中我只是简单介绍了Formik的常用的几个属性,而这次我们要使用如下几个属性:

属性 类型 说明
touched { [field: string]: boolean } 判断表单字符是否已经访问或者修改过
isValid boolean 如果没有错误(即错误对象为空),则返回 true,否则返回 false
handleChange (e: React.ChangeEvent) => void 主键更新 values[key]对应的值,其中 key 是事件发出输入的名称属性。如果 name 属性不存在,handleChange 将查找输入的 id 属性

具体的代码如下:

<Formik
  initialValues={
    
    {
    
     passwordLength: "" }}
  validationSchema={
    
    PasswordSchema}
  onSubmit={
    
    (values) => {
    
    
    generatePasswordString(+values.passwordLength);
  }}
>
  {
    
    ({
    
    
    values,
    errors,
    touched,
    isValid,
    handleChange,
    handleSubmit,
    handleReset,
  }) => (
    <>
      <View style={
    
    styles.inputWrapper}>
        <View style={
    
    styles.inputColumn}>
          <Text style={
    
    styles.heading}></Text>
          {
    
    touched.passwordLength && errors.passwordLength && (
            <Text style={
    
    styles.errorText}>{
    
    errors.passwordLength}</Text>
          )}
        </View>
        <TextInput
          style={
    
    styles.inputStyle}
          value={
    
    values.passwordLength}
          onChangeText={
    
    handleChange("passwordLength")}
          placeholder="例如:8"
          keyboardType="numeric"
        />
      </View>
      <View style={
    
    styles.inputWrapper}>
        <Text style={
    
    styles.heading}>是否包含小写字母</Text>
        <BouncyCheckbox
          disableBuiltInState
          isChecked={
    
    lowerCase}
          onPress={
    
    () => setLowerCase(!lowerCase)}
          fillColor="#29AB87"
        />
      </View>
      <View style={
    
    styles.inputWrapper}>
        <Text style={
    
    styles.heading}>是否包括大写字母</Text>
        <BouncyCheckbox
          disableBuiltInState
          isChecked={
    
    upperCase}
          onPress={
    
    () => setUpperCase(!upperCase)}
          fillColor="#FED85D"
        />
      </View>
      <View style={
    
    styles.inputWrapper}>
        <Text style={
    
    styles.heading}>是否包括数字</Text>
        <BouncyCheckbox
          disableBuiltInState
          isChecked={
    
    numbers}
          onPress={
    
    () => setNumbers(!numbers)}
          fillColor="#C9A0DC"
        />
      </View>
      <View style={
    
    styles.inputWrapper}>
        <Text style={
    
    styles.heading}>是否包含符号</Text>
        <BouncyCheckbox
          disableBuiltInState
          isChecked={
    
    symbols}
          onPress={
    
    () => setSymbols(!symbols)}
          fillColor="#FC80A5"
        />
      </View>
      <View style={
    
    styles.formActions}>
        <TouchableOpacity
          disabled={
    
    !isValid}
          style={
    
    styles.primaryBtn}
          onPress={
    
    () => handleSubmit()}
        >
          <Text style={
    
    styles.primaryBtnTxt}>生成密码</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={
    
    styles.secondaryBtn}
          onPress={
    
    () => {
    
    
            handleReset();
            resetPasswordState();
          }}
        >
          <Text style={
    
    styles.secondaryBtnTxt}>重置</Text>
        </TouchableOpacity>
      </View>
    </>
  )}
</Formik>

完整代码下载

完整代码下载

猜你喜欢

转载自blog.csdn.net/qq_33003143/article/details/132462518