Задать вопрос
@campus1

Почему не рендерится календарь?

Доброй ночи господа.
Подскажите, где я туплю. При нажатии на <, должна рендерится новая таблица с предыдущим месяцем.

То есть сначала у нас отображается текущий месяц знач которого 11makeCalendar(currentMonth), при клике я вызываю makeCalendar(currentMonth - 1), но оно не меняется визуально.

Код

Спасибо за помощь.
  • Вопрос задан
  • 172 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Ошибка номер раз - html-код вы сгенерировали, но засунуть его пытаетесь куда-то не туда (туда - это view.innerHTML).

Ошибка номер два - обработчик клика после первого переключения месяца отвалится, поскольку элемент, к которому он привязан, будет удалён. Или назначайте обработчик заново при каждом переключении месяца; или делегируйте обработку клика элементу, который не будет перетираться при переключении (view, например); или перепишите построение таблицы так, чтобы кнопки не создавались заново (например, вынесите их и заголовки с днями недели в thead, и перезаписывайте только tbody вместо всей таблицы).

UPD. Ещё ряд косяков поменьше, но упомянуть стоит:

Массивы с днями недели и месяцами не нужны - можно просто форматировать дату.

Знать количество дней в месяцах тоже не нужно - всегда выводим по шесть недель, начиная с последней недели предыдущего месяца, это минимальное количество полных недель, в которые помещается любой месяц. Почему всегда - чтобы вне зависимости от месяца, размер календаря не изменялся.

Чтобы переключаться месяцами, у объекта даты есть методы - получили текущий месяц, сделали ему +/- 1, установили. Заодно и про год думать не надо при переходе от декабря к январю и наоборот - всегда будет правильным.

if (i == day && month == currentMonth) {
    calendarView += "<td class='currentday'>" + i + "</td>";

Во-первых, условие кривое - currentMonth это тот месяц, который выводится, а не реально текущий. Т.е., с таким условием currentday у вас в каждом месяце будет, где количество дней больше или равно текущему числу. Во-вторых, условие недостаточно - не учитывается год.

Исправляем, переписываем:

document.body.innerHTML = `
  <table class="calendar">
    <thead>
      <tr>
        <th data-step="-1">&lt;</th>
        <th class="month" colspan="5"></th>
        <th data-step="+1">&gt;</th>
      </tr>
      <tr class="weekdays">${Array.from({ length: 7 }, (_, i) => `
        <th>${
          new Date(2001, 0, i).toLocaleString('en', { weekday: 'short' })}
        </th>`).join('')}
      </tr>
    </thead>
    <tbody></tbody>
  </table>
`;

const calendar = document.querySelector('table');
const month = calendar.querySelector('.month');
const tbody = calendar.tBodies[0];
const date = new Date;

calendar.querySelectorAll('[data-step]').forEach(n => {
  n.addEventListener('click', showNextMonth);
});

function showNextMonth({ target: { dataset: { step } } }) {
  date.setMonth(date.getMonth() + +step);
  renderCalendar();
}

function renderCalendar() {
  tbody.innerHTML = '';
  month.innerText = date.toLocaleString('en', {
    year: 'numeric',
    month: 'long',
  });

  const m = date.getMonth();
  const d = new Date(date.getFullYear(), m);
  const today = new Date().setHours(0, 0, 0, 0);

  do {
    d.setDate(d.getDate() - 1);
  } while (d.getDay() !== 0);

  for (let i = 0; i < 6; i++) {
    const tr = tbody.insertRow();

    for (let j = 0; j < 7; j++, d.setDate(d.getDate() + 1)) {
      const td = tr.insertCell();
      td.innerHTML = d.getDate();
      td.classList.toggle('today', +d === today);
      td.classList.toggle('current-month', m === d.getMonth());
    }
  }
}

renderCalendar();
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы