使用 JavaScript 進行即時表單驗證

920302 7年前發布 | 39K 次閱讀 JavaScript開發 JavaScript

HTML5引入了幾個新的屬性來實現基于瀏覽器的表單驗證。 pattern屬性是一個正則表達式,用于定義textarea元素和大多數input元素類型的有效輸入范圍。 required 屬性指定某個字段是否需要輸入。 對于沒有實現這些屬性的傳統瀏覽器,我們可以使用它們的值作為填充表單的基礎。 我們還可以使用它們來提供更有趣的增強功能 - 即時表單驗證。

來自作者的更多內容

我們必須非常小心以避免得意忘形,創建過于侵略性的表單驗證,打破了自然的瀏覽行為,給用戶造成麻煩。 例如,我見過無法使用Tab鍵跳出無效字段的表單 - JavaScript被使用(或者被 濫用 )來強制焦點留在字段中直到有效為止。 這是非常糟糕的可用性,并且直接違反了 可訪問性準則

我們在本文中要做的是更少的侵入性。 它甚至不是完整的客戶端驗證 - 它只是一個微妙的可用性增強,以可訪問的方式實現,(正如我在測試腳本時發現的)幾乎完全相同于Firefox的原生功能。

基本概念

在最新版本的Firefox中,如果必填( required )字段為空,或者其值與模式( pattern )不匹配,那么該字段將顯示一個紅色的輪廓,如下圖所示。

當然,這種情況不會馬上發生。如果是這樣的話,則默認情況下,每個必填字段都將具有該輪廓。相反,這些輪廓僅在您與該字段進行交互 之后 顯示,這基本上(盡管不是精確)類似于onchange事件。

所以這就是我們要做的,使用onchange作為觸發事件。作為替代方案,我們可以使用oninput事件,一旦任何值被輸入或粘貼到該字段中即可觸發。但這實在是 太  快了,因為它很容易在打字時快速地觸發和關閉,產生一種閃爍的效果,這將使一些用戶感到討厭或不可避免地分散了用戶的注意力。而且,在任何情況下,oninput不會從程序輸入中觸發,而onchange會,而且我們可能還需要它處理像第三方插件那樣的自動完成的事情。

定義HTML和CSS

讓我們看一看我們的實現,從它的HTML開始:

<form action="#" method="post">
  <fieldset>

    <legend><strong>Add your comment</strong></legend>

    <p>
      <label for="author">Name <abbr title="Required">*</abbr></label>
      <input 
        aria-required="true"
        id="author"
        name="author"
        pattern="^([- \w\d\u00c0-\u024f]+)$"
        required="required"
        size="20"
        spellcheck="false"
        title="Your name (no special characters, diacritics are okay)"
        type="text"
        value="">
    </p>

    <p>
      <label for="email">Email <abbr title="Required">*</abbr></label>
      <input 
        aria-required="true"
        id="email"
        name="email"
        pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$" 
        required="required"
        size="30"
        spellcheck="false"
        title="Your email address"
        type="email"
        value="">
    </p>

    <p>
      <label for="website">Website</label>
      <input
        id="website"
        name="website"
        pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$"
        size="30"
        spellcheck="false"
        title="Your website address"
        type="url"
        value="">
    </p>

    <p>
      <label for="text">Comment <abbr title="Required">*</abbr></label> 
      <textarea
        aria-required="true"
        cols="40"
        id="text"
        name="text"
        required="required"
        rows="10"
        spellcheck="true"
        title="Your comment"></textarea>
    </p>

  </fieldset>
  <fieldset>

    <button name="preview" type="submit">Preview</button>
    <button name="save" type="submit">Submit Comment</button>

  </fieldset>
</form>

這個例子是一個簡單的評論表單,其中一些字段是必需的,一些是需要驗證的,一些是二者都有的。 具有 required屬性的 字段也具有aria-required屬性,這為那些不了解新的input類型的輔助技術提供了回退語義。

ARIA規范 還定義了aria-invalid屬性,這就是我們將要用來指示字段何時無效(HTML5中沒有等效屬性)的屬性。 aria-invalid屬性顯然提供了可訪問的信息,但它也可以用作CSS鉤子來應用紅色輪廓:

input[aria-invalid="true"], textarea[aria-invalid="true"] {
  border: 1px solid #f00;
  box-shadow: 0 0 4px 0 #f00;
}

