Задать вопрос
@Gloriane
Люблю стратегии и карточные игры

Как сделать Date picker кастомный html/qjuery?

<div th:fragment="date-input" class="datepicker-container">
    <input type="text" class="date-input" placeholder="Select date" />

    <div class="datepicker">
      <div class="datepicker-header">
        <i class="prev ki-outline ki-left"></i>
        <div>
          <span class="month-input">January</span>
          <span class="year">2024</span>
        </div>
        <i class="next ki-outline ki-right"></i>
      </div>

      <div class="days">
        <span>Sun</span>
        <span>Mon</span>
        <span>Tue</span>
        <span>Wed</span>
        <span>Thu</span>
        <span>Fri</span>
        <span>Sat</span>
      </div>

      <div class="dates"></div>

      <div class="datepicker-footer">
        <button class="cancel">Cancel</button>
        <button class="apply">Apply</button>
      </div>
    </div>
</div>


SCSS:
.datepicker-container {
  position: relative;

  .date-input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
  }

  .datepicker {
    position: absolute;
    background-color: #fff;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    padding: 20px;
    z-index: 999;
    display: none;

    .datepicker-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 10px;

      .month-input {
        font-size: 18px;
        font-weight: bold;
        cursor: pointer;
      }

      .prev, .next {
        background: none;
        border: none;
        font-size: 18px;
        cursor: pointer;
        padding: 5px;
      }
    }

    .days {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      grid-gap: 10px;
      font-weight: bold;
      margin-bottom: 10px;

      span {
        text-align: center;
      }
    }

    .dates {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      grid-gap: 10px;

      button {
        background-color: transparent;
        border: none;
        font-size: 16px;
        padding: 8px;
        cursor: pointer;

        &.today {
          color: red;
          font-weight: bold;
        }

        &.selected {
          background-color: #007bff;
          color: white;
          border-radius: 50%;
        }

        &:disabled {
          color: #ccc;
          cursor: not-allowed;
        }

        &:hover:not(:disabled) {
          background-color: #f0f0f0;
        }
      }
    }

    .datepicker-footer {
      display: flex;
      justify-content: space-between;
      margin-top: 15px;

      button {
        padding: 5px 10px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;

        &:hover {
          background-color: #0056b3;
        }
      }
    }

    .month-selection {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-gap: 10px;
      padding: 10px;
      background-color: #fff;
      border: 1px solid #ccc;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
      border-radius: 8px;
      z-index: 9999;

      button {
        background: none;
        border: 1px solid #007bff;
        padding: 8px;
        cursor: pointer;

        &.selected {
          background-color: #007bff;
          color: white;
        }

        &:hover {
          background-color: #f0f0f0;
        }
      }
    }
  }
}

.today {
  background-color: gray;
  color: white;
  border-radius: 50%;
}

.selected {
  background-color: green;
  color: white;
  border-radius: 50%;
}

.current-month {
  background-color: gray;
  color: white;
  border-radius: 50%;
}

.selected-month {
  background-color: green;
  color: white;
  border-radius: 50%;
}


JQUERY JS:

$(document).ready(function () {
    const datepicker = $(".datepicker");
    const dateInput = $(".date-input");
    const monthInput = $(".month-input");
    const yearInput = $(".year");
    const cancelBtn = $(".cancel");
    const applyBtn = $(".apply");
    const nextBtn = $(".next");
    const prevBtn = $(".prev");
    const dates = $(".dates");

    let activeInput = null;
    let selectedDate = new Date();
    let year = selectedDate.getFullYear();
    let month = selectedDate.getMonth();
    let isMonthPickerOpen = false;

    dateInput.on("click", function () {
        activeInput = $(this);
        const rect = activeInput[0].getBoundingClientRect();
        datepicker.css({
            top: `${rect.bottom + window.scrollY + 10}px`,
            left: `${rect.left + window.scrollX}px`,
        });

        selectedDate = new Date(activeInput.data("date") || new Date());
        year = selectedDate.getFullYear();
        month = selectedDate.getMonth();
        displayDates();
        datepicker.show();
    });

    cancelBtn.on("click", function () {
        datepicker.hide();
    });

    applyBtn.on("click", function () {
        if (activeInput) {
            activeInput.val(selectedDate.toLocaleDateString("cs-CZ", {
                year: "numeric",
                month: "2-digit",
                day: "2-digit",
            }));
            activeInput.data("date", selectedDate);
        }
        datepicker.hide();
    });

    nextBtn.on("click", function () {
        if (month === 11) {
            year++;
        }
        month = (month + 1) % 12;
        displayDates();
    });

    prevBtn.on("click", function () {
        if (month === 0) {
            year--;
        }
        month = (month - 1 + 12) % 12;
        displayDates();
    });

    monthInput.on("click", function () {
        isMonthPickerOpen = !isMonthPickerOpen;
        if (isMonthPickerOpen) {
            displayMonthPicker();
        } else {
            displayDates();
        }
    });

    const updateMonthYear = () => {
        monthInput.text(new Date(year, month).toLocaleString('default', { month: 'long' }));
        yearInput.text(year);
    };

    const handleMonthPick = function () {
        month = $(this).data("month");
        isMonthPickerOpen = false;
        displayDates();
    };

    const createMonthButton = (monthName, monthIndex) => {
        const button = $("<button>").text(monthName).data("month", monthIndex).on("click", handleMonthPick);
        return button;
    };

    const displayMonthPicker = () => {
        dates.empty();
        const months = [
            "Leden", "únor", "Březen", "Duben", "Květen", "Červen",
            "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"
        ];

        months.forEach((monthName, index) => {
            const button = createMonthButton(monthName, index);
            if (index === new Date().getMonth()) {
                button.addClass("current-month");
            }
            if (index === month) {
                button.addClass("selected-month");
            }
            dates.append(button);
        });
    };

    const createButton = (text, isDisabled = false, type = 0) => {
        const currentDate = new Date();
        let comparisonDate = new Date(year, month + type, text);
        const isToday = currentDate.getDate() === text && currentDate.getFullYear() === year && currentDate.getMonth() === month;
        const selected = selectedDate.getTime() === comparisonDate.getTime();
        const button = $("<button>").text(text).prop("disabled", isDisabled)
            .addClass(isToday && !isDisabled ? "today" : "")
            .addClass(selected ? "selected" : "");

        return button;
    };

    const displayDates = () => {
        updateMonthYear();
        dates.empty();

        if (isMonthPickerOpen) {
            displayMonthPicker();
            return;
        }

        const lastOfPrevMonth = new Date(year, month, 0);
        for (let i = 0; i <= lastOfPrevMonth.getDay(); i++) {
            const text = lastOfPrevMonth.getDate() - lastOfPrevMonth.getDay() + i;
            const button = createButton(text, true, -1);
            dates.append(button);
        }

        const lastOfMonth = new Date(year, month + 1, 0);
        for (let i = 1; i <= lastOfMonth.getDate(); i++) {
            const button = createButton(i, false);
            button.on("click", function () {
                const button = $(this);
                dates.find(".selected").removeClass("selected");
                button.addClass("selected");
                selectedDate = new Date(year, month, parseInt(button.text()));
            });
            dates.append(button);
        }

        const firstOfNextMonth = new Date(year, month + 1, 1);
        for (let i = firstOfNextMonth.getDay(); i < 7; i++) {
            const text = firstOfNextMonth.getDate() - firstOfNextMonth.getDay() + i;
            const button = createButton(text, true, 1);
            dates.append(button);
        }
    };

    displayDates();
});


У меня не совсем получаеться сделать. В низу изображения как я представляю функционал. Когда я кликаю на input показивается date picker, серым цветом показывается текущый день/месяц, зеленым показывается выбраный день/месяц. Когда открыт выбор месяца то кнопки prev/next меняют год, когда открыт выбор даты то кнопки prev/next меняют месяц. Буду признателен за помощь.

674ca1bc9449b037725158.png
  • Вопрос задан
  • 188 просмотров
Подписаться 2 Простой 1 комментарий
Пригласить эксперта
Ответы на вопрос 1
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
Зачем писать с нуля? Возьмите готовый и поправьте ему стили.
Функционально такие есть.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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