溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

發(fā)布時(shí)間:2021-03-29 09:30:38 來(lái)源:億速云 閱讀:227 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

前言

近期開(kāi)發(fā)的移動(dòng)端項(xiàng)目直接上了 vue3 ,新特性 composition api 確實(shí)帶來(lái)了全新的開(kāi)發(fā)體驗(yàn).開(kāi)發(fā)者在使用這些特性時(shí)可以將高耦合的狀態(tài)和方法放在一起統(tǒng)一管理,并能視具體情況將高度復(fù)用的邏輯代碼單獨(dú)封裝起來(lái),這對(duì)提升整體代碼架構(gòu)的健壯性很有幫助.

如今新啟動(dòng)的每個(gè)移動(dòng)端項(xiàng)目基本上都包含注冊(cè)登錄模塊,本次實(shí)踐過(guò)程中針對(duì)登錄注冊(cè)中的表單控件做了一些經(jīng)驗(yàn)上的總結(jié),通過(guò)抽離提取共性代碼來(lái)提升代碼的可維護(hù)性和開(kāi)發(fā)效率.

接下來(lái)觀察一下美工同學(xué)提供的圖片.

注冊(cè)頁(yè)面

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

登錄頁(yè)面

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

忘記密碼頁(yè)面

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

修改密碼頁(yè)面

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

通過(guò)觀察上面幾張產(chǎn)品圖片,可以清晰看出構(gòu)成整個(gè)登錄注冊(cè)模塊的核心組件就是 input 輸入框.只要把輸入框組件開(kāi)發(fā)完備,其他頁(yè)面直接引用就行了.

輸入框開(kāi)發(fā)完了只實(shí)現(xiàn)了靜態(tài)頁(yè)面的展示,另外我們還要設(shè)計(jì)一套通用的數(shù)據(jù)校驗(yàn)方案應(yīng)用到各個(gè)頁(yè)面中的表單控件.

輸入框組件

從上面分析可知,輸入框組件是整個(gè)登錄注冊(cè)模塊的核心內(nèi)容.我們先看一下輸入框組件有哪幾種 UI 形態(tài).

形態(tài)一

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

左側(cè)有文字 +86 ,中間是輸入框,右側(cè)如果檢測(cè)到輸入框有數(shù)據(jù)輸入顯示叉叉圖標(biāo),如果沒(méi)有數(shù)據(jù)為空隱藏圖標(biāo).

形態(tài)二

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

左側(cè)只有一個(gè)輸入框,右側(cè)是文案.文案的內(nèi)容可能是驗(yàn)證碼,也可能是點(diǎn)擊驗(yàn)證碼后顯示的倒計(jì)時(shí)文案.

形態(tài)三

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

左側(cè)依舊只有一個(gè)輸入框,右側(cè)如果檢測(cè)到輸入框有內(nèi)容顯示叉叉圖標(biāo),如果內(nèi)容為空隱藏圖標(biāo).

布局

依據(jù)上面觀察而來(lái)的現(xiàn)象分析,我們?cè)O(shè)計(jì)這款 input 組件時(shí)可以將其分為左中右三部分.左側(cè)可能是文案,也可能是空.中間是一個(gè)輸入框.右側(cè)可能是文案也可能是叉叉圖標(biāo).

模板內(nèi)容如下:

<template>
 <div class="input">
  <!--左側(cè),lt是左側(cè)內(nèi)容-->
   <span class="left-text">
   {{ lt }}
   </span>
  
  <!--中間-->
  <input class="content" v-bind="$attrs" :value="value" @input="onChange" /> 
  
  <!--右側(cè),rt判端是驗(yàn)證碼還是叉叉圖標(biāo)-->
   <div v-if="rt == 'timer'" class="right-section">
    {{ timerData.content }} <!--可能是'驗(yàn)證碼',也可能是倒計(jì)時(shí) -->
   </div>
   <div
   v-else-if="rt == 'close'"
   class="right-section"
   >
   <van-icon name="close" /> <!--叉叉圖標(biāo)-->
   </div>
 </div> 
</template>

布局上將左中右的父級(jí)設(shè)置為 display:flex ,子級(jí)的三個(gè)元素全部設(shè)置成 display:inline-block 行內(nèi)塊模式,目的是為了讓左側(cè)和右側(cè)依據(jù)自身內(nèi)容自適應(yīng)寬度,而中間的 input 設(shè)置成 flex:1 充滿(mǎn)剩余的寬度.

理論上這樣的布局是可行的,但實(shí)踐中發(fā)現(xiàn)了問(wèn)題.

Demo 效果圖如下:

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

右側(cè)持續(xù)增加寬度時(shí),中間 input 由于默認(rèn)寬度的影響導(dǎo)致讓右側(cè)向外溢出了,這并不是我們想要的.

解決這個(gè)問(wèn)題的辦法很簡(jiǎn)單,只需要將中間 input 的 width 設(shè)置為 0 即可,如下便達(dá)到了我們想要的效果.

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

v-model

外部頁(yè)面引用上述封裝的組件結(jié)構(gòu)如下:

 <InputForm
  lt="+86" <!--左側(cè)顯示+86--> 
  rt="close" <!--右側(cè)顯示叉叉圖標(biāo)-->
  placeholder="請(qǐng)輸入手機(jī)號(hào)碼"
 />

外部頁(yè)面創(chuàng)建了一個(gè)表單數(shù)據(jù) form_data 如下,但希望能通過(guò) v-model 的形式將 form_data 的數(shù)據(jù)與子組件輸入框的值建立雙向數(shù)據(jù)綁定.

 const form_data = reactive({
  number_number: '', //用戶(hù)名
  password: '', //密碼
  ppassword: '', //重復(fù)密碼
  captcha: '', //驗(yàn)證碼
 })

在 vue3 實(shí)現(xiàn) v-model 非常簡(jiǎn)便,在父組件中使用 v-model:xx 完成綁定,這里的 xx 對(duì)應(yīng)著子組件要綁定的狀態(tài)名稱(chēng),如下所示.

 <InputForm
    lt="+86"  <!--左側(cè)顯示+86--> 
    rt="close" <!--右側(cè)顯示叉叉圖標(biāo)-->
    placeholder="請(qǐng)輸入手機(jī)號(hào)碼"
    v-model:value="form_data.password"
 />

接下來(lái)子組件里首先聲明要綁定的屬性 value ,并監(jiān)聽(tīng)輸入框的 oninput事件 .代碼如下:

<template>
  <div class="input">
    ...
      <input class="content" v-bind="$attrs" :value="value" @input="onChange" /> 
    ...
  </div> 
</template>
export default defineComponent({
 props: {
  lt:String,
  rt: String,
  value: String
 },
 setup(props, context) {
  const onChange = (e:KeyboardEvent) => {
   const value = (e.target as HTMLInputElement).value;
    context.emit("update:value",value);
  };
  return {
    onChange
  }
 }
 })

oninput事件 的回調(diào)函數(shù)將獲取到的值使用 context.emit("update:value",value) 返回回去.

其中 update:value 里前面部分 update: 為固定寫(xiě)法,后面填寫(xiě)要建立雙向綁定的狀態(tài)名稱(chēng).如此一來(lái)就輕易的完成了 v-model 的綁定.

數(shù)據(jù)校驗(yàn)

一般來(lái)說(shuō)只要頁(yè)面上涉及到表單控件(比如輸入框),那么就要針對(duì)相應(yīng)的值做數(shù)據(jù)校驗(yàn).如果按照原始的方法,當(dāng)用戶(hù)點(diǎn)擊按鈕, js 接受響應(yīng)依次獲取每個(gè)表單項(xiàng)的值一一校驗(yàn).

這樣的做法當(dāng)然可以實(shí)現(xiàn)功能,但并不高效和精簡(jiǎn).因?yàn)楹芏囗?yè)面都要做校驗(yàn),大量的校驗(yàn)邏輯是重復(fù)書(shū)寫(xiě)的.

