【monaca】JavaScriptでアプリの簡易パスロック機能を作る

monacaで作ったアプリにJavaScriptを使ってパスロックもどきを実装してみました。

こんなの↓

![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/bcef0d3c-9559-0b95-40c3-4bd8e8b70753.gif)![2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/00ab6944-cce7-226b-e72d-01b4a9ffc298.gif)




こちらがパスコードを設定/変更するための画面↓


![4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/353ba270-cd8f-0fbf-78ab-e4bfe2f9c4d2.gif)

仕組みとしては、パスコード入力画面をモーダルとしてホーム画面に被せ、入力したパスコードがあらかじめローカルストレージに保存しておいたパスコードと一致したらモーダルを消す、という単純な機能です。

ただし、[後で説明](#6-注意点)しますが、この方法はハイブリッドアプリでしか通用しません。モーダルを被せてるだけなので、Webアプリやサイトに使ってもあまりパスロックとしては機能しないのでご注意ください。

#目次
[1.完成形](#1-完成形)
[2.パスロック設定メニュー](#2-パスロック設定メニュー)
[3.パスコード入力画面](#3-パスコード入力画面)
[4.パスロック設定メニュー解説](#4-パスロック設定メニュー解説)
[5.パスコード入力画面解説](#5-パスコード入力画面解説)
[6.注意点](#6-注意点)




<hr>

#1. 完成形

##2. パスロック設定メニュー
まず完成形がこちら。
こちらパスロック設定メニューのコード。３個目のGIFのやつです


<p class="codepen" data-height="971" data-theme-id="dark" data-default-tab="html,result" data-user="toshihide2000" data-slug-hash="jOVKMYo" style="height: 971px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="passlock-menu">
  <span>See the Pen <a href="https://codepen.io/toshihide2000/pen/jOVKMYo">
  passlock-menu</a> by toshihide (<a href="https://codepen.io/toshihide2000">@toshihide2000</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

##3. パスコード入力画面

<p class="codepen" data-height="848" data-theme-id="dark" data-default-tab="css,result" data-user="toshihide2000" data-slug-hash="wvoXoaL" style="height: 848px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="enterpass-modal">
  <span>See the Pen <a href="https://codepen.io/toshihide2000/pen/wvoXoaL">
  enterpass-modal</a> by toshihide (<a href="https://codepen.io/toshihide2000">@toshihide2000</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>



#4. パスロック設定メニュー解説

<b>新規パスコードを入力するフォーム</b>

````html
  <div  class="pass-container"id="newpass">
    <div>パスワードを設定/更新</div>
        <label>
          <input type="password"  maxlength="4" pattern="[1-9][0-9]*" inputmode="numeric" id="newpassword" required>
        </label>※数字4字
  </div>
  <div  class="pass-container"id="confirmation">
        <div>確認のためもう一度入力してください。</div>
        <label>
         <input type="password"  maxlength="4" pattern="[1-9][0-9]*" inputmode="numeric"id="pass-confirm" onchange="Varidate()" required>
        </label>
        <div  class="green"id="log"></div>
  </div>
  <div  class="modalbefore btn"id="pass-set">決定</div>
````

input type="password"だと英数字キーボードが出るのでinputmode="numeric"でテンキーが出るようにします。

````JavaScript
 function Varidate(){
            var NewPass=document.getElementById("newpassword").value;
      　　　 var ConfirmPass=document.getElementById("pass-confirm").value;
            var Log= document.getElementById("log");
        if(NewPass===ConfirmPass){
         Log.innerHTML="一致";
         document.getElementById("pass-set").classList.remove("modalbefore");
         Log.classList.remove("red");
         Log.classList.add("green");
       }
    else{
         Log.innerHTML="不一致";
         Log.classList.remove("green");
         Log.classList.add("red");
       }
         };
  document.getElementById("pass-set").addEventListener("click",()=>{
       var savedpass=document.getElementById("newpassword").value;
       var Log= document.getElementById("log");
       if(savedpass.length<4){
           Log.innerHTML="パスワードは4字で設定してください";
           Log.classList.remove("green");
           Log.classList.add("red");
       }else{
           localStorage.setItem("kin-pass",savedpass);
           alert("パスワードを"+savedpass+"に設定しました");
       }
    });

````

パスコードがnullの状態で保存すると解除できなくなって詰むので、初期の状態ではパスコードを保存する「決定」ボタンはdisplay:none;であるmodalbeforeクラスをつけて消しておきます。
確認用フォームに入力し終わったタイミングで両方のフォームを参照し、互いのvalueが一致すればdisplay:none;を外し、保存できるようにします。


決定ボタンを押すとフォームのvalueが取得されます。パスコードが4文字未満だと保存せず、input要素にmaxlength="4"をつけているので、保存できるパスコードは４文字になります。保存できたらアラートを出してパスワードをユーザーに確認させます。

greenとかredとかいうクラスをつけ外ししていますが、ログの色を変えてるだけなので省いても大丈夫です。

<hr>

````html
    <div class="passlock-box" id="passlock-onoff">
         <i class="fas fa-lock-open" id="lock-open"></i>
        <i class="fas fa-lock none" id="lock"></i>
   <div class="switch">
            <div class="switchbtn" id="Switchbtn">
              <div class="btncircle" id="iosbtn" ></div>
              <div class="btncircle none" id="on"></div>
            </div>
          </div>
</div>
````

````JavaScript
// <!-- ONにした時 -->
document.getElementById("iosbtn").addEventListener("click",()=>{
    var PASS=localStorage.getItem("kin-pass");
    if(PASS==null){
            alert("パスワードが設定されていないためロックをONにできません");
    }else{
        document.getElementById("iosbtn").classList.add("none");
        document.getElementById("on").classList.remove("none"); 
        document.getElementById("lock-open").classList.add("none");
        document.getElementById("lock").classList.remove("none");
        document.getElementById("Switchbtn").classList.add("swi-btn-active");
        localStorage.setItem("passlock",1);
    }
});
// <!-- OFFにした時 -->
document.getElementById("on").addEventListener("click",()=>{
  document.getElementById("iosbtn").classList.remove("none");
  document.getElementById("on").classList.add("none");
  document.getElementById("lock").classList.add("none");
  document.getElementById("lock-open").classList.remove("none");
  document.getElementById("Switchbtn").classList.remove("swi-btn-active");
  localStorage.setItem("passlock",0);
});


````

やたらとdocument.getElementById~~が続いてますが、これらは全てこれ↓です。パスロックの機能とは関係ない部分なので無視してもらって大丈夫です。

![5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/7de6c833-e592-cc1a-4742-3f8edeb02cef.gif)


大事なのは、パスロックをONにした時の<code> localStorage.setItem("passlock",1);</code>と、OFFにした時の<code>localStorage.setItem("passlock",0);</code>、

初期状態ではもちろんパスロックはOFFになっていますが、パスロックをONにしたら、次にアプリを開いた時にはパスロックがONになっていないといけません。つまりパスロックがONなのかOFFなのかということをブラウザに記憶させ、次回読み込み時にはそれに基づいてパスロック入力モーダルを表示するかしないか分岐する必要があります。そこで、パスロックがONの状態を1、OFFの状態を0として、ON/OFFを切り替えた時に0か1かを保存しています。

#5. パスコード入力画面解説

````html

<!-- パスコード入力モーダル -->
<div class="off"id="enterpass-body">
 <div class="delay" id="enterpass-container">
  <div id="enterpass-text"> パスワード</div>
  <label>
    <input type="password" maxlength="4" pattern="[1-9][0-9]*" inputmode="numeric" required class="shake-2" id="enterpass" onchange="unlock()">
  </label>
 </div>
</div>

````


````JavaScript
//パスコードが一致したら解除
function unlock(){
  var PassWord=localStorage.getItem("kin-pass");
  var Enterpass=document.getElementById("enterpass").value;
  if(PassWord===Enterpass){
   document.getElementById("enterpass-body").classList.add("off");
  }else{
   document.getElementById("enterpass").classList.toggle("shake");
   document.getElementById("enterpass").classList.toggle("shake-2");
  }
}
// ページの読み込み時 
window.addEventListener("load",()=>{
  var OnOff=localStorage.getItem("passlock")
  if(OnOff==1){
     document.getElementById("enterpass-body").classList.remove("off");
  }else{
     console.log("パスロックOFF");
  };
});

````

パスコード入力モーダルは、position:absolute;でビューポートいっぱいに画面に重ねられており、デフォルトでdisplay:none;がついています。アプリを開いたときに、ローカルストレージから0か1かを取得し、1なら（パスロックがONなら）display:none;を外してパスコード入力モーダルを表示させます。0ならdisplay:none;のままです。
パスロックがONの場合、先程のパスロックメニューで設定したパスコードと、フォームに入力されたパスコードが同じであれば、もう一度モーダルがdisplay:none;となり、パスロック解除となります。

以上が、JavaScriptでフロントだけで簡易パスロックを実装する方法です。

#6. 注意点

注意したいのは、パスロックといえどモーダルで隠してるだけで、開発者ツールで普通に中身が見れてしまうのでWebアプリやサイトではパスロックとしては全く意味がないということです。ただ、今回のようにmonacaでアプリ化した場合には開発者ツールで覗くなんてことはできませんので、こういう場合に限っては、パスロックとしてそこそこ使えるんじゃないかと思います。


<hr>

今回パスロックを実装したアプリ
※オ●禁アプリです
![kinyoku-100px-icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/e4e3ef0f-f893-59bd-540b-d3c09d83e2ae.png)
[禁欲エボリューション](https://apps.apple.com/jp/app/禁欲エボリューション/id1553966013)

過去アプ↓
![mem-100px-icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/c4b778ff-7a14-b489-c71e-23fe6f6b7eb8.png)
[文字数制限メモ](https://apps.apple.com/jp/app/文字数制限メモ/id1552651234)