単語帳 - Javascript

自作プログラム

JSON ファイルを読み込んで単語帳のようなものを作成しました。

JSFiddle(ジェイエスフィドル) で動作が確認できます。

サーバーにアップロードしなくても、index.html をブラウザで開けばローカル上でも動作します。

JSFiddle

HTML・CSS・JavaScriptコードスニペットを共有できるオンラインIDEサービス・コミュニティ。ほかには、「 CodePen 」、「 JS Bin 」、「 Codeply 」などがあります。

JSFiddle の実行結果を画面いっぱいに表示するには、URL の最後に「 show 」を加えます。

操作方法

「 ファイルを選択 」で、JSON ファイルを読み込みます。

「 show - toggle 」のボタンで、読み込んだ JSON ファイルのデータ一覧の表示・非表示

「 開始No 」と「 終了No 」に数字でそれぞれ指定

「 next 」のボタンで問題の変更

「 show 」のボタンで答えの表示

JSON ファイル

読み込む JSON ファイルは次の形式です。

[
  { "que" : "質問", "ans" : "答え" }
]

サンプルデータの原子記号のデータです。sample.json ファイルを作成し、以下をコピーして JSFiddle でファイルを読み込ませて利用できます。

sample.json

[
  { "que" : "H", "ans" : "水素" },
  { "que" : "He", "ans" : "ヘリウム" },
  { "que" : "Li", "ans" : "リチウム" },
  { "que" : "Be", "ans" : "ベリリウム" },
  { "que" : "B", "ans" : "ホウ素" },
  { "que" : "C", "ans" : "炭素" },
  { "que" : "N", "ans" : "窒素" },
  { "que" : "O", "ans" : "酸素" },
  { "que" : "F", "ans" : "フッ素" },
  { "que" : "Ne", "ans" : "ネオン" },
  { "que" : "Na", "ans" : "ナトリウム" },
  { "que" : "Mg", "ans" : "マグネシウム" },
  { "que" : "Al", "ans" : "アルミニウム" },
  { "que" : "Si", "ans" : "ケイ素" },
  { "que" : "P", "ans" : "リン" },
  { "que" : "S ", "ans" : "硫黄" },
  { "que" : "Cl", "ans" : "塩素" },
  { "que" : "Ar", "ans" : "アルゴン" },
  { "que" : "K", "ans" : "カリウム" },
  { "que" : "Ca", "ans" : "カルシウム" },
  { "que" : "Sc", "ans" : "スカンジウム" },
  { "que" : "Ti", "ans" : "チタン" },
  { "que" : "V", "ans" : "バナジウム" },
  { "que" : "Cr", "ans" : "クロム" },
  { "que" : "Mn", "ans" : "マンガン" },
  { "que" : "Fe", "ans" : "鉄" },
  { "que" : "Co", "ans" : "コバルト" },
  { "que" : "Ni", "ans" : "ニッケル" },
  { "que" : "Cu", "ans" : "銅" },
  { "que" : "Zn", "ans" : "亜鉛" },
  { "que" : "Ga", "ans" : "ガリウム" },
  { "que" : "Ge", "ans" : "ゲルマニウム" },
  { "que" : "As", "ans" : "ヒ素" },
  { "que" : "Se", "ans" : "セレン" },
  { "que" : "Br", "ans" : "臭素" },
  { "que" : "Kr", "ans" : "クリプトン" },
  { "que" : "Rb", "ans" : "ルビジウム" },
  { "que" : "Sr", "ans" : "ストロンチウム" },
  { "que" : "Y", "ans" : "イットリウム" },
  { "que" : "Zr", "ans" : "ジルコニウム" }
]

次のコードは、JSON ファイルを読み込み、単語帳用の JSON データを作成するサンプルです。

const fs = require('fs');
const data = JSON.parse(fs.readFileSync('./data.json', 'utf8'));
let num = data.length;
let arr = "[\n";
let que_name = "sym";
let ans_name = "name";
let file_name = "sample";

data.forEach((value, index) => {
  let txt = "";
  txt += "  { "
  txt += `"que" : "${value[que_name]}"`
  txt += `, "ans" : "${value[ans_name]}"`
  if(num == value["no"]){
    txt += " }\n"
  } else {
    txt += " },\n"
  }
  arr += txt;
})

arr += "]"

fs.writeFile(`./${file_name}.json`, arr, (err) => {});

ファイル内容

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>sample</title>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="wrapper">
    <div id="box_left" class="box">
      <div class="item">
        
        <form>
          <p>開始NO:<input type="number" id="start"></p>
          <p>終了NO:<input type="number" id="end"></p>
          
          <p><input id="myfile" type="file" /></p>
        </form>
        <div id="btn_box">
          <button type="button" id="next">next</button>
          <button type="button" id="show">show</button>
        </div>
        
        <div id="error_box">
          <p id="message"></p>
        </div>
        <div>
          <p id="question"></p>
          <p id="answer" class="dis_none"></p>
        </div>
      </div>
    </div>
    <div id="box_right" class="box">
      <div class="item">
        <h1>データ一覧</h1>
        <button type="button" id="data">show - toggle</button>
        <div id="view_box">
          <ul id="view" class="data_none"></ul>
        </div>
      </div>
    </div>
  </div>
</body>
</html>

script.js

window.onload = function(){
  var target = document.getElementById('myfile')
  let target_que = document.getElementById("question");
  let target_ans = document.getElementById("answer");
  let btn = document.getElementById("next");
  let show_btn = document.getElementById("show");
  let msg = document.getElementById("message");
  let view = document.getElementById("view");
  let data_btn = document.getElementById("data");
  let encode_data;
  let qIndex = []; // question index

  function delete_answer(target_ans){
    target_ans.innerHTML = "";
  }
  
  data_btn.addEventListener('click', function(){
    if(view.className == "data_none"){
      view.removeAttribute("class")
    } else {
      view.classList.add("data_none")
    }
  });

  show_btn.addEventListener('click', function(){
    target_ans.removeAttribute("class")
  })

  target.addEventListener('change', function(e) {
    const reader = new FileReader();
    const file = e.target.files[0];
    if(typeof file != "undefined"){
      reader.readAsText( file );
      reader.addEventListener('load', function(){
        view.innerHTML = "";
        if(JSON.parse(reader.result).length < 10){
          msg.innerHTML = "データ数が10より少ない為、処理できませんでした。"
          return;
        } else if(JSON.parse(reader.result).length > 100){
          msg.innerHTML = "データ数が100より大きい為、処理できませんでした。"
          return;
        } else {
          encode_data = JSON.parse(reader.result);
          
          encode_data.forEach(function(value, index){
            view.innerHTML += "<li>No:" + (index + 1) + ", 質問:" + value["que"] + ", 答え:" + value["ans"] + "</li>";
          })          
        }
       
      });
    } else {
      view.innerHTML = "";
    }
  })

  btn.addEventListener("click", function(){
    if(typeof encode_data != "undefined"){
      let start;
      let end;
      let startBtn = document.getElementById("start");
      let endBtn = document.getElementById("end");
      let max = encode_data.length;
      target_ans.classList.add("dis_none");
      let num = 0;

      start = Number(startBtn.value);
      end = Number(endBtn.value);

      if(startBtn.value == "" || endBtn.value == "" ){
        msg.innerHTML = "開始 No 、終了No が未入力です。";
        delete_answer(target_ans);
        return;
      }
      if(start < 1){
        msg.innerHTML = "開始 No が1より小さいです。";
        delete_answer(target_ans);
        return;
      }
      if(end > max){
        msg.innerHTML = "終了 No がデータ数より大きいです。";
        delete_answer(target_ans);
        return;
      }
      if(end < start){
        msg.innerHTML = "開始 No より 終了 No の値が小さいです。";
        delete_answer(target_ans);
        return;
      }
      if(end - start + 1 < 5){
        msg.innerHTML = "開始 No と 終了 No は5つ以上間隔をあけてください。";
        delete_answer(target_ans);
        return;
      }

      while(true){
        num = Math.floor( Math.random() * (end + 2 - start - 1) ) + start - 1;
        if (qIndex.indexOf(num) == -1){
          if(qIndex.length < 4){
            qIndex.push(num);
          } else {
            qIndex.shift();
            qIndex.push(num);
          }
          break;
        }
      }

      msg.innerHTML = "";
      target_que.innerHTML = encode_data[num]["que"];
      target_ans.innerHTML = encode_data[num]["ans"];
    }
  });
}

style.css

html {
  height: 100%;
}
body {
  height: 100%;
  margin: 0;
}
#wrapper {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
#box_left {
  margin: 0;
  padding: 0;
}
#box_right {
  margin: 0;
  padding: 0;
  border-left: 1px solid gray;
  height: 100%;
}
#box_right h1 {
  padding: 0;
  margin: 0;
}
.item {
  padding: 20px;
}
.box {
  float: left;
}
.dis_none {
  display: none;
}
#view {
  height: 400px;
  width: 800px;
  overflow-y: scroll;
}
.data_none {
  display: none;
}