我們接下來(lái)設(shè)計(jì)一套通用的校驗(yàn)方案,將那些可以復(fù)用的邏輯代碼都封裝起來(lái),并且能夠快速的應(yīng)用到每個(gè)頁(yè)面上,提升開(kāi)發(fā)效率.

依注冊(cè)頁(yè)面為例,模板代碼如下.創(chuàng)建四個(gè)輸入框組件:手機(jī)號(hào),手機(jī)驗(yàn)證碼,密碼和確認(rèn)密碼.最后面再放置一個(gè)注冊(cè)按鈕.(為了看起來(lái)更清晰,下面的代碼將所有 ts 類(lèi)型刪除)

 <Form ref="form" :rules="rules">
 
   <InputForm
    lt="+86"
    rt="close"
    v-model:value="form_data.number_number"
    placeholder="請(qǐng)輸入手機(jī)號(hào)碼"
    propName="number_number"
   />
   
   <InputForm
    rt="timer"
    v-model:value="form_data.captcha"
    placeholder="請(qǐng)輸入手機(jī)驗(yàn)證碼"
    propName="captcha"
   />

   <InputForm
    rt="close"
    v-model:value="form_data.password"
    placeholder="請(qǐng)輸入密碼"
    type="password"
    propName="password"
   />

   <InputForm
    rt="close"
    v-model:value="form_data.ppassword"
    placeholder="請(qǐng)輸入確認(rèn)密碼"
    type="password"
    propName="ppassword"
   />

   <Button text="注 冊(cè)" @sub="onSubmmit" /> <!--注冊(cè)按鈕-->

  </Form>

在借鑒了一些其他優(yōu)秀框架的表單實(shí)踐后,我們首先是在最外層增加了一個(gè)組件 Form ,其次給每個(gè)輸入框組件增加了一個(gè)屬性 propName .這個(gè)屬性是配合 rules 一起使用的, rules 是手動(dòng)定義的校驗(yàn)規(guī)則,當(dāng)它傳遞給 Form 組件后,子組件(輸入框組件)就能通過(guò) propName 屬性拿到屬于它的校驗(yàn)規(guī)則.

整體的實(shí)現(xiàn)思路可以從頭串聯(lián)一遍.首先是前端開(kāi)發(fā)者定義好當(dāng)前頁(yè)面的校驗(yàn)規(guī)則 rules ,并將它傳遞給 Form 組件. Form 組件接受到后會(huì)將校驗(yàn)規(guī)則分發(fā)給它的每個(gè)子組件(輸入框組件).子組件拿到校驗(yàn)規(guī)則后就能夠針對(duì)輸入框的值做相應(yīng)的數(shù)據(jù)校驗(yàn).

當(dāng)用戶(hù)點(diǎn)擊注冊(cè)按鈕時(shí),點(diǎn)擊事件會(huì)獲取 Form 組件的實(shí)例,并運(yùn)行它的 validate 方法,此時(shí) Form 組件就會(huì)對(duì)它旗下的每個(gè)子組件做一輪數(shù)據(jù)校驗(yàn).一旦所有校驗(yàn)成功了, validate 方法返回 true .存在一個(gè)校驗(yàn)沒(méi)通過(guò), validate 方法就返回 false ,并彈出錯(cuò)誤信息.

注冊(cè)頁(yè)面邏輯如下:

export default defineComponent({
 components: {
  InputForm, //輸入框
  Button, //注冊(cè)按鈕
  Form, //Form組件
 },
 setup(props) {
 
  const form_data = ...; //省略
  
  const rules = ...;
  
  //獲取最外層Form組件的實(shí)例
  const form = ref(null);
  
  const onSubmmit = ()=>{
   if (!form.value || !form.value.validate()) {
     return false;
   }
   //校驗(yàn)通過(guò)了,可以請(qǐng)求注冊(cè)接口了
  }

  return {
   form,
   rules,
   onSubmmit,
   form_data
  };
 },
});

定義一個(gè)變量 form ,用它來(lái)獲取 Form 表單的實(shí)例.模板上 <Form ref="form" :rules="rules"> 只需要加上一個(gè) ref 屬性就可以了.

