1. 程式人生 > >使用者註冊資訊驗證功能(前端+後臺)

使用者註冊資訊驗證功能(前端+後臺)

一、寫在前面羅裡吧嗦的話

最近在寫自己的第一個個人專案,開始寫了很久了,但是每天沒啥時間記錄,趁著週末先記錄一些思路和踩過的坑。

專案預計是做一個關於家裝的電商網站,樣式參考自土巴兔網站(我不是打廣告!)。目前寫了幾個靜態頁面,寫得有點審美疲勞,遂決定寫一寫後臺JS換換心情~

之前聽師兄說登入註冊倆小時就能搞定,想一想不如就先寫登陸註冊吧,反正用不了多久。好吧,事實光速打臉了,我怎麼就把自己對號入座了呢?(好吧,我菜了,真的要勤加練習啊!!!)每天抽空寫一寫,刪刪改改居然鼓搗了幾天才寫完(再一次淚奔)。

言歸正傳,還是說說我的實現思路和踩到的坑吧(T_T)。

宣告:本專案目前採用jQuery框架!!!

二、功能實現的思路

2.1 前端格式驗證

註冊介面我設計了四個輸入框,分別是:手機號、使用者名稱和兩次密碼。

手機號---滿足一般手機號碼格式:/^1[34578]\d{9}$/

使用者名稱---4-16位,可選擇包含字母,數字,下劃線:/^[\w\u4e00-\u9fa5]{4,16}$/

