vue 如何寫插件窥妇、自己寫一個表單驗(yàn)證插件

一般我們用vue的時候舷胜,有很多好用的插件,我們npm安裝一下就可以用了秩伞,但是像表單驗(yàn)證這種的很難找到自己心儀的插件逞带,和自己的網(wǎng)站交互也不一樣,還需要修改一下纱新,而且文件很大展氓,不如自己手寫一個了,只要自己需要的功能脸爱,可能寫的不好遇汞,提出意見

在我們開始寫插件之前要好好看看vue官方文檔,了解下面幾個API
1簿废、 Vue.directive( id, [definition] )
參數(shù):

{string} id
{Function | Object} [definition]
用法:

注冊或獲取全局指令空入。


image.png

image.png

image.png

image.png

2、好好看看文檔的這里 ---->插件
下面我們開始寫一個驗(yàn)證的插件

validator.js 定義插件


/**
 * 默認(rèn)規(guī)則:
 * 1族檬、不為空
 * 2歪赢、電話號碼校驗(yàn)
 * 3、郵箱校驗(yàn)
 */
// 默認(rèn)規(guī)則正則表
let regList = {
  required: true,
  Mobile: /^1[3|4|5|7|8]\d{9}$/,
  Mail: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
}
// 默認(rèn)規(guī)則錯誤信息
let msgList = {
  required: '必填',
  Mobile: '請輸入正確的手機(jī)號',
  Mail: '請輸入正確的郵箱'
}
// 規(guī)則構(gòu)造器
function Rule (ruleName, ruleValue, ruleMsg) {
  this.ruleName = ruleName
  this.ruleValue = ruleValue
  this.msg = ruleMsg
}
// 掛在vue實(shí)例上面$va
function createVa (vm, domSelector) {
  let va = {
    ruleListRank: [],
    forms: {},
    checkRule: checkRule,
    checkAll: checkAll
  }
  if (vm.$va) {
    return vm.$va
  } else {
    vm.$va = va
    return vm.$va
  }
}
// va構(gòu)造器掛在vue實(shí)例上面$va的forms上面
function VaForm (el, finalRule) {
  this.dom = el
  this.rules = finalRule
}
// 斷言函數(shù)
function assert (condition, message) {
  if (!condition) {
    console.error('[validator-warn]:' + message)
  }
}
// 掛載va上的方法================================================>
// 校驗(yàn)表單的全部字段
function checkAll () {
  let ruleListRank = this.ruleListRank
  let forms = this.forms
  let checkRule = this.checkRule
  let checkFlag = true
  for (let name of ruleListRank) {
    let dom = forms[name].dom
    let rules = forms[name].rules
    let flag = checkRule(dom, rules)
    if (flag === false) {
      checkFlag = flag
    }
  }
  return checkFlag
}
// 校驗(yàn)表單的一個字段的第一個報錯信息
function checkRule (dom, rules) {
  let ruleCheckers = {
    required: checkEmpty,
    reg: checkReg
  }
  for (let rule of rules) {
    let {ruleName, ruleValue, msg} = rule
    let checkResult
    if (typeof ruleValue === 'function') {
      checkResult = ruleValue()
    } else {
      checkResult = ruleCheckers[ruleName]
        ? ruleCheckers[ruleName](ruleValue, dom)
        : ruleCheckers.reg(ruleValue, dom)
    }

    if (!checkResult) {
      setError(dom, msg, 'add')
      return false
    }
  }
  setError(dom, '', 'remove')
  return true
}
// 表單驗(yàn)證的方法================================================>
// 檢測非空
function checkEmpty (ruleValue, vaForm, va) {
  return vaForm.value.trim() !== ''
}
// 檢測正則
function checkReg (ruleValue, vaForm, va) {
  return ruleValue.test(vaForm.value)
}
/**
 * 設(shè)置錯誤的方法
 * @param {*} dom 當(dāng)前dom元素
 * @param {*} msg 報錯信息
 * @param {*} type 是添加報錯信息還是移除
 */
function setError (dom, msg, type) {
  if (dom.parentNode.classList) {
    if (type === 'add') {
      dom.parentNode.classList.add('error_item')
    } else {
      dom.parentNode.classList.remove('error_item')
    }
  }
  dom.nextElementSibling.innerHTML = msg
}
let installed = false
function plugin (Vue, options) {
  if (installed) {
    assert(installed, 'already installed')
    return
  }
  Vue.directive('validator', {
    bind: function (el, binding, vnode) {
      let vm = vnode.context // 基本的校驗(yàn)規(guī)則
      let finalRule = [] // 最終的校驗(yàn)規(guī)則
      let domSelector = binding.arg === undefined ? el.getAttribute('id') : binding.arg
      let options = binding.value ? binding.value : []// 特殊配置(允許非空单料,編輯新增共用等)
      assert(domSelector, 'not set id or binding.arg')
      let va = createVa(vm, domSelector)// 單例模式創(chuàng)建va埋凯,綁定在vm上
      va.ruleListRank.push(domSelector)// 表單檢驗(yàn)的順序
      for (let option of options) {
        if (typeof option === 'object') {
          // 用戶自定義的校驗(yàn)規(guī)則
          let ruleName = Object.keys(option)[0]
          let ruleValue = option[ruleName] ? option[ruleName] : regList[ruleName]
          assert(ruleValue, domSelector + " selector's " + ruleName + ' not set verification mode')
          finalRule.push(new Rule(ruleName, ruleValue, option.msg))
        } else {
          // 配置項(xiàng)定義的校驗(yàn)規(guī)則
          if (regList[option]) {
            finalRule.push(new Rule(option, regList[option], msgList[option]))
          }
        }
      }
      let vaForm = new VaForm(el, finalRule)
      va.forms[domSelector] = vaForm
    }
  })
  installed = true
}
// 自動注冊vue
if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(plugin)
}
export default {
  install: plugin
}

API文檔


vue template結(jié)構(gòu)外層嵌套input_item里面有一個class為error的p標(biāo)簽

    <div class="input_item">
       <label for="password">{{$t('login.password.name')}}</label>
       <input class="error-content" type="password" id="password" v-model="password" :placeholder="$t('login.password.name')" autocomplete="off" tag="密碼" v-validator:password= "validatePassword" >
       <p class="error"></p>
   </div>
/**
 * @param {*} type   reg(正則), required(必填),Mobile(電話)扫尖,Mail(郵件)白对,type 
    填寫其他的話默認(rèn)按照正則
 * @param {*} typeVal 根據(jù)不同type設(shè)置不同的值,正則表達(dá)式换怖,type類型為 
    Mobile甩恼、required、Mail 的可以寫true,false 条摸,還有function
 * @param {*} errMsg 自定義的報錯信息
 * 設(shè)置了三種規(guī)則:
 * 1.選項(xiàng)規(guī)則: 通過Vue指令的修飾符添加的規(guī)則悦污。v-validator:email= "[ 
    'required', 'Mail','Mobile']" 就可以校驗(yàn)?zāi)J(rèn)有的規(guī)則彈出默認(rèn)的錯誤提示信息。 
    例如你不想要默認(rèn)的錯誤提示信息屈溉。用自己寫的
    v-validator:email= "[{required: '', msg: '不可以為空呦'}]"
 * 2.自定義規(guī)則: Vue指令屬性值上添加的規(guī)則塞关。有兩種
       (1)正則
      v-validator:email= "[ 
      'required', 'Mail','Mobile']"
      (2)function
      [{limit: () =>{
        return true/false
       }, msg: this.$i18n.t('login.password.errorMsg.limit')}]
       如果你是放在data中設(shè)置規(guī)則的話
export default {
  name: 'login',
  data () {
    return {
      validatePassword: [
        {limit: this.limit, msg: this.$i18n.t('login.password.errorMsg.limit')}//$i18n是 
         為了語言切換
      ]
    }
  },
  methods: {
    limit: function () {
      let password = this.$data.password
      return (password.length >= 6 && password.length <= 12)
    }
  }
   3.還沒加這個功能 同一個type的規(guī)則只存在一個,也就是說子巾,如果type為reg(正則),那么會互相 
      蓋帆赢。 覆蓋的優(yōu)先級: 自定義規(guī)則 > 選項(xiàng)規(guī)則 > 默認(rèn)規(guī)則
 */

實(shí)戰(zhàn)使用
main.js

import Validator from './plugins/validator'
Vue.use(Validator)

main.vue

<template>
  <div class="login-main">
      <div class="login-form">
        <div class="login-content">
            <div class="input_item">
                <label for="email">{{$t('login.email.name')}}{{$t('login.email.errorMsg.required')}}</label>
                <input class="error-content" type="text" id="email"  v-model="email" :placeholder="$t('login.email.placeholder')" autocomplete="off" v-validator:email= "validateEmail" tag="郵箱">
                <span class="error"></span>
            </div>
            <div class="input_item">
                <label for="password">{{$t('login.password.name')}}</label>
                <input class="error-content" type="password" id="password" v-model="password" :placeholder="$t('login.password.name')" autocomplete="off" tag="密碼" v-validator:password= "validatePassword" >
                <p class="error"></p>
            </div>
            <div class="login-options">
              <input type="submit" class="cannot-login-btn" :value="$t('login.forget.name')" >
            </div>
            <input type="submit" class="login-btn" :value="$t('login.loginBtn.name')"  @click="checkLogin();">
        </div>
          <div class="change-btn">
              {{$t('login.changedes')}}
              <a href="/signup"> {{$t('login.signInBtn.name')}}</a>
          </div>
      </div>
  </div>
</template>
<script>
export default {
  name: 'login',
  data () {
    return {
      email: '',
      validateEmail: [
        {required: '', msg: this.$i18n.t('login.email.errorMsg.required')},
        {Mail: '', msg: this.$i18n.t('login.email.errorMsg.mail')}
      ],
      password: '',
      validatePassword: [
        {required: '', msg: this.$i18n.t('login.password.errorMsg.required')},
        {limit: this.limit, msg: this.$i18n.t('login.password.errorMsg.limit')}
      ]
    }
  },
  methods: {
    checkLogin: function () {
      let _this = this
      let checkResult = _this.$va.checkAll()
      if (checkResult) {
        console.log('請求接口去登陸')
      }
    },
    limit: function () {
      let password = this.$data.password
      return (password.length >= 6 && password.length <= 12)
    }
  }
}
</script>
<style lang="less" scoped>
.login-main{
  min-height: 100vh;
  background: #000000;
  // background: url('../../../static/img/login/login1.png')no-repeat;
  background-size: cover;
  overflow: hidden;
  .login-form{
    width: 432px;
    margin: 150px auto;
    background-color: #fff;
    border-radius: 2px;
    box-shadow: 0 1px 3px rgba(26,26,26,.1);
    .login-content{
      padding: 62px 42px 68px;
    }
    .input_item{
      margin: 0 0 20px;
      label{
        font-size: 16px;
        display: block;
        color: #2d2d2d;
        margin-bottom: 5px
      }
      input{
        font-size: 16px;
        border: none;
        line-height: 32px;
        width: 100%;
        border-bottom: 1px solid #ebebeb;
      }
      input::-webkit-input-placeholder{
        color: #DFE2EC;
      }
      input::-moz-placeholder{  //不知道為何火狐的placeholder的顏色是粉紅色,怎么改都不行线梗,希望有大牛路過幫忙指點(diǎn)
        color: #DFE2EC;
      }
      input::-ms-input-placeholder{  //由于我的IE剛好是IE9椰于,支持不了placeholder,所以也測試不了(⊙﹏⊙)仪搔,有IE10以上的娃可以幫我試試
        color: #DFE2EC;
      }
//沒報錯的樣式
      .error{
        display: none
      }
//沒報錯的樣式
    }
//報錯的樣式
    .input_item.error_item{
    .error{
        display: block;
        color: red;
        font-size: 16px;
        line-height: 32px;
    }
    .error-content{
          border-bottom: 1px solid red;
    }
    }
//樣式
    .login-btn{
          margin-top: 30px;
          border: none;
          background: rgba(0,166,248,0.9);
          width: 100%;
          color: #fff;
          padding: 10px 0;
          border-radius: 3px;
          font-size: 16px;
    }
    .change-btn{
        display: flex;
        -webkit-box-align: center;
        align-items: center;
        -webkit-box-pack: center;
        justify-content: center;
        width: 100%;
        background-color: #f6f6f6;
        height: 58px;
        border-top: 1px solid #ebebeb;
        font-size: 16px;
        border-radius: 0 0 2px 2px;
        a{
          color:rgba(0, 166, 248, 1)
        }
    }
    .login-options{
      .cannot-login-btn{
          float: right;
          border: none;
          font-size: 14px;
          color: #BEBCBA;
          text-align: center;
          cursor: pointer;
          background: none;
      }
    }
  }
}
</style>

最終的效果


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘾婿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烤咧,更是在濱河造成了極大的恐慌偏陪,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煮嫌,死亡現(xiàn)場離奇詭異笛谦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)昌阿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門饥脑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人懦冰,你說我怎么就攤上這事灶轰。” “怎么了刷钢?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵笋颤,是天一觀的道長。 經(jīng)常有香客問我内地,道長伴澄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任瓤鼻,我火速辦了婚禮,結(jié)果婚禮上贤重,老公的妹妹穿的比我還像新娘茬祷。我一直安慰自己,他們只是感情好并蝗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布祭犯。 她就那樣靜靜地躺著秸妥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沃粗。 梳的紋絲不亂的頭發(fā)上粥惧,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音最盅,去河邊找鬼突雪。 笑死,一個胖子當(dāng)著我的面吹牛涡贱,可吹牛的內(nèi)容都是我干的咏删。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼问词,長吁一口氣:“原來是場噩夢啊……” “哼督函!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起激挪,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤辰狡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后垄分,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宛篇,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年锋喜,在試婚紗的時候發(fā)現(xiàn)自己被綠了些己。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘿般,死狀恐怖段标,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炉奴,我是刑警寧澤逼庞,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站瞻赶,受9級特大地震影響赛糟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜砸逊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一璧南、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧师逸,春花似錦司倚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皿伺。三九已至,卻和暖如春盒粮,著一層夾襖步出監(jiān)牢的瞬間鸵鸥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工丹皱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妒穴,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓种呐,卻偏偏與公主長得像宰翅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爽室,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容