1. 程式人生 > >註冊全局指令(表單驗證)

註冊全局指令(表單驗證)

route reat 所有 指令對象 word 父節點 自定義 重新 efault

1). 導出驗證指令對象

src/directives 下新建 validator.js 文件,復制貼入以下代碼:

src/directives/validator.js

  1 function validate(el, modifiers, bindingValue) {
  2   bindingValue = bindingValue && typeof bindingValue === ‘object‘ ? bindingValue : {}
  3   const value = typeof el.value === ‘string‘ ? el.value.trim() : ‘‘
  4
const { title = ‘該項‘, error } = bindingValue 5 let defaultError = ‘‘ 6 7 if (modifiers.required && value === ‘‘) { 8 defaultError = `${title}不能為空` 9 } else if (bindingValue.target) { 10 const target = document.querySelector(bindingValue.target) 11 const targetValue = target ? target.value : null
12 13 if (targetValue !== value) { 14 defaultError = `輸入的${title}不匹配` 15 } 16 } else if (bindingValue.regex) { 17 try { 18 if (!bindingValue.regex.test(value)) { 19 defaultError = `${title}格式不正確` 20 } 21 } catch (e) {} 22 } 23 24 if (defaultError) {
25 if (error === undefined) { 26 showError(el, defaultError) 27 } else { 28 showError(el, error) 29 } 30 } else { 31 showError(el) 32 } 33 } 34 35 function showError(el, error) { 36 const parentElement = el.parentElement 37 const errorElement = getErrorElement(el) 38 39 if (error === undefined) { 40 errorElement.style.display = ‘none‘ 41 parentElement.classList.remove(‘has-error‘) 42 } else { 43 errorElement.textContent = error 44 errorElement.style.display = ‘block‘ 45 parentElement.classList.add(‘has-error‘) 46 } 47 } 48 49 function getErrorElement(el) { 50 const parentElement = el.parentElement 51 let errorElement = parentElement.querySelector(‘.help-block‘) 52 53 if (!errorElement) { 54 const tpl = `<span class="help-block"></span>` 55 const fragment = document.createRange().createContextualFragment(tpl) 56 57 parentElement.appendChild(fragment) 58 errorElement = parentElement.querySelector(‘.help-block‘) 59 } 60 61 return errorElement 62 } 63 export default { 64 bind(el, binding, vnode) { 65 // 使用解構賦值聲明 value = binding.value, arg = binding.arg, modifiers = binding.modifiers 66 const { value, arg, modifiers } = binding 67 // 如果沒傳對應的事件名稱參數,就默認使用 change 事件 68 const eventType = [‘change‘, ‘blur‘, ‘input‘].indexOf(arg) !== -1 ? arg : ‘change‘ 69 // 默認處理器,當用戶開始輸入時,移除錯誤提示 70 const defaultHandler = () => { 71 showError(el) 72 } 73 // 驗證處理器,當用戶觸發對應的事件時,驗證用戶輸入的信息 74 const handler = () => { 75 validate(el, modifiers, value) 76 } 77 78 // 在 el 元素上的添加 input 事件監聽 79 el.addEventListener(‘input‘, defaultHandler, false) 80 // 在 el 元素上的添加用戶指定的事件監聽 81 el.addEventListener(eventType, handler, false) 82 83 // 移除 el 元素上事件監聽和數據綁定的方法 84 el.destroy = () => { 85 el.removeEventListener(‘input‘, defaultHandler, false) 86 el.removeEventListener(eventType, handler, false) 87 el.destroy = null 88 } 89 }, 90 inserted(el, binding, vnode) {//被綁定插入父節點的時候調用,保證了父節點的存在 91 const { value, modifiers } = binding 92 // 指定當前一系列驗證項的父級,我們這裏指定為含 data-validator-form 的元素 93 const form = el.closest(‘[data-validator-form]‘) 94 // 指定一個按鈕來檢查所有驗證項,我們這裏指定為含 type=submit 的元素 95 const submitBtn = form ? form.querySelector(‘[type=submit]‘) : null 96 97 if (submitBtn) { 98 // 提交處理器 99 const submitHandler = () => { 100 // 驗證所有項 101 validate(el, modifiers, value) 102 103 // 獲取錯誤信息 104 const errors = form.querySelectorAll(‘.has-error‘) 105 106 if (!errors.length) { 107 // 沒有錯誤信息時,在按鈕上添加一個 canSubmit 屬性,並指定為 true 108 submitBtn.canSubmit = true 109 } else { 110 // 有錯誤信息時,在按鈕上添加一個 canSubmit 屬性,並指定為 false 111 submitBtn.canSubmit = false 112 } 113 } 114 115 // 在按鈕上的添加 click 事件監聽 116 submitBtn.addEventListener(‘click‘, submitHandler, false) 117 118 // 移除按鈕上事件監聽和數據綁定的方法 119 el.destroySubmitBtn = () => { 120 submitBtn.removeEventListener(‘click‘, submitHandler, false) 121 el.destroySubmitBtn = null 122 } 123 } 124 }, 125 unbind(el) { 126 // 移除事件監聽和數據綁定 127 el.destroy() 128 if (el.destroySubmitBtn) el.destroySubmitBtn() 129 } 130 }

2). 註冊全局驗證指令

src/directives 下新建 index.js 文件,復制貼入以下代碼:

src/directives/index.js

import Vue from ‘vue‘
import validator from ‘./validator‘

Vue.directive(‘validator‘, validator)

註冊全局指令需要使用 Vue.directive,第一個參數 ‘validator‘ 是指令名稱,第二個參數 validator 是指令對象或者指令函數,我們這裏是指令對象。全局註冊的好處是,可以在實例內部的所有組件中使用,而不用在每個組件內部單獨引用和註冊。

3). 引入全局驗證指令