用戶(hù)點(diǎn)擊注冊(cè)按鈕觸發(fā) onSubmmit 函數(shù),因?yàn)?form 是使用 ref 創(chuàng)建的變量,獲取值要調(diào)用 .value .運(yùn)行 form.value.validate() 函數(shù),就能讓 Form 表單下面的每一個(gè)子組件開(kāi)始執(zhí)行校驗(yàn)邏輯,如果全部通過(guò)就會(huì)返回 true ,存在一個(gè)沒(méi)通過(guò)返回 false .

從上面分析可知, Form 控件只對(duì)外暴露一個(gè) validate 函數(shù),通過(guò)調(diào)用該函數(shù)就能知道校驗(yàn)是否通過(guò).那么 validate 如何知道該采用什么規(guī)則來(lái)校驗(yàn)?zāi)?所以我們要先設(shè)計(jì)一套校驗(yàn)的規(guī)則 rules ,把它傳給 Form 組件,那么它內(nèi)部的 validate 函數(shù)就能采用規(guī)則來(lái)執(zhí)行校驗(yàn).

rules設(shè)計(jì)

rules 是一個(gè)對(duì)象,例如上述注冊(cè)頁(yè)面的 rules 定義如下:

const rules = {
   number_number:[{
        type: 'required',
        msg:"請(qǐng)輸入正確的手機(jī)號(hào)" 
      }
        "phone"
      ],
   captcha:[
    {
     type: 'required',
     msg: '驗(yàn)證碼不能為空'
    }
   ],
   password: [
    {
     type: 'required',
     msg: '請(qǐng)輸入密碼',
    },
    {
     type: 'minLength',
     params: 6,
     msg: '密碼長(zhǎng)度不能小于6位',
    },
   ],
   ppassword:[
    {
     type: 'custome',
     callback() {
      if (form_data.password !== form_data.ppassword) {
       return {
        flag: false,
        msg: '兩次輸入的密碼不一致',
       };
      }
      return {
       flag: true,
      };
     },
    },
   ]
  }

我們定義的 rules 是一個(gè)鍵值對(duì)形式的對(duì)象. key 對(duì)應(yīng)著模板上每個(gè)輸入框組件的 propName ,值是一個(gè)數(shù)組,對(duì)應(yīng)著該輸入框組件要遵守的規(guī)則.

現(xiàn)在細(xì)致的看下每個(gè)對(duì)象下的值的構(gòu)成,值之所以組織成數(shù)組形式,是因?yàn)檫@樣可以給輸入框增加多條規(guī)則.而規(guī)則對(duì)應(yīng)著兩種形式,一種是對(duì)象,另外一種是字符串.

字符串很好理解,比如上面的 number_number 屬性,它就對(duì)應(yīng)著字符串 phone .這條規(guī)則的意義就是該輸入框的值要遵守手機(jī)號(hào)的規(guī)則.當(dāng)然字符串如果填 email ,那就要當(dāng)做郵箱來(lái)校驗(yàn).

規(guī)則如果為對(duì)象,那么它包含了以下幾個(gè)屬性:

 {
  type, // 類(lèi)型
  msg, //自定義的錯(cuò)誤信息
  params, //傳過(guò)來(lái)的參數(shù)值 比如 {type:'minLength',params:6},值最小長(zhǎng)度不能低于6位
  callback //自定義校驗(yàn)函數(shù)
 }

type 是校驗(yàn)類(lèi)型,它如果填 required ,表示是必填項(xiàng).如果用戶(hù)沒(méi)填,點(diǎn)擊注冊(cè)按鈕提交時(shí)就會(huì)報(bào)出 msg 定義的錯(cuò)誤信息.

另外 type 還可以填 minLength 或者 maxLength 用來(lái)限定值的長(zhǎng)度,那到底限定為幾位呢,可以通過(guò) params 傳遞過(guò)去.

最后 type 還可以填 custome ,那么就是讓開(kāi)發(fā)者自己來(lái)定義該輸入框的校驗(yàn)邏輯函數(shù) callback .該函數(shù)要求最后返回一個(gè)帶有 flag 屬性的對(duì)象,屬性 flag 為布爾值,它會(huì)告訴校驗(yàn)系統(tǒng)本次校驗(yàn)是成功還是失敗.

Form表單

rules 被定義好后傳給 Form 組件, Form 組件需要將校驗(yàn)邏輯分發(fā)給它的子組件.讓其每個(gè)子組件都負(fù)責(zé)生成自己的校驗(yàn)函數(shù).

<!-- 表單組件 -->
<template>
 <div class="form">
  <slot></slot>
 </div>
</template>

<script lang="ts">
import { ref, provide } from "vue";
export default defineComponent({
 name: "Form",
 props:{
  rules:Object
 },
 setup(props) {
  
  ...//省略

  provide("rules",props.rules); // 將校驗(yàn)規(guī)則分發(fā)下去
  
  const validate = ()=>{
   //向外暴露的校驗(yàn)函數(shù)
  }
  
  return {
   validate
  } 
 }
 }) 
</script>

從上面結(jié)構(gòu)可以看出, Form 組件模板提供了一個(gè)插槽的作用,在邏輯代碼里利用 provide 將校驗(yàn)規(guī)則傳給后代,并向外暴露一個(gè) validate 函數(shù).

子組件生成校驗(yàn)函數(shù)

這一次又回到了登錄注冊(cè)模塊的核心組件 InputForm ,我們現(xiàn)在要給該輸入框組件添加校驗(yàn)邏輯.

import { inject,onMounted } from "vue";
...

setup(props, context) {

 const rules = inject("rules");
 
 const rule = rules[props.propName];// 通過(guò)propName拿到校驗(yàn)規(guī)則
 
 const useValidate = () => {
      const validateFn = getValidate(rule); // 獲取校驗(yàn)函數(shù)
      const execValidate = () => { 
        return validateFn(props.value); //執(zhí)行校驗(yàn)函數(shù)并返回校驗(yàn)結(jié)果    
      };
      onMounted(() => {
        const Listener = inject('collectValidate');
        if (Listener) {
         Listener(execValidate);
        }
      });  
 };
 
 useValidate(); //初始化校驗(yàn)邏輯
 ...
}

rules 結(jié)構(gòu)類(lèi)似如下.通過(guò) inject 和 propName 可以拿到 Form 分發(fā)給該輸入框要執(zhí)行的規(guī)則 rule .

{
  captcha:[{
   type: 'required',
   msg: '驗(yàn)證碼不能為空'
  }],
  password:[{
   type: 'required',
   msg: '請(qǐng)輸入密碼', 
  }]
}

再將規(guī)則 rule 傳遞給 getValidate 函數(shù)(后面會(huì)講)獲取校驗(yàn)函數(shù) validateFn .校驗(yàn)函數(shù) validateFn 傳入輸入框的值就能返回校驗(yàn)結(jié)果.在這里把 validateFn 封裝了一層賦予 execValidate 給外部使用.

在上面的代碼中我們還看到了 onMounted 包裹的邏輯代碼.當(dāng)組件掛載完畢后,使用 inject 拿到 Form 組件傳遞下來(lái)的一個(gè)函數(shù) Listener ,并將校驗(yàn)函數(shù) execValidate 作為參數(shù)傳遞進(jìn)去執(zhí)行.

我們?cè)倩氐较旅娲a中的 Form 組件,看一下 Listener 是一個(gè)什么樣的函數(shù).

setup(props) {

const list = ref([]);//定義一個(gè)數(shù)組

const listener = (fn) => {
 list.value.push(fn);
};

provide("collectValidate", listener); //將監(jiān)聽(tīng)函數(shù)分發(fā)下去

//驗(yàn)證函數(shù)
const validate = (propName) => {
  const array = list.value.map((fn) => {
    return fn();
  });
  const one = array.find((item) => {
    return item.flag === false;
  });
  if (one && one.msg) {
    //驗(yàn)證不通過(guò)
    Alert(one.msg);//彈出錯(cuò)誤提示
    return false;
  } else {
    return true;
  }
};
...

從上面可以看出, Form 組件將 listener 函數(shù)分發(fā)了下去.而子組件在 onMounted 的生命周期鉤子里,獲取到分發(fā)下來(lái)的 listener 函數(shù),并將子組件內(nèi)部定義的校驗(yàn)函數(shù) execValidate 作為參數(shù)傳遞進(jìn)去執(zhí)行.

這樣一來(lái)就可以確保每個(gè)子組件一旦掛載完畢就會(huì)把自己的校驗(yàn)函數(shù)傳遞給 Form 組件中的 list 收集.而 Form 組件的 validate 方法只需要循環(huán)遍歷 list ,就可以依次執(zhí)行每個(gè)子組件的校驗(yàn)函數(shù).如果都校驗(yàn)通過(guò)了,給外部頁(yè)面返回 true .存在一個(gè)不通過(guò),彈出錯(cuò)誤提示返回 false .

走到這里整個(gè)校驗(yàn)的流程已經(jīng)打通了. Form 首先向子組件分發(fā)校驗(yàn)規(guī)則,子組件獲取規(guī)則生成自己的校驗(yàn)函數(shù),并且在其掛載完畢后將校驗(yàn)函數(shù)再返回給 Form 收集起來(lái).這個(gè)時(shí)候 Form 組件向外暴露的 validate 函數(shù)就可以實(shí)現(xiàn)針對(duì)所有表單控件的數(shù)據(jù)校驗(yàn).

接下來(lái)最后一步研究子組件如果通過(guò)規(guī)則來(lái)生成自己的校驗(yàn)函數(shù).

校驗(yàn)

首先編寫(xiě)一個(gè)管理校驗(yàn)邏輯的類(lèi) Validate .代碼如下.我們可以不斷的根據(jù)新需求擴(kuò)充該類(lèi)的方法,比如另外再增加 email 或者 maxLength 方法.

class Validate {

 constructor() {}

 required(data) { //校驗(yàn)是否為必填  
  const msg = '該信息為必填項(xiàng)'; //默認(rèn)錯(cuò)誤信息
  if (data == null || (typeof data === 'string' && data.trim() === '')) {
   return {
    flag:false,
    msg
   }
  }
  return {
    flag:true
  }
 }
 
 //校驗(yàn)是否為手機(jī)號(hào)
 phone(data) { 
  const msg = '請(qǐng)?zhí)顚?xiě)正確的手機(jī)號(hào)碼'; //默認(rèn)錯(cuò)誤信息
  const flag = /^1[3456789]\d{9}$/.test(data);
  return {
   msg,
   flag
  }
 }
 
 //校驗(yàn)數(shù)據(jù)的最小長(zhǎng)度
 minLength(data, { params }) {
  
    let minLength = params; //最小為幾位
    
    if (data == null) {
     return {
      flag:false,
      msg:"數(shù)據(jù)不能為空"
     }
    }

    if (data.trim().length >= minLength) {
     return {flag:true};
    } else {
     return {
      flag:false,
      msg:`數(shù)據(jù)最小長(zhǎng)度不能小于${minLength}位`
     }
    } 
  }

}

Validate 類(lèi)定義的所有方法中,第一個(gè)參數(shù) data 是被校驗(yàn)的值,第二個(gè)參數(shù)是在頁(yè)面定義每條 rule 中的規(guī)則.形如 {type: 'minLength', params: 6, msg: '密碼長(zhǎng)度不能小于6位'} .

Validate 類(lèi)中每個(gè)方法最終的返回的數(shù)據(jù)結(jié)構(gòu)形如 {flag:true,msg:""} .結(jié)果中 flag 就來(lái)標(biāo)識(shí)校驗(yàn)是否通過(guò), msg 為錯(cuò)誤信息.

校驗(yàn)類(lèi) Validate 提供了各種各樣的校驗(yàn)方法,接下來(lái)運(yùn)用一個(gè)單例模式生成該類(lèi)的一個(gè)實(shí)例,將實(shí)例對(duì)象應(yīng)用到真實(shí)的校驗(yàn)場(chǎng)景中.

 const getInstance = (function(){
  let _instance;
  return function(){
     if(_instance == null){
      _instance = new Validate();
     }
     return _instance;
   }
 })()

通過(guò)調(diào)用 getInstance 函數(shù)就可以得到單例的 Validate 實(shí)例對(duì)象.

輸入框組件通過(guò)給 getValidate 函數(shù)傳入一條 rule ,就能返回該組件需要的校驗(yàn)函數(shù).接下來(lái)看一下 getValidate 函數(shù)是如何通過(guò) rule 來(lái)生成校驗(yàn)函數(shù)的,代碼如下:

/**
 * 生成校驗(yàn)函數(shù)
 */
export const getValidate = (rule) => {
  const ob = getInstance();//獲取 Validate類(lèi) 實(shí)例對(duì)象
  const fn_list = []; //將所有的驗(yàn)證函數(shù)收集起來(lái)
  //遍歷rule數(shù)組,根據(jù)其類(lèi)型獲取Validate類(lèi)中的校驗(yàn)方法放到fn_list中收集起來(lái)
  rule.forEach((item) => {
   if (typeof item === 'string') { // 字符串類(lèi)型 
    fn_list.push({
     fn: ob[item], 
    });
   } else if (isRuleType(item)) { // 對(duì)象類(lèi)型
    fn_list.push({
     //如果item.type為custome自定義類(lèi)型,校驗(yàn)函數(shù)直接使用callback.否則從ob實(shí)例獲取 
     ...item, 
     fn: item.type === 'custome' ? item.callback : ob[item.type],
    });
   }
  });
  //需要返回的校驗(yàn)函數(shù)
  const execuate = (value) => {
   let flag = true,
    msg = '';
   for (let i = 0; i < fn_list.length; i++) {
    const item = fn_list[i];
    const result = item.fn.apply(ob, [value, item]);//item.fn對(duì)應(yīng)著Validate類(lèi)定義的的校驗(yàn)方法
    if (!result.flag) {
     //驗(yàn)證沒(méi)有通過(guò)
     flag = false;
     msg = item.msg ? item.msg : result.msg;//是使用默認(rèn)的報(bào)錯(cuò)信息還是用戶(hù)自定義信息 
     break;
    }
   }
   return {
    flag,
    msg,
   };
  };
  return execuate;
};

rule 的數(shù)據(jù)結(jié)構(gòu)形類(lèi)似如下代碼.當(dāng)把 rule 傳入 getValidate 函數(shù),它會(huì)判端是對(duì)象還是字符串,隨后將其類(lèi)型對(duì)應(yīng)的校驗(yàn)函數(shù)從 ob 實(shí)例中獲取存儲(chǔ)到 fn_list 中.

 [
  {
   type: 'required',
   msg: "請(qǐng)輸入電話(huà)號(hào)碼"
  },
  "phone"
 ]

getValidate 函數(shù)最終返回 execuate 函數(shù),此函數(shù)也正是輸入框組件得到的校驗(yàn)函數(shù).在輸入框組件里是可以拿到輸入框值的,如果將值傳給 execuate 方法調(diào)用.方法內(nèi)部就會(huì)遍歷之前緩存的校驗(yàn)函數(shù)列表 fn_list ,將值傳入每個(gè)校驗(yàn)方法運(yùn)行就能獲取該輸入框組件對(duì)當(dāng)前值的校驗(yàn)結(jié)果并返回回去.

以上校驗(yàn)的邏輯也已經(jīng)走通了.接下來(lái)不管是開(kāi)發(fā)登錄頁(yè),忘記密碼或者修改密碼的頁(yè)面,只需要使用 Form 組件和輸入框 InputForm 組件組織頁(yè)面結(jié)構(gòu),并寫(xiě)一份當(dāng)前頁(yè)面的 rules 校驗(yàn)規(guī)則即可.剩下的所有校驗(yàn)細(xì)節(jié)和交互動(dòng)作全部交給了 Form 和 InputForm 內(nèi)部處理,這樣會(huì)極大的提升開(kāi)發(fā)效率.

最終效果

vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊

以上是“vue3怎么優(yōu)雅的實(shí)現(xiàn)移動(dòng)端登錄注冊(cè)模塊”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI