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

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

ただいまの
回答率

87.36%

javascriptで表示するカレンダーでのDOM clickイベントの問題

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,077

score 11

前提・実現したいこと

https://qiita.com/kan_dai/items/b1850750b883f83b9bee
を参考に、JSでカレンダー機能を実装しています。

ボタンで変更できるところまで行ったのですが、日付をクリックするところを
独自の方法で、DOMでコンソール表示するところでうまくいきません。
DOMのせレクターで,querySelector('td')として、
特定の日付をとりだそうとしているのですが、できません。
なおここを('tr')とすると、一行目の曜日(日から土)はくりっくできるようになります。
querySelectorで引数にtdを指定すれば、日付にアクションを設定できる気がするのですが、
なぜでしょうか?

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

js

'use strict';
{

  //曜日
  const weeks = ['日', '月', '火', '水', '木', '金', '土'];

  //現在日付
  const date = new Date();

  //現在西暦
  let year = date.getFullYear();

  //現在月
  let month = date.getMonth() + 1;

  //表示月数
  const config = {
    show: 3,
  };


//関数 カレンダー表示
  function showCalender(year, month) {
    for (let i = 0; i < config.show; i++) {
      const calenderHtml = createCalender(year, month);
      const sec = document.createElement('section');
      sec.innerHTML = calenderHtml;
      document.querySelector('#calender').appendChild(sec);
      month++;
      if (month > 12) {
        year++;
        month = 1;
      }
    }
  }


//関数 カレンダー作成
  function createCalender(year, month) {
    //つき最初の日の情報
    const startDate = new Date(year, month - 1, 1);
    //付き最後の日の情報
    const endDate = new Date(year, month, 0);
    //月の末日
    const endDayCount = endDate.getDate();
    //前月最後の日の情報
    const lastMonthEndDate = new Date(year, month - 1, 0);
    //前月末日
    const lastMonthendDayCount = lastMonthEndDate.getDate();
    //月の最初の日の曜日を取得
    const startDay = startDate.getDay();
    //日にちのカウント変数宣言
    let dayCount = 1;
    //html変数宣言
    let calenderHtml = '';
    calenderHtml += '<h1>' + year + '/' + month + '</h1>';
    calenderHtml += '<table>';
    //曜日を並べる
    for (let i = 0; i < weeks.length; i++) {
      calenderHtml += '<td>' + weeks[i] + '</td>';
    }
    //日付を並べる
    for (let w = 0; w < 6; w++) {
      calenderHtml += '<tr>';
      for (let d = 0; d < 7; d++) {
        if (w == 0 && d < startDay) {
          let num = lastMonthendDayCount - startDay + d + 1;
          calenderHtml += '<td class="is-disabled">' + num + '</td>';
        } else if (dayCount > endDayCount) {
          let num = dayCount - endDayCount;
          calenderHtml += '<td class="is-disabled">' + num + '</td>';
          dayCount++;
        } else {
          calenderHtml += '<td>' + dayCount + '</td>';
          dayCount++;
        }
      }
      calenderHtml += '</tr>';

    }
    calenderHtml += '</table>';

    return calenderHtml;

  }

  function moveCalender(e) {
    document.querySelector('#calender').innerHTML = '';

    if (e.target.id === 'prev') {
      month--;
      if (month < 1) {
        year--;
        month = 12;
      }
    }

    if (e.target.id === 'next') {
      month++;
      if (month > 12) {
        year++;
        month = 1;
      }
    }
    showCalender(year, month);
  }

  document.querySelector('#prev').addEventListener('click', moveCalender);
  document.querySelector('#next').addEventListener('click', moveCalender);

  showCalender(year, month);


 const dayClick = document.querySelector('td');

 dayClick.addEventListener('click', function() {
   console.log('クリックされました');
 }, false);

  }
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>calender_test</title>
    <link rel="stylesheet" href="css/styles.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>

<button type="button" name="button" id="prev">前月</button>
<button type="button" name="button" id="next">次月</button>
<div id="calender">

</div>

<div class="timerange">
<table>
  <tr>
    <th></th><th>予約枠</th>
  </tr>
  <tr>
    <td>9:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>10:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>11:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>13:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>14:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>15:00</td><td>5/5</td>
  </tr>
  <tr>
    <td>16:00</td><td>5/5</td>
  </tr>
</table>
</div>

<script src="js/script*.js">

</script>
  </body>
</html>

試したこと

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

querySelectorはセレクタに一致する、文書内の最初の Element を返します。
なので、一つ目の「日」をクリックすると反応しています。

【Document.querySelector() - Web API | MDN】
https://developer.mozilla.org/ja/docs/Web/API/Document/querySelector

Document の querySelector() メソッドは、指定されたセレクターまたはセレクターのグループに一致する、文書内の最初の Element を返します。


どのように処理したいのかがわからないのでざっくり書くと2通りの方法があります。

  1. 各日付にイベントをつけて回る(各日付をうまくセレクトしてaddEventListenerでイベントを付ける)
  2. tableにイベントを付けてイベント発生元を捕まえる

後者のほうが難しいですが、イベントがどのように処理されるかを理解しておくとよいと思います。

【DOMイベントのキャプチャ/バブリングを整理する 〜 JSおくのほそ道 #017 - Qiita】
https://qiita.com/hosomichi/items/49500fea5fdf43f59c58

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/08/20 11:20

    >kei344
    ご回答ありがとうございます。
    tdの最初の要素なのですね。

    qiitaの記事のように日付のみにイベントを設定したいのですが、記事の
    内容の理解が足りません。function(e) のeとは、イベントのオブジェクトのことを指しているのでしょうか?また、calender_tdとは何を意味するのか?(このようなタグがあるのか?)

    精進します。

    キャンセル

  • 2019/08/20 11:31

    「function(e) のeとは」文脈によりますが、提示されているコードで使われている物はイベントオブジェクトでよいです。
    「calender_td」はコード中でtd要素に付与しているクラス名です。

    キャンセル

0

解決しました。
for文で日付を入れる箇所で,class属性をつけ、data-setを付与しているのに気づきました。これをDOMで操作しているのですね、理解できました。

以下の内容ですね。
https://into-the-program.com/js/dataset.php

(省略)
'use strict';
{

  //曜日
  const weeks = ['日', '月', '火', '水', '木', '金', '土'];

  //現在日付
  const date = new Date();

  //現在西暦
  let year = date.getFullYear();

  //現在月
  let month = date.getMonth() + 1;

  //表示月数
  const config = {
    show: 3,
  };


//関数 カレンダー表示
  function showCalender(year, month) {
    for (let i = 0; i < config.show; i++) {
      const calenderHtml = createCalender(year, month);
      const sec = document.createElement('section');
      sec.innerHTML = calenderHtml;
      document.querySelector('#calender').appendChild(sec);
      month++;
      if (month > 12) {
        year++;
        month = 1;
      }
    }
  }


//関数 カレンダー作成
  function createCalender(year, month) {
    //つき最初の日の情報
    const startDate = new Date(year, month - 1, 1);
    //付き最後の日の情報
    const endDate = new Date(year, month, 0);
    //月の末日
    const endDayCount = endDate.getDate();
    //前月最後の日の情報
    const lastMonthEndDate = new Date(year, month - 1, 0);
    //前月末日
    const lastMonthendDayCount = lastMonthEndDate.getDate();
    //月の最初の日の曜日を取得
    const startDay = startDate.getDay();
    //日にちのカウント変数宣言
    let dayCount = 1;
    //html変数宣言
    let calenderHtml = '';
    calenderHtml += '<h1>' + year + '/' + month + '</h1>';
    calenderHtml += '<table>';
    //曜日を並べる
    for (let i = 0; i < weeks.length; i++) {
      calenderHtml += '<td>' + weeks[i] + '</td>';
    }
    //日付を並べる
    for (let w = 0; w < 6; w++) {
      calenderHtml += '<tr>';
      for (let d = 0; d < 7; d++) {
        if (w == 0 && d < startDay) {
          let num = lastMonthendDayCount - startDay + d + 1;
          calenderHtml += '<td class="is-disabled">' + num + '</td>';
        } else if (dayCount > endDayCount) {
          let num = dayCount - endDayCount;
          calenderHtml += '<td class="is-disabled">' + num + '</td>';
          dayCount++;
        } else {
          calenderHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
          dayCount++;
        }
      }
      calenderHtml += '</tr>';

    }
    calenderHtml += '</table>';

    return calenderHtml;

  }

  function moveCalender(e) {
    document.querySelector('#calender').innerHTML = '';

    if (e.target.id === 'prev') {
      month--;
      if (month < 1) {
        year--;
        month = 12;
      }
    }

    if (e.target.id === 'next') {
      month++;
      if (month > 12) {
        year++;
        month = 1;
      }
    }
    showCalender(year, month);
  }

  document.querySelector('#prev').addEventListener('click', moveCalender);
  document.querySelector('#next').addEventListener('click', moveCalender);

  document.addEventListener("click", function(e) {
    if(e.target.classList.contains("calendar_td")) {
        alert('クリックした日付は' + e.target.dataset.date + 'です');
    }
  });

  showCalender(year, month);

  }

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

同じタグがついた質問を見る