打開 src/main.js 文件,引入 ./directives

src/main.js

1 import Vue from ‘vue‘
2 import App from ‘./App‘
3 import router from ‘./router‘
4 import ‘./directives‘

4). 使用表單驗證指令

打開 src/views/auth/Register.vue,查找 <div class="panel-body"> 元素,復制以下代碼將其替換:

src/views/auth/Register.vue

 1 <div class="panel-body" data-validator-form>
 2   <div class="form-group">
 3     <label class="control-label">用戶名</label>
 4     <input v-validator:input.required="{ regex: /^[a-zA-Z]+\w*\s?\w*$/, error: ‘用戶名要求以字母開頭的單詞字符‘ }" type="text" class="form-control" placeholder="請填寫用戶名">
 5   </div>
 6   <div class="form-group">
 7     <label class="control-label">密碼</label>
 8     <input id="password" v-validator.required="{ regex: /^\w{6,16}$/, error: ‘密碼要求 6 ~ 16 個單詞字符‘ }" type="password" class="form-control" placeholder="請填寫密碼">
 9   </div>
10   <div class="form-group">
11     <label class="control-label">確認密碼</label>
12     <input v-validator.required="{ target: ‘#password‘ }" type="password" class="form-control" placeholder="請填寫確認密碼">
13   </div>
14   <div class="form-group">
15     <label class="control-label">圖片驗證碼</label>
16     <input v-validator.required="{ title: ‘圖片驗證碼‘ }" type="text" class="form-control" placeholder="請填寫驗證碼">
17   </div>
18   <div class="thumbnail" title="點擊圖片重新獲取驗證碼">
19     <div class="captcha"></div>
20   </div>
21   <button type="submit" class="btn btn-lg btn-success btn-block">
22     <i class="fa fa-btn fa-sign-in"></i> 註冊
23   </button>
24 </div>

我們先在外層元素上,添加 data-validator-form 屬性,使其成為所有驗證項的父級:

1 <div class="panel-body" data-validator-form>

自定義指令知識:

  • binding.name:指令名,不包括 v- 前綴,這裏是 ‘validator‘
  • binding.value:指令的綁定值,這裏是 { regex: /^[a-zA-Z]+\w*\s?\w*$/, error: ‘用戶名要求以字母開頭的單詞字符‘ }
  • binding.arg:傳給指令的參數,這裏是 ‘input‘
  • binding.modifiers:一個包含修飾符的對象,這裏是 { required: true }

註冊全局指令(表單驗證)