
Vanilla JSを使用してログイン機能を実装しました。
こんにちは。Webコーダーのはるです。
現在、所属している「もりけん塾」でJavaScriptのハンズオン課題 に取り組み、レビューをいただいています。
今日は、課題26 についてアウトプットをしていきます。
(前回までのアウトプットは、こちらです。)
実装する過程で学んだことを、学習ノートとして記録していきます。
認識の間違えている箇所がありましたら、お問い合わせからご指摘いただけるとうれしいです。
JavaScript課題26の仕様
(もりけん先生のJavaScriptハンズオン課題より)
HTMLコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/reset.css">
<link rel="stylesheet" href="./css/style.css">
<script type="module" src="./js/login.js"></script>
<title>Login</title>
</head>
<body>
<script>
if (localStorage.getItem("token")) window.location.href = "./loginuserpage.html";
</script>
<form class="form box" id="js-form">
<div class="form__title" id="is-form-title">
<h1 class="title form__title-text">Login</h1>
<a class="form__title-link" href="./register.html">Sign Up</a>
</div>
<div class="form__inner">
<div class="form__item">
<label for="userid">User ID <span class="form__notion">(Name or E-mail)</span></label>
<input type="text" class="form__item-input js-form-userid" id="userid" name="userid" required>
<p class="error"></p>
</div>
<div class="form__item">
<label for="password">Password</label>
<input type="password" class="form__item-input js-form-password" id="password" name="password" required>
<p class="error"></p>
</div>
<p class="form__text"><a class="form__link" href="./forgotpassword.html">パスワードをお忘れの方はこちら</a></p>
<div class="form__button">
<input type="button" id="js-submit-button" value="Login" disabled>
</div>
</div>
</form>
</body>
</html>
フォームは前回の課題25とほぼ一緒ですが、UserIDのinputには名前・メールアドレスのどちらも入れられるように type=”text” としました。
submitボタンを押したときの挙動
ログイン画面のsubmitボタンを押すと、tryLogin()関数が実行されます。
submitButton.addEventListener("click", tryToLogin);
tryLogin()関数はasync/awaitを使用して、checkToRegisterd()関数をawaitしています。
これは “input入力値と登録された値が正しいか” を確認する関数です。
const tryToLogin = async() => {
let result;
try {
result = await checkToRegistered();
localStorage.setItem("token", result.token);
} catch(rejectObj) {
result = rejectObj;
} finally {
window.location.href = result.token ? "./loginuserpage.html" : "./notautherize.html";
}
}
const checkToRegistered = () => {
return new Promise((resolve, reject) => {
const inputsValues = {
userId: userIdOfInput.value,
password: passwordOfInput.value
}
const registeredData = {
name: "takeda",
email : "abcdefg@gmail.com",
password : "N302aoe3"
}
if ((inputsValues.userId === registeredData.name || inputsValues.userId === registeredData.email) && (inputsValues.password === registeredData.password)) {
resolve({ token: chance.apple_token(), ok: true, code: 200 });
} else {
reject({ ok: false, code: 401 });
}
})
}
- checkToRegistered()関数でpromiseオブジェクトを定義して、inputValuesとregisteredDataを比較しました。
if ((inputsValues.userId === registeredData.name || inputsValues.userId === registeredData.email) && (inputsValues.password === registeredData.password)) {
resolve({ token: chance.apple_token(), ok: true, code: 200 });
} else {
reject({ ok: false, code: 401 });
}
- 合っていればresolveが実行されて、引数としてtoken情報のオブジェクトが渡されます。
- 間違っていたらrejectが実行されて、引数のオブジェクトにはtoken情報は含まれません。
それぞれの引数が、tryToLogin() 関数
のtry / catch に渡ります。
let result;
try {
result = await checkToRegistered();
localStorage.setItem("token", result.token);
} catch(rejectObj) {
result = rejectObj;
変数resultには、
- resolveの時に渡されるtoken情報のオブジェクト
または
- rejectの時に渡されるオブジェクト
が代入されます。
finallyでは、変数resultにtokenの値があればコンテンツページへ、なければ権限なしページ遷移させます。
} finally {
window.location.href = result.token ? "./loginuserpage.html" : "./notautherize.html";
}
レビュー
① finally内のコードをrefactor
最初はこのように書いていましたが、もっとスマートに書けることを知りました。
//旧コード
result.token? window.location.href = "./loginuserpage.html" : window.location.href = "./notautherize.html";
//修正コード
window.location.href = result.token ? "./loginuserpage.html" : "./notautherize.html";
② checkToRegistered関数の登録済みデータのオブジェクトにnameがない
仕様に「userIDのinputには名前とメールアドレスのどちらも入れられるようにする」とあったのですが、最初その仕様を満たせていませんでした。。
//旧コード
const registeredData = {
userId : "abcdefg@gmail.com", //架空のメアドです
password : "N302aoe3"
}
//修正コード
const registeredData = {
name : takeda,
userId : "abcdefg@gmail.com",
password : "N302aoe3"
}
③ inputの値を取得する別関数を、tryToLogin関数に合体させる
inputの値を取得する別関数を作っていたのですが、他の場所で返り値を使用しないためtryToLogin関数の中で実行するようアドバイスいただきました。
//削除した関数
const getInputValueAndTryLogin = () => {
const inputsValues = {
userId: document.querySelector(".js-form-userid").value,
password: document.querySelector(".js-form-password").value
}
tryToLogin(inputsValues); //inputsValuesをこの関数で取得するようにした
}
chance.jsの使用
今回、tokenの値としてランダムな文字列を発行するためにchance.jsを使用しました。
1. nodeでインストール
$ npm install chance
2. 使いたいjsファイルでimport、インスタンスを作成
//in js file
import { Chance } from "chance";
const chance = new Chance();
3. 使用の際は、公式ページから作成したい文字列や数値などの様式に合わせて用意されているメソッドを使います。今回は、apple_tokenを使用しています。
//該当箇所のオブジェクト抜粋
{ token: chance.apple_token(), ok: true, code: 200 }
これで、毎回ランダムなtokenが発行されます。
tokenをlocalStorageに保存・削除
仕様にもあるとおり、ローカルストレージの使用はあくまで学習のために使用しています。
【保存】
- ログインに成功してtokenが発行されていれば、そのtokenをlocalStorageに埋め込みます。
// localStorage.setItem("キー名", 値);
localStorage.setItem("token", result.token);
変数resultには、resolveされた時に引数として渡るオブジェクトが代入されています。
{ token: chance.apple_token(), ok: true, code: 200 }
【確認】
- localStorageに保存されているかの確認は、キー名での検索が可能です。
// tokenというキーを入れて確認した例
const hoge = localStorage.getItem("token");
または、Developer Toolsでも確認できます。
DevTools > Apprication > Storage > LocalStorage
【削除】
localStorage.removeItem("キー名");
tokenがあるか確認してページ遷移させる
仕様にある、「ログインページやコンテンツページに遷移したら localStorage
に値があるかチェックして、なければログイン画面に飛ばしてください。」を実装するために、該当コードを書く位置を工夫しました。
<body>
<script>
if (localStorage.getItem("token")) window.location.href = "./loginuserpage.html";
</script>
- jsファイルの最初にコードを書く
- 該当コードを別ファイルに分ける
- jsファイルの読み込みにasyncを使用する
など試行錯誤しましたが、tokenがない場合でもコンテンツページのロードの方が先に始まってしまい、ログインページへの遷移が遅れるためです。
もしかしたら他に良い方法があるのかもしれませんが、辿り着けていません。
今回のコード
OpenSandboxから詳細を見ることができます。login.jsがこの課題の主なjsコードです。
//
学習に使用している本は、JavaScript本格入門・独習JavaScriptです。
あとがき
さえさん(@sae_prog)、まいさん(@mai2022web)、ちひろさん(@chihiro7029) レビューいただきありがとうございました!
今回も、仕様を満たしているかの細かなチェックから、refactorの上手な方法までたくさんのアドバイスをいただきました。お時間を割いていただきありがとうございました!
今日は以上です。
//
【もりけん塾で勉強しています】
もりけん先生(@terrace_tec)のHPはこちら