密碼---6-16位,其中必須含有數字、字母和特殊符號:/^.*(?=.{6,16})(?=.*\d)(?=.*[A-Za-z])(?=.*[[email protected]#$%^&*?\(\)\.]).*$/

二次密碼:比較和上述密碼是否一致,返回判斷結果。

坑1(嚴格來講這不算坑,只是我學藝不精 >_<):

密碼的正則涉及一個先行斷言。在符號“(?=” 和 “)” 之間加入一個表示式,它就是一個先行斷言,用以說明圓括號內的表示式必須正確匹配。比如:/Java(?=\:)/ 只能匹配Java且後面有冒號的。

思路:每當輸入框失去焦點(blur事件)時,預設使用者完成當前輸入框資訊的錄入,觸發該輸入框資訊的正則驗證,根據正則驗證的結果決定是否給使用者錯誤提示(HTML文件中input輸入框的下一個兄弟元素next為錯誤提示內容,控制其display樣式,正則驗證失敗進行提示display:block,成功則隱藏錯誤提示display:none)。

優化:此處我為了介面的美觀性,當正則驗證失敗時,使輸入框的邊框變為紅色(本來獲得焦點時是主題色),這個也挺好辦,就是麻煩了點——在CSS檔案裡寫個樣式,用JS動態為該input新增(addClass())/刪除(removeClass())該樣式就OK啦。

2.2 後臺資料庫查詢驗證

主要是驗證手機號和使用者名稱是否已被佔用(不能重複註冊嘛!),然後對使用者進行錯誤提示。

使用者名稱:未被佔用--->不進行錯誤提示(意思就是這是可用的啦)

               被佔用---->進行錯誤提示

密碼:功能需求同上,就是錯誤提示的內容不一樣

思路:說在前面,此處的錯誤提示預設修改2.1中相應位置的錯誤提示內容。當前端頁面的手機號/使用者名稱輸入框失去焦點時(此時預設使用者輸入完成),用jQuery封裝好的ajax函式將使用者當前輸入的手機號/使用者名稱傳送給伺服器端,在伺服器端獲取到前端傳過來的資料,再將其傳入資料庫的查詢sql語句中,根據返回結果result(result是一個數組,請牢記!)的長度,判斷該手機號/使用者名稱是否已被佔用,並將此結果返回給前端頁面,然後前端頁面據此進行錯誤提示。

簡單來講,就是前端頁面將使用者當前輸入的資料傳給後端伺服器進行資料庫查詢,並返回查詢結果,前端頁面再根據此結果決定是否進行錯誤提示。

2.3 點選註冊

前端驗證和後臺驗證均通過且勾選同意條款的複選框(isAgree)

前端正則驗證通過:regResult = true;

後臺資料驗證通過:resResult = true;                                        ===> 註冊成功

勾選同意條款的複選框:isAgree = true;

坑2:使用者啥都不填(P.S.我要是使用者,我絕對不會這麼作!我發四!),直接點選註冊。這時候各表單的blur事件就沒有被觸發,所以我只能在註冊按鈕的繫結事件裡手動讓各輸入框失去焦點了(感覺這樣會浪費資源,可是臣妾真的不造怎麼解決了啊啊啊啊,要不然給使用者提示個“請您善良”?會被打死吧)。

三、翠花,上程式碼

好了,思路大致就如第二部分所講,程式碼嘛,也不可能大段大段複製過來,這樣可讀性很差,撿重要的記錄。

3.1 前端驗證

由於要進行四個正則驗證(以後可能更多,哭),所以我果斷決定先封裝一個正則驗證函式吧(我這麼懶,怎麼可能想寫辣麼多重複程式碼,逃...)

3.1.1 封裝正則驗證函式

先貼上程式碼吧

function regStyle(t,str,reg){
    if(t == null) return false;
    else if(!(reg.test(str))){      //正則失敗
        $(t).addClass("error_border");
        $(t).next().removeClass("hint_hide")
        .addClass("error_hint");
        return false;
    }else{
        $(t).removeClass("error_border");
        $(t).next().addClass("hint_hide")
        .removeClass("error_hint");
        return true;
    }
}

解釋:要求傳入的三個引數分別是:當前需要進行正則驗證的輸入框,當前需要進行驗證的字串(就是輸入框內容啦,當然這個可以在封裝的函式裡獲取到,可是我喜歡把需要分別獲取到的資料寫在一起,所以就寫在各輸入框blur事件的函式裡啦),當前輸入框內容需要滿足的正則表示式。

解釋:if-else條件語句:首先判斷輸入框內容是否為空,為空直接返回false(即正則驗證結果),之後的程式碼比較簡單就不詳述了。需要說明的是$(t)語句是控制是否進行錯誤提示的,樣式想法參見2.1中的優化部分啦。

3.1.2 輸入框資訊驗證

各輸入框驗證的步驟大致一樣,除了手機號和使用者名稱需要進行後臺驗證之外,其餘兩項只需進行前端驗證,此處以手機號驗證為例(僅貼出前端驗證的程式碼)。

// 1.驗證手機號:滿足一般手機號碼格式
    $("input[name='phone']").blur(function(){
        // 1.1 獲取頁面相應資料,進行前端正則驗證,並取得驗證結果
        phone = $(this).val();
        var reg = /^1[34578]\d{9}$/;
        regResult[0] = regStyle($(this),phone,reg);
    });

解釋:此處有一處需要注意,各輸入框都需實時儲存當前驗證結果(確保使用者反覆進行修改之後儲存的結果是正確的),所以我就乾脆建立一個數組來分別儲存各輸入框的驗證結果,只要輸入框一失去焦點就實時更新正則結果。

解釋:最後當用戶點選註冊按鈕時(其實是個a標籤),需要對regResult這個陣列中的所有值進行判斷,只要有一個為false(表明當前至少有一項輸入框內容不符合正則表示式要求。)

3.2 後臺驗證

話不多說,直接上程式碼,還是以手機號的後臺驗證為例。

先貼出前端頁面傳送的ajax請求:

    // 1.驗證手機號:滿足一般手機號碼格式
    $("input[name='phone']").blur(function(){
        // 1.2 向伺服器傳送請求,進行後臺資料庫驗證——該手機號是否被佔用
        $.ajax({
            url: "http://localhost:3000/register/isPhoneRepeat",
            type: "get",
            dataType: "json",
            data: {phone},
            async: false,        /*注意注意 此處有個坑噢!*/
            success: function(result){
                // 1.2.1 將後臺返回的查詢結果放入陣列中對應位置
                resResult[0] = result.code;
                // 1.2.2 查詢返回1,表示該手機號未註冊過,可以使用
                if(result.code == 1){
                    $("input[name='phone']").next().children().next().html("手機號格式不正確!");
                // 1.2.2 查詢返回0,表明該手機號已註冊過 ,被佔用不能使用
                }else if(result.code == 0){
                    $("input[name='phone']").next().children().next().html(result.msg);
                    $("input[name='phone']").addClass("error_border")
                    .next().removeClass("hint_hide")
                    .addClass("error_hint");
                }
            }
        })
    });

以下是伺服器端註冊路由中相應介面的程式碼:

// 判斷手機號是否註冊
router.get("/isPhoneRepeat",(req,res)=>{
    console.log("接收到一個手機號的後臺驗證請求!");
    var $phone = req.query.phone;
    var sql = "SELECT * FROM user_info WHERE phone = ?";
    pool.query(sql,[$phone],(err,result)=>{
        if(err) throw err;
        // console.log(result.length);
        res.writeHead(200,{
            // 定義內容型別:json資料格式,中文采用utf-8
			"Content-Type": "application/json;charset=utf-8",
			// 允許跨域請求
			"Access-Control-Allow-Origin": "*"
        });
        // 如果找到該手機的資料則表示佔用,若result為空則表示沒有被佔用,可以進行註冊
        if(result.length > 0){
            res.write(JSON.stringify({code:0,msg:"該手機號已被佔用!"}));
        }else{
            res.write(JSON.stringify({code:1,msg:"註冊成功!"}));
        }
        res.end();
    })
});

程式碼比較簡單,主要理清楚前後端資料傳送的關係即可(前部分思路中有講喲)。

3.3 點選註冊

同上,先貼前端的程式碼,主要就是根據上兩部分的驗證和二次觸發驗證結果,決定是否滿足註冊條件,然後告知伺服器,可以將這些資料插入資料庫(也就是說,從現在開始,使用者您嘞已經是我站的合法公民了)。

// 5.點選註冊按鈕向伺服器傳送請求,將使用者資訊資料存入資料庫
    $(".zh_reg a.signin_btn").click(function(){
        // 5.1 是否勾選同意條款複選框
        var isAgree = $("input[type='checkbox']").prop("checked");
        // 5.2 點選註冊按鈕,使上面的表單(除複選框外)全部失去焦點,再次進行判斷
        //     可攔截使用者什麼都不填直接點選註冊的行為
        var inputArr = $("input.reg_info");
        for(var input of inputArr){
            $(input).blur();
            console.log("在此使各input失去焦點了!");
        }
        // 5.3 獲取前端正則驗證結果
        var reg = true,res = true;
        for(var g of regResult){
            if(!g){
                reg = false;
                break;
            }
        }
        // 5.4 獲取後臺資料庫驗證結果
        for(var s of resResult){
            if(!s){
                res = false;
                break;
            }
        }
        // 5.5 根據驗證結果輸出提示
        if(!reg || !res){
            // 坑2:alert函式是window自帶函式,為同步CPU程式碼,會先於DOM渲染(非同步)先執行
            // 使用定時器延時函式將其變為非同步函式,放入事件佇列,就可以在DOM渲染完成之後才觸發執行
            setTimeout("alert('正確填寫註冊資訊後才能註冊喔~')",0);
        }else if(!isAgree){
            setTimeout("alert('如您同意我站的服務條款,請勾選同意喔~')",0);
        }else{
            $.ajax({
                url: "http://localhost:3000/register/signin",
                dataType: "json",
                data: {phone,uname,upwd},
                type: "post",
                async: false,
                success: function(result){
                    setTimeout(`alert('${result.msg}')`,0);
                }
            })
        }
    })

好吧,我承認我的程式碼寫的很爛,可這也是我思考良久的智慧結晶!!!(我發現我寫功能總是能想出很多奇葩的如果,如果使用者不輸入咋辦,如果使用者xxxx怎麼辦.....哇,真的要被自己轉的牛角尖給折磨死)。

咳咳,說回正題(我怎麼又跑題了),程式碼註釋已經比較詳細了,我就不再贅述(怎麼感覺文字部分全是我自己的內心戲啊T_T)。

接下來是伺服器端相應介面的程式碼:

// 將通過驗證的新使用者資訊註冊到資料庫中並返回成功與否
router.post("/signin",(req,res)=>{
    console.log("伺服器接收到一個註冊資訊儲存請求!");
    var $phone = req.body.phone;
    var $uname = req.body.uname;
    var $upwd = req.body.upwd;
    var sql = "INSERT INTO user_info VALUES(null,?,?,md5(?));"
    pool.query(sql,[$phone,$uname,$upwd],(err,result)=>{
        if(err) throw err;
        console.log(result);
        if(result.affectedRows > 0){
            res.send(JSON.stringify({code:1,msg:"恭喜您,註冊成功!"}));
        }else{
            res.send(JSON.stringify({code:0,msg:"啊哦,註冊失敗了"}));
        }
    })
})

程式碼差不多搬運到這,接下來講一講我踩過的坑及解決方法。

四、坑什麼的,總是讓我痛並快樂著

不要忘了前面還有兩個標紅了的坑!!!!!所以不要說我不識數,從3開始計數(身為程式媛,我是不是應該從坑0開始記錄??)

坑3:原本想讓後臺返回的資料為-1和1來區分驗證成功與否,這倒是沒啥大問題,可是前端頁面我用的是if(驗證結果)進行判斷,導致if裡的該條件一直為true,百思不得其解,後來靈光一閃,才發現原來是自己蠢了orz...

解決:數字中只有0==false,其餘的正數和負數均會自動轉換為true。劃重點:(-1==true) ===> true

坑4:點選註冊按鈕,觸發其繫結事件(裡面有alert彈框提示和使各輸入框失去焦點觸發二次前端+後臺驗證,後者涉及錯誤提示)。但alert()內容先於介面的錯誤提示,也就是說會出現alert彈框提示註冊成功,但介面卻有錯誤提示,需要第二次點選註冊才會alert提示註冊資訊有誤的詭異現象。

解釋:alert函式是window自帶函式,為同步CPU程式碼,會先於DOM渲染(非同步)先執行。

解決:使用定時器延時函式setTimeout("",0)將其變為非同步函式,放入事件佇列,就可以在DOM渲染完成之後才觸發執行。

坑4.1:不要忘了如果setTimeout()函式的第一個引數傳入的不是函式而是語句的話(如本文中就是一段alert()語句),需要叫上引號,加引號,加引號!(重要的事情說三遍)。

此坑詳見此文章(如有侵權,請速告知,立馬刪 0.0):https://www.cnblogs.com/zhenbianshu/p/8686681.html

坑5:多個ajax請求順序執行問題:表單後臺驗證的ajax請求和註冊資訊的ajax請求執行順序不能確定,導致重複點選註冊時未能如預想中一樣攔截重複註冊請求。

解決:在每個ajax非同步請求中加上async:false,使非同步請求按程式碼出現先後順序執行。(回去看看上面貼出的前端ajax函式,會有驚喜哦~~)

文章寫到這裡我也是很不容易了,我能說我寫了幾個小時嗎!!!!!(我真的更加寧願寫程式碼 T_T),路漫漫其修遠兮啊,功能完成到這裡還是有很多不足的,先列出來有空好好改造改造,啊不對,是優化!

五、列出不足點吧,畢竟我還是很謙虛的

  1. 註冊按鈕的二次驗證(迴圈使所有Input框失去焦點觸發其blur事件)會導致重複驗證,使用者輸入的資訊確實不符合註冊要求還好,要是使用者輸入的資訊全部正確,卻要驗證兩次,是很浪費系統資源的(手機號和使用者名稱還要各自重複傳送一次後臺驗證請求)。
  2. 用系統自帶的alert()提示框對使用者進行註冊結果的提示,好像。。。非常low!!!所以有空改改。(大概查了查,bootstrap有自帶的彈框樣式貌似還可以,也有相關方法可以自己封裝一個自定義的彈框方法及樣式)