HTML の input に入力された Email のバリデーションをフォーカスアウト時に行うスクリプト

ウェブのフォームでメールアドレスの形式を確認するときに、HTML 属性で `type="email"` を指定しておくと、メールアドレスのチェックをしてくれます。

ただこの機能、 "foge@fuga" のようなものも通してしまって結構緩めなんですよね。

で、もうちょっと厳密に確認するためのスクリプトを探すと jQuery のプラグインが多いんですが、ピュアな JavaScript のものがほしいなと思いました。

```html
<meta charset="utf-8">
<style>
  form {
    margin: 30px;
  }
  
  form > div {
    margin-bottom: 1em;
  }

  label {
    margin-right: .5em;
  }

  label::after {
    content: ":";
  }

  input,textarea,button {
    border-radius: 3px;
    font-size: 12pt;
    padding: .2em .8em;
  }

  button {
    cursor: pointer;
  }

  .sng-email-alert {
    color: #F00;
    font-weight: bold;
    margin-left: 1em;
  }
</style>
<form action="#">
  <div>
    <label for="email">Email</label>
    <input type="email" name="email" id="email" class="sng-email-check">
    <span class="sng-email-alert">正しいメールアドレスを入力して下さい</span>
  </div>

  <div>
    <button type="button">入力内容を送信する</button>
  </div>
</form>

<script>
  // script を初期化する
  window.onload = function() {
    SngEmailChecker({
      fadeInTime: '200ms',
      fadeOutTime: '200ms',
      borderNotification: true
    });
  }  
</script>
```

```css
.sng-email-alert {
  opacity: 0;
  transition-property: opacity;
}

.sng-email-alert.sng-alert-show {
  opacity: 1;
  transition-property: opacity;
}

input.sng-email-check {
  transition-property: box-shadow;
}

input.incorrectValue {
  box-shadow: 0 0 3px 3px rgba(255, 60, 30, .9);
  transition-property: box-shadow;
}

input.incorrectValue:focus {
  outline: 0;
}
```

```js
(function(global) {
  var SngEmailChecker = (function() {
    // メールアドレス判定用の正規表現
    // 参考: http://emailregex.com/
    var emailExpression = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
        emailInputs = Array.prototype.slice.call(document.getElementsByClassName('sng-email-check')),
        alertBoxes = Array.prototype.slice.call(document.getElementsByClassName('sng-email-alert')),
        globalConfig = {}

    function SngEmailChecker(config) {
      if (! config) config = {};
      globalConfig['fadeInTime'] = config.fadeInTime || '200ms';
      globalConfig['fadeOutTime'] = config.fadeOutTime || '200ms';
      globalConfig['borderNotification'] = config.borderNotification === undefined || config.borderNotification;

      emailInputs.map(function(elm) {
        elm.addEventListener('blur', onFocusOut);
      });
    }

    function onFocusOut() {
      var value = this.value;
      var isCorrect = emailExpression.test(value);
      alertBoxes.map(function(elm) {
        var classList = elm.classList;
        if (isCorrect) {
          elm.style['transition-duration'] = globalConfig.fadeOutTime;
          classList.remove('sng-alert-show');
        } else {
          elm.style['transition-duration'] = globalConfig.fadeInTime;
          classList.add('sng-alert-show');
        }
      });

      if (globalConfig.borderNotification) {
        emailInputs.map(function(elm) {
          if (isCorrect) {
            elm.style['transition-duration'] = globalConfig.fadeOutTime;
            elm.classList.remove('incorrectValue');
          } else {
            elm.style['transition-duration'] = globalConfig.fadeInTime;
            elm.classList.add('incorrectValue');
          }
        });
      }
    }
    return SngEmailChecker;
  }());

  global.SngEmailChecker = SngEmailChecker;
}(this));
```

CodePen にデモを置いておきます。

<p data-height="265" data-theme-id="dark" data-slug-hash="oBPZbL" data-default-tab="js,result" data-user="shingorow" data-embed-version="2" data-pen-title="SNGEmailValidation" class="codepen">See the Pen <a href="http://codepen.io/shingorow/pen/oBPZbL/">SNGEmailValidation</a> by Shingo Matsui (<a href="http://codepen.io/shingorow">@shingorow</a>) on <a href="http://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

世の中にはキーをタイプする度にチェックするものが結構ありますが、個人的にちょっとしつこすぎるなぁと思うのでフォーカスが外れたときのみチェックするようにしています。

使い方は、

1. JavaScript と CSS ファイルを読み込む
2. チェックしたい INPUT 要素にクラス "sng-email-check" を、アラートとして表示する要素にクラス "sng-email-alert" を設定
3. 任意のタイミングで関数を実行するスクリプトを書く
4. オプションで関数にパラメータを設定する

と言った感じ。

パラメーターは

```js

{
  fadeInTime: '200ms', // メッセージやインプット要素のシャドウが表示されるまでの時間
  fadeOutTime: '200ms', // メッセージやインプット要素のシャドウが消えていくまでの時間
  boarderNotification: true // インプット要素のシャドウを表示するか否か
}

```

を設定できます。

引数を省略すると上記の値がデフォルト値として設定されます。

勉強も兼ねて作ったものなので、実運用にあたっては jQuery プラグインなどを探したほうがいいかもしれません。

Bootstrap とか使うときにどうせ jQuery 必要になりますしねぇ。