Оценка таймера обратного отсчета

Пожалуйста, оцените приведенный ниже код на предмет передовых методов, эффективности и ошибок. Я получил часть кода из школ W3 (я знаю, я знаю, но они прошли долгий путь) и ассимилировал его с тем, что мне нужно. В частности, days = hours = minutes = seconds = 0; вероятно, вызовет у людей стресс, но после исследования и оценки я обнаружил, что в этом случае он работает хорошо.

Пожалуйста, оцените мои JS код. Спасибо. CODEPEN

ВАЖНО: Приведенный ниже код проверяет наличие переменной ACF (предоставляемой через functions.php с серверной частью WordPress), на которой основан весь этот код. Я заменил переменную примером строки, которая будет возвращена этим полем.

(function () {
    let acf_vars = {timer: "2021 1 21 13 08 00"}; // this code is a replacement for the ACF variable

    if (!acf_vars.timer) {
        return document
            .querySelectorAll('.mobile-ticker')
            .forEach((container) => (container.style.display = 'none'));
    }

    const backendTimer = acf_vars.timer.split(' ');
    const y = backendTimer[0];
    const M = +backendTimer[1] - 1; // monthIndex in Date Object begins with 0, so we subtract 1
    const d = backendTimer[2];
    const h = backendTimer[3];
    const m = backendTimer[4];
    const s = backendTimer[5];

    // new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])
    const countDownDate = new Date(y, M, d, h, m, s, 0).getTime();

    const timerInterval = setInterval(() => {
        const now = new Date().getTime();
        const distance = countDownDate - now;
        const expiredTimer = distance <= 0;

        let days = Math.floor(distance / (1000 * 60 * 60 * 24));
        let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        let seconds = Math.floor((distance % (1000 * 60)) / 1000);

        if (expiredTimer) {
            days = hours = minutes = seconds = 0;
            clearInterval(timerInterval);
        }

        if (typeof window.innerWidth === 'number' && window.innerWidth < 768) {
            document.querySelector('.ticker-mobile #days').innerHTML = days;
            document.querySelector('.ticker-mobile #hours').innerHTML = hours;
            document.querySelector('.ticker-mobile #minutes').innerHTML = minutes;
            document.querySelector('.ticker-mobile #seconds').innerHTML = seconds;
        } else {
            document.querySelector('.ticker-desktop #days').innerHTML = days;
            document.querySelector('.ticker-desktop #hours').innerHTML = hours;
            document.querySelector('.ticker-desktop #minutes').innerHTML = minutes;
            document.querySelector('.ticker-desktop #seconds').innerHTML = seconds;
        }
    }, 1000);
})();

1 ответ
1

Можете ли вы вместо этого отправить метку времени? Управление датами в JS немного утомительно без библиотеки. Это, вероятно, уже довольно ясно вам, поскольку нужно объявлять все y M d h m s переменные. PHP, с другой стороны, имеет createFromFormat, который имеет гибкий и удобный API. Например, я считаю, что вы можете передать строку форматирования 'Y m d H i s' (соответствует вводу '2021 1 4 13 08 00') и немедленно получите отметку времени.

В любом случае работать с отметками времени проще, чем со строками, отформатированными пользователем. Я не знаю источник исходной строки даты, но я бы превратил ее в метку времени как можно скорее, как только ваше приложение получит ее (и, например, сохраню метку времени в базе данных вместо строки).

Когда ты делать необходимо передавать строку вместо метки времени, используйте стандартизованный Строка ISO 8601, который может быть автоматически проанализирован на большинстве языков.

Отображение тикера В настоящее время тикеры скрыты через JS, если нет таймера. Подумайте, можете ли вы выполнить эту проверку (и весь этот условный код) в PHP, вместо того, чтобы отправлять разметку HTML в любом случае, а затем, возможно, скрыть ее, если нет таймера. Например, вы можете изменить его так, чтобы сервер обслуживал только этот .js если есть таймер для начала, иначе <script> тег (и, возможно, тикеры) полностью опускаются серверной частью.

Разрушение Если вам действительно нужно проанализировать строку даты во внешнем интерфейсе, вы можете сделать ее более краткой, деструктурируя вместо того, чтобы перечислять все признаки backendTimer. Я бы также хотя бы использовал month и minutes вместо M и m (вы также можете расширить другие имена переменных для единообразия):

const [y, month, d, h, minutes, s] = acf_vars.timer.split(' ');
// The month in the input string is 1-indexed
// The month the date constructor accepts is 0-indexed, so subtract 1:
const countDownDate = new Date(y, month - 1, d, h, minutes, s).getTime();

Количество миллисекунд можно полностью опустить при передаче в конструктор Date.

Показать таймер немедленно Прямо сейчас тикеры начинают заполняться через 1000 мс после запуска этого скрипта. А пока они будут пустыми. Подумайте о том, чтобы сначала поместить обратный вызов интервала в именованную функцию и немедленно вызвать эту функцию, чтобы пользователю не пришлось ждать дополнительную секунду. Например

const updateCountdown = () => {
  const now = new Date().getTime();
  // ...
};
const timerInterval = setInterval(updateCountdown, 1000);
updateCountdown();

Повторяющиеся идентификаторы недействительны HTML В документе должно быть не более одного элемента с данным идентификатором. Если элементы определенного типа могут повторяться, используйте класс вместо идентификатора. Но даже лучше:

Можете ли вы совместить тикеры? У вас есть одна бегущая строка для мобильных устройств и отдельная для настольных компьютеров. Это странно и приводит к повторению кода. Если нет веской причины не делать этого, выясните, можно ли как-нибудь их объединить. (Я не вижу чего-либо существенного различия между двумя тикерами в приведенном коде, поэтому я не уверен, что может быть препятствием. Если это только для CSS, используйте вместо этого медиа-запросы.)

Мобильный тикер против мобильного тикера? HTML немного сбивает с толку:

<section class="mobile-ticker">
  <div class="ticker ticker-desktop">
    ...
  </div>
    <div class="ticker ticker-mobile">

Итак, есть .mobile-ticker, контейнер, а затем .ticker-desktop, ребенок, а потом есть .ticker-mobile, еще один ребенок. Может быть, назовите контейнер как-нибудь ticker-container вместо?

Только использовать .innerHTML при сознательной работе с разметкой HTML. Если то, что вы имеете или хотите, простой текст, это быстрее, безопаснее и семантически целесообразнее использовать .textContent вместо .innerHTML.

  • Это действительно хорошо, большое спасибо за подробный ответ. Я внедряю некоторые из этих изменений, как мы говорим, но элемент innerHTML / textContent, похоже, не доступен, если сначала поместить обратный вызов интервала в именованную функцию: Uncaught TypeError: Cannot set property 'innerHTML' of null. Чтобы исправить это, я нашел один вариант – заменить IIFE на jQuery(function() {}), но я не совсем понимаю, почему это может быть проблемой в первую очередь

    – Он Мы


  • Ваш сценарий выполняется до того, как элемент существует. Видеть Вот. Мое предпочтительное решение – дать <script> пометить defer атрибут.

    – CertainPerformance

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *