質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.97%

JavaScriptでデータの保存

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 4,076

Furisuke

score 101

<div id="dayCount"></div>
<script>
var count1 = 0;
counter();

function counter(){
  count1 += 1;
  save();
}

window.onload = function(){
    var count_load = localStorage.getItem("count1");
    document.getElementById("dayCount").innerHTML = count_load;
}

function save(){
    localStorage.setItem("count1" , document.getElementById("dayCount").innerHTML);
}
</script>


というコードなのですがページを更新してもcount1は保存されているのですが、更新後にボタンを押すとまた一からカウントされます
どうすれば続きからカウントしてくれますか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • sounisi5011

    2016/07/02 18:33 編集

    「ボタン」に該当するコードを見つけられません。コード全体を質問本文に書いてください。または、「ボタン」が何を意味するのか、分かるように書いてください。

    キャンセル

回答 4

+1

いい加減な読み方をしていて、いい加減なことを書いてしまい、追記追記で訂正しましたが、煩雑になったので削除しました。元のいい加減な回答が知りたい方は編集履歴をご覧ください。

本題

他の部分をばっさり削除してこれではダメですか?

window.onload = function(){
    var count_load = localStorage.getItem("count1");
    document.getElementById("dayCount").innerHTML = count_load;
    localStorage.setItem("count1", count_load + 1);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/03 08:44

    ローカルストレージのcount1に値が何も保存されてない場合に読み込んだらどうなるの?何もない時用に初期値0で返すようにしないといけないのかな。

    キャンセル

  • 2016/07/03 08:55

    そこが問題になるのは最初の一回だけなので、あらかじめ初期化しておけばいいんじゃないでしょうか?

    もちろん無い場合は 0 を設定するようコーディングしても結構です。ただし初回以外毎回無用なチェックをする事になります。

    キャンセル

checkベストアンサー

0

var count1 = 0;
counter();

function counter(){
  count1 += 1;
  save();
}

window.onload = function(){
    var count_load = localStorage.getItem("count1");
    document.getElementById("dayCount").innerHTML = count_load;
}

function save(){
    localStorage.setItem("count1" , document.getElementById("dayCount").innerHTML);
}

このコードを見る限りでは、以下の問題が挙げられます。

  • 変数count1が、初期化とカウントアップ以外で使用されていない。

ページを読み込んだ後、このコードは以下の順に動作します。

  1. var count1 = 0;を実行。
    変数count1の値に0を代入して初期化。
  2. counter();を実行。
    counter関数を呼び出す。
  3. count1 += 1;を実行。
    変数count1の値をカウントアップし、1に変更。
  4. save();を実行。
    save関数を呼び出す。
  5. localStorage.setItem("count1" , document.getElementById("dayCount").innerHTML);を実行。
    <div id="dayCount"></div>内のinnerHTMLの値(この時点では空文字列となる値)を、LocalStorageにcount1キーと関連付けて保存。
  6. window.onloadに関数を設定。
  7. ページ読み込みが完了し、window.onloadに設定した関数が実行される。
  8. var count_load = localStorage.getItem("count1");を実行。
    LocalStorageにcount1キーと関連付けて保存した値(空文字列)を取り出し、変数count_loadに代入。
  9. document.getElementById("dayCount").innerHTML = count_load;を実行。
    <div id="dayCount"></div>内のinnerHTMLの値を、変数count_loadの値(空文字列)に変更。

このうち、カウントに使用されている(と思われる)変数count1は、1番目と3番目の処理、
コードで言えば、以下の箇所のみで使用されているように見えます。

var count1 = 0;
count1 += 1;

値を0に初期化した後、カウントアップして1にしている。ただそれだけです。
「この変数の値がLocalStorageに保存される」事がこのコードの要件(本来求める動作)だと考えられますが、このコードでLocalStorageに保存されているのは、id属性にdayCountが指定された要素(<div id="dayCount"></div>)内の「innerHTMLの値」だけです。
そしてこの「innerHTMLの値」の空文字列をLocalStorageに保存してから、再度取り出し、
再びinnerHTMLへと設定しなおしています。
が、この間にこの空文字列がカウントの値へ変更されてはいません。

これが、カウントアップされない原因です。そもそもカウントの値が保存されていません。
実際、以下の実際に書いてみたサンプルでもカウントアップどころか、何も表示されない状態になっています。

※空文字列は0文字の文字列データのため、何も表示されない。

LocalStorageを利用したカウントアップのサンプルコード


解決するには、変数count1の値をLocalStorageに保存するようにしましょう。

まず、変数count1を初期化するときに、0をそのまま代入するのではなく、LocalStorageから読みだした値を変数count1に代入するようにします。
ただし、LocalStorageにカウントの値が無い場合には、代わりに0を代入するようにします。
このあたりの処理は、「LocalStorageからカウントの値を読み出し、カウントの数値か0を返す」関数としてひとまとめにしてしまったほうが良いと思います。
ここでは、これらの処理をload関数にまとめることにします。

load関数で取得したカウントの値を変数count1に代入し、それから変数count1をカウントアップします。
そして、カウントアップした値をLocalStorageに保存して、innerHTMLの値も更新します。
この時、innerHTMLの値をLocalStorageに保存するような処理にしては駄目です。
LocalStorageに保存するのは、変数count1の値です。
そしてinnerHTMLは、変数count1の値を書き込むだけにしましょう。

以上の処理を、全て「window.onloadに設定する関数」の中で書きます
window.onloadに指定された関数」は非同期処理されるため、外側のコードが最後まで実行された後に呼び出されてしまいます。
このため、外側と内側とでコードの実行タイミングが異なるようになってしまいます。
これを混同するとえらく面倒になるうえに、殆どの場合は期待した動作をしてくれなくなるので、
全ての処理は「window.onloadに設定する関数」の中に書いてしまいましょう。

ただし、関数定義は除きます。
関数定義はあくまで関数を定義するだけであって、その場で動作するコードではないため、window.onloadの外に書いても問題はありません。

※関数定義を内側に書いても間違いではありません。動作します。このあたりは、見やすさや好みの差だと私は思います。この例では見やすさのため、外側に書くことにします。

以上の修正案を具体的なコードにしたものが以下になります。

window.onload = function() {
  /**
   * @type {number}
   *
   * LocalStorageから、カウントの値を読み込む。
   */
  var count1 = load();

  /* カウントアップ */
  count1 += 1;

  /* カウントアップした値を保存 */
  save(count1);

  /* カウントを表示 */
  document.getElementById("dayCount").innerHTML = count1;
};

/**
 * LocalStorageに保存しておいたカウントの値を数値で取り出す。
 *
 * LocalStorageに値が保存されていない場合、代わりに0を返す。
 * また、値が正の整数以外の場合も0を返す。
 * (LocalStorageの値は簡単に改変されてしまうため、その対策)
 *
 * @return {number} カウントを示す数値
 */
function load() {
  /**
   * @type {string|null}
   *
   * LocalStorageに保存されていた文字列値を取り出す。
   * LocalStorageに値が保存されていない場合、代わりにnullが返される。
   */
  var count_data = localStorage.getItem("count1");

  /**
   * @type {number}
   *
   * 保存されていた値を数値に変換。nullの場合は0になる。
   * また、数値に変換できない文字列値はNaN(非数)という特殊な数値になる。
   */
  var count = Number(count_data);

  /*
   * 値が適切な数値(0とNaN以外の数値であり、かつ、1以上の数値であり、かつ、整数値である)かどうか判定。
   * 条件に合致した場合は数値をそのまま返し、それ以外の場合は0を返す。
   */
  if (
    count &&                    // 0とNaN以外の数値か判定
    1 <= count &&               // 1以上の数値か判定
    Math.floor(count) === count // 整数値か判定
  ) {
    return count;
  } else {
    return 0;
  }
}

/**
 * LocalStorageにカウントの値を保存する
 *
 * @param {number} count LocalStorageに保存するカウントの値
 */
function save(count) {
  localStorage.setItem("count1", count);
}

動作サンプル:LocalStorageを利用したカウントアップのサンプルコード

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/03 08:41

    この回答を書くのに費やした時間が気になります!!

    キャンセル

  • 2016/07/03 13:11

    > 回答を書くのに費やした時間

    多分1時間未満…いや、2時間未満です

    キャンセル

  • 2016/07/03 16:44

    すごい。。時間単価5000円なら一万円の価値。

    キャンセル

0

ロードするたびに下記が実行されているので、0から計算が始まってしまっています。

var count1 = 0;

なので、「ロード時にまずローカルストレージを参照し、値が保存されていなければ0を代入する」という形に改める必要があります。
また、ローカルストレージには文字列として保存されているので、数値として計算するために型変換も行います。

function counter(count){
  count += 1;
  save(count);
};

function save(count){
    localStorage.setItem("count1" , count);
};

window.onload = function(){
    var count_load = parseInt(localStorage.getItem("count1") || 0);
    document.getElementById("dayCount").innerHTML = count_load;

    counter(count_load);
};

以上のコードでいかがでしょうか?

 補足

元々のコードではローカルストレージ上に正しい値が保存できていない可能性がありますので、
一旦下記のように値を消去してからお試しください。

localStorage.clear("count1");

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/02 20:50 編集

    parseInt関数の第二引数は、きちんと「10」に指定したほうが良いです。古いブラウザでは8進数と解釈され、予期しない動作を引き起こす可能性があります。

    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt

    > 第1引数のstringが「0」で始まるときは、第2引数のradixは8(8進法)または10(10進法)とされます。厳密には、基数がどちらになるかは実装によります。ECMAScript 5 の仕様では10(10進法)です。ただし、まだすべてのブラウザがサポートしている訳ではありません。したがって、parseInt()関数を使うとき基数は必ず与えてください。

    http://liginc.co.jp/web/js/31018

    > 何でこうなったかっていうと、parseInt()は第二引数で基数を設定できるんですよね。
    > ちゃんとここに来るのは10進数なんだよって教えてあげないと、0から始まる文字は8進数と解釈されてしまうようです。

    最も、今の時代、ES5に非対応のブラウザ(この問題を引き起こすブラウザ。例えばIE8とか)がどれほど生き残っているのか疑問ではあるのですが…
    やらないよりはやったほうが良いと考えます。

    キャンセル

-7

ちゃんとしたコードに直せばok

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/02 18:35 編集

    どこがどう「ちゃんと」していないコードなのか、その具体的な説明が必要だと考えます。

    キャンセル

  • 2016/07/03 08:05 編集

    私もそう考えます。ま、毎回、カウント値をロードの度に0にしてたら、そりゃー、上手く行かんですわ。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.97%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる