国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

react如何實(shí)現一個(gè)密碼強度檢測器詳解

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:正經(jīng)修行人 欄目: JavaScript 歡迎投稿:712375056

目錄

        前言

        密碼強度文件校驗器; 注冊帳號的時(shí)候我們需要對用戶(hù)當前的密碼強度進(jìn)行一個(gè)評估,這個(gè)過(guò)程我們需要做一個(gè)檢測器,最好寫(xiě)的靈活點(diǎn),這樣方便產(chǎn)品修改規則。

        先看下效果吧~~   下面是截圖對應的狀態(tài)

        使用

        1 參數傳遞

        const PasswordForce = passwordForce({     inputValue,     className: 'password-force',   });

        2 使用

        <PasswordForce.View />

        3 校驗

        檢測是否超出字符PasswordForce.invaildWord

        實(shí)現例子

        我們配置antd實(shí)現下密碼輸入框上面綁定一個(gè)提示器吧

        1,2都是不需要改的,但是實(shí)際我們需要監聽(tīng)input的值然后設置值。于是我們可以定義一個(gè)監聽(tīng)修改value的函數

        const [inputValue, setInputValue] = useState('');
            const passwordChange = (value: string) => {
            setInputValue(value);
        };
        const onPasswordInput = (e: any) => {
            passwordChange(e?.target?.value || '');
        };
        

        然后綁定即可,綁定好了我們就可以正常顯示了,但是,如果輸入了非法字符,這時(shí)候我們需要通過(guò)攔截器攔截。

        <Form.Item
        ...
        rules={[
            {
              required: true,
              message: 'Password not empty',
            },
            ({ getFieldValue }) => ({
              validator(_, value) {
                passwordChange(value);
                if (PasswordForce.invaildWord) {
                  return Promise.reject(
                    new Error('Password contains invalid characters.'),
                  );
                }
                return Promise.resolve();
              },
            }),
        ]}
        ...
        

        好了,使用片結束,我們實(shí)現下吧。

        組件編寫(xiě)

        編寫(xiě)組件

        import {
          getRuleMatchResult,
          IpasswordForce,
          IpasswordRule,
          isMatchForceResultConfig,
          matchResultConfig,
          passwordBreakKey,
        } from '@/utils/passwordStrengthChecker';
        import React, { CSSProperties } from 'react';
        import { useEffect } from 'react';
        import { useState } from 'react';
        import styled from 'styled-components';
        
        interface props {
          inputValue: string;
          color?: string;
          style?: CSSProperties;
          className?: string;
          customRule?: IpasswordRule[];
        }
        enum ForceMap {
          high = 'High',
          middle = 'Mid',
          low = 'Low',
        }
        const boolNumSum = (list: boolean[]) =>
          list.reduce<number>(
            (previousValue, currentValue) =>
              currentValue ? previousValue + 1 : previousValue,
            0,
          );
        
        const passwordForce: (props: props) => {
          View: React.FC;
          invaildWord: boolean;
          force: IpasswordForce;
        } = ({ inputValue, style = {}, className, customRule = [] }) => {
          const [force, setforce] = useState<IpasswordForce>(false);
          const [invaildWord, setIsInvaildWord] = useState(false);
          const inputValueLen = inputValue?.length || 0;
          const setData = () => {
            setforce(false);
            const isFirstWordUp = inputValue[0] === inputValue[0].toLocaleUpperCase();
            const ruleRsult = getRuleMatchResult(customRule, inputValue, undefined, '');
            const matchNum = boolNumSum(ruleRsult.list.map((e) => e[passwordBreakKey]));
            const matchResultConfig: matchResultConfig[] = [
              { min: 0, max: 32, matchNum: 1, value: 'low' },
              { min: 7, max: 32, matchNum: 2, value: 'middle' },
              { min: 7, max: 32, matchNum: 3, value: 'middle' },
              { min: 15, max: 32, matchNum: 3, value: 'high', need: isFirstWordUp },
            ];
            setIsInvaildWord(ruleRsult.invaildWord);
            matchResultConfig.forEach((config) => {
              isMatchForceResultConfig(config, matchNum, inputValueLen) &&
                setforce(config.value);
            });
          };
          useEffect(() => {
            inputValue ? setData() : setforce(false);
          }, [inputValue]);
          return {
            View: () =>
              force ? (
                <PasswordForceWrap {...{ style, className }}>
                  {ForceMap[force]}
                </PasswordForceWrap>
              ) : (
                <></>
              ),
            invaildWord,
            force,
          };
        };
        export default passwordForce;
        
        const PasswordForceWrap = styled.span`
          color: ${({ color }) => color ?? '#000'};
        `;
        
        

        數據結構解析

        • list 規則的集合,每一個(gè)規則都有是否匹配到和規則名及已規則數據本身。
        • map 就是方便直接獲取對應規則的數據。
        • matchCount 就是匹配到的字符數
        • invaildWord 可以根據這個(gè)來(lái)判斷是否有非法字符(超過(guò)規則本身規定的字符)

        流程解析

        這個(gè)其實(shí)就兩個(gè)流程

        • 根據輸入的值和規則獲取處理后的數據,獲得的數據結構如上面所示。
        • 然后再編寫(xiě)具體符合業(yè)務(wù)需求的config數據交給isMatchForceResultConfig函數去匹配設置強度

        嗯。 業(yè)務(wù)代碼差不多就這么多了。 然后里面關(guān)于依賴(lài)那就是屬于基本不會(huì )改動(dòng)的代碼,基于下面底層的文件,在業(yè)務(wù)代碼我們可以配置出很復雜的校驗器,這部分代碼我們可以在其他文件上實(shí)現。

        底層代碼解析

        讓我們來(lái)康康吧。

        下面是純ts代碼,可以運行任意框架哦。

        passwordStrengthChecker.ts

        import { numberList, specialList, wordList } from './constants';
        
        type map = <U, T>(opstion: {
          array: U[];
          range: number;
          matchList: T[];
          tokenMap: (updateItem: T, token: U, index: number) => T;
          breakKey?: string;
          arrayMap?: (item: U, index: number) => void;
        }) => T[];
        
        /**
         * match array and set
         */
        export const setArrayMatch: map = ({
          array,
          range,
          matchList,
          breakKey,
          tokenMap,
          arrayMap,
        }) => {
          const tokenLen = array.length;
          for (let tokenIndex = tokenLen - 1; tokenIndex >= 0; tokenIndex--) {
            const arrayToken = array[tokenIndex];
            arrayMap && arrayMap(arrayToken, tokenIndex);
            for (let findIndex = range - 1; findIndex >= 0; findIndex--) {
              matchList = matchList.map((item) =>
                tokenMap(item, arrayToken, findIndex),
              );
            }
            if (breakKey && !matchList.map((e) => (e as any)[breakKey]).includes(false))
              break;
          }
          return matchList;
        };
        
        export const passwordBreakKey = 'isMatch';
        export type IpasswordRule = {
          list: string[];
          isMatch: boolean;
          name: string;
        };
        export const defaultPasswordRuleList = [
          { name: 'special', list: specialList },
          { name: 'num', list: numberList },
          { name: 'word', list: wordList },
        ];
        
        type PickValue<T, K extends keyof T> = T[K];
        
        export const getRuleMatchResult: (
          customRule: IpasswordRule[],
          inputValue: string,
          disableDefaultRule?: boolean,
          breakKey?: string,
        ) => {
          list: IpasswordRule[];
          map: Map<PickValue<IpasswordRule, 'name'>, boolean>;
          matchCount: number;
          invaildWord: boolean;
        } = (customRule, inputValue, disableDefaultRule = true, breakKey) => {
          let ruleList = [
            ...(disableDefaultRule ? defaultPasswordRuleList : []),
            ...customRule,
          ].map((item) => ({ ...item, [passwordBreakKey]: false }));
          const range = Math.max(...ruleList.map((ruleItem) => ruleItem.list.length));
          let matchCount = 0;
          ruleList = setArrayMatch<string, IpasswordRule>({
            array: inputValue.split(''),
            range,
            matchList: ruleList,
            // not breakKey  full match
            breakKey: breakKey === void 0 ? passwordBreakKey : breakKey,
            tokenMap: (ruleItem, inputToken, findIndex) => {
              const match = ruleItem?.list[findIndex] === inputToken;
              if (match) {
                matchCount++;
                return { ...ruleItem, isMatch: true };
              }
              return ruleItem;
            },
          });
          return {
            list: ruleList,
            map: new Map(ruleList.map((e) => [e.name, e[passwordBreakKey]])),
            matchCount,
            // 想要獲取這個(gè)值,必須breakKey設置為空字符,如果提前退出會(huì )導致提前中止條件
            // To get this value, breakkey must be set to null string
            invaildWord: matchCount !== inputValue.length,
          };
        };
        
        export const isMatchForceResultConfig = (
          config: matchResultConfig,
          matchNum: number,
          inputValueLen: number,
        ) => {
          return (
            matchNum === config.matchNum &&
            inputValueLen >= config.min &&
            inputValueLen <= config.max &&
            (config.need !== undefined ? config.need : true)
          );
        };
        
        export type matchResultConfig = {
          min: number;
          max: number;
          matchNum: number;
          value: IpasswordForce;
          need?: boolean;
          back?: IpasswordForce;
        };
        export type IpasswordForce = false | 'high' | 'middle' | 'low';
        
        

        流程就是合并規則,一個(gè)是默認規則一個(gè)是自定義規則,如果自定義規則,那么就會(huì )覆蓋默認規則。
        從規則中,尋找規則數量最長(cháng)的規則,因為等下我們遍歷的時(shí)候可以合并所有的規則,不管多少規則,其實(shí)遍歷數是區別不大的。

        遍歷函數是個(gè)單獨的高階函數,可以自定義處理內部的邏輯,這時(shí)候,我們匹配到了之后對應的規則,激活對應規則的屬性,并累計匹配到的字符。

        最后正常全部匹配到了就應該中止遍歷,但是有一個(gè)情況是不能中止的,那就是需要判斷是否有非法字符。

        最后這個(gè)函數把處理過(guò)的數據丟給上層組件,流程就是這樣

        在數據拋出的過(guò)程中,有些場(chǎng)景可能需要對對應規則的數據進(jìn)行特殊處理,但是如果是array結構就很不方便,于是拋出的數據應該分為list和map類(lèi)型,上層應用想要獲取對應規則的情況可以map.get(規則名稱(chēng))來(lái)操作

        constants.ts

        export const specialList = ["~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "-", "/", ",", ".", "?", "<", ">", ";", ":", "[", "]", "{", "}", "|", "\\"];
        export const numberList = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
        export const wordList = ["q", "a", "z", "w", "s", "x", "e", "d", "c", "r", "f", "v", "t", "g", "b", "y", "h", "n", "u", "j", "m", "i", "k", "o", "l", "p", "Q", "A", "Z", "W", "S", "X", "E", "D", "C", "R", "F", "V", "T", "G", "B", "Y", "H", "N", "U", "J", "M", "I", "K", "O", "L", "P"];
        

        其他

        很多人可能會(huì )有疑問(wèn),一個(gè)代碼檢測器有必要搞這么復雜嗎,直接正則不好嗎。其實(shí)從實(shí)用角度來(lái)說(shuō),確實(shí)正則更方便點(diǎn),但是有時(shí)候我們不想要循規蹈矩,或者想要手動(dòng)編碼的快感,或者要從無(wú)聊中代碼獲得更多的可玩性等,于是編寫(xiě)一個(gè)看起來(lái)挺復雜的代碼,不過(guò)把底層的封裝住,然后保留靈活性,在業(yè)務(wù)層里面盡量簡(jiǎn)單點(diǎn),其實(shí)也不是不可以試試的,但是也會(huì )在review的時(shí)候被懟,各位看官拷貝請注意哈,時(shí)間緊迫或者編碼能力不強的不建議使用本代碼,出問(wèn)題本人概不負責。

        總結

        到此這篇關(guān)于react如何實(shí)現一個(gè)密碼強度檢測器的文章就介紹到這了,更多相關(guān)react密碼強度檢測器內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

        免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

        欧美老妇激情BBBWWBBW| 妇女性内射冈站HDWWWCOM| 国产在线拍揄自揄拍免费下载| 精品成人一区二区三区四区| 亚洲乱码无人区卡1卡2卡3| 最新中文字幕AV无码专区|