我們可以只使用box-shadow,而不是border,坦率地說,這看上去更好,但是不支持box-shadow的瀏覽器將不會顯示,比如IE8。

閱讀現代JavaScript

跟上不斷變化的的JavaScript世界

開始閱讀

添加JavaScript

現在我們已經有了靜態代碼,我們可以添加腳本。 我們首先需要的是一個基本的addEvent()函數:

function addEvent(node, type, callback) {
  if (node.addEventListener) {
    node.addEventListener(type, function(e) {
      callback(e, e.target);
    }, false);
  } else if (node.attachEvent) {
    node.attachEvent('on' + type, function(e) {
      callback(e, e.srcElement);
    });
  }
}

接下來,我們需要一個函數來確定一個給定的字段是否應該被驗證,它只是測試該字段既沒被禁用(disabled )也不是只讀(readonly),并且它具有一個 pattern 或一個 required 屬性:

function shouldBeValidated(field) {
  return (
    !(field.getAttribute("readonly") || field.readonly) &&
    !(field.getAttribute("disabled") || field.disabled) &&
    (field.getAttribute("pattern") || field.getAttribute("required"))
  );
}

前兩個條件可能看起來很冗長,但它們是必需的,因為元素的 disabled 和 readonly 屬性不一定反映其屬性狀態。 例如,在Opera中,硬編碼屬性readonly =“readonly”的字段對于其readonly屬性仍將返回undefined(點屬性僅匹配通過腳本設置的狀態)。

一旦我們得到了這些實用程序,我們就可以定義主要的驗證函數,它測試這個字段,然后執行實際的驗證,如果適用的話:

function instantValidation(field) {
  if (shouldBeValidated(field)) {
    var invalid =
      (field.getAttribute("required") && !field.value) ||
      (field.getAttribute("pattern") &&
        field.value &&
        !new RegExp(field.getAttribute("pattern")).test(field.value));
    if (!invalid && field.getAttribute("aria-invalid")) {
      field.removeAttribute("aria-invalid");
    } else if (invalid && !field.getAttribute("aria-invalid")) {
      field.setAttribute("aria-invalid", "true");
    }
  }
}

所以當一個字段是必需的卻沒有賦值,或者它的值不匹配它的模式,則該字段是無效的。

由于模式( pattern )已經定義了正則表達式的字符串形式,所以我們要做的就是將該字符串傳遞給RegExp構造函數,它將創建一個可以對該值進行測試的正則表達式對象。 但是,我們必須 預先測試  該值以確保它不為空,以便正則表達式本身不必考慮空字符串。

一旦我們確定一個字段是否無效,我們就可以控制它的aria-invalid屬性來指示該狀態 - 將它添加到一個不具有該字段的無效字段中,或者從一個有效的字段中刪除它。 簡單吧! 最后,為了把這一切付諸實施,我們需要將驗證函數綁定到一個onchange事件。 就是  這么簡單:

addEvent(document, "change", function(e, target) {
  instantValidation(target);
});

然而,為了使它工作,onchange事件 必須冒泡 (使用通常稱為 事件委托 的技術),但在Internet Explorer 8和更早版本中,onchange事件 不會冒泡 。 我們可以選擇忽略這些瀏覽器,但我認為這將是一種恥辱,尤其是當問題的解決方法是如此簡單。 它只是意味著代碼更加復雜 - 我們必須獲取input和textarea元素的集合,遍歷它們,并將onchange事件單獨綁定到每個字段上:

var fields = [
  document.getElementsByTagName("input"),
  document.getElementsByTagName("textarea")
];
for (var a = fields.length, i = 0; i < a; i++) {
  for (var b = fields[i].length, j = 0; j < b; j++) {
    addEvent(fields[i][j], "change", function(e, target) {
      instantValidation(target);
    });
  }
}

結論及更多

至此我們已經完成了 - 一個簡單和非侵入性的即時表單驗證增強,提供可訪問和可視化的提示,以幫助用戶完成表單。 您可以查看以下演示:

請參閱 CodePen 上SitePoint( @SitePoint )的Pen 即時表單驗證

 

來自:https://coyee.com/article/12365-instant-form-validation-using-javascript

 

 本文由用戶 920302 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!