用户输入未来日期变量的计时器

A timer where user enters variable for future date

如果有人能为我正在进行的学校项目指明正确的方向,那就太好了。下面你会看到一个超级简单的计时器,我在一个名为 Web Dev 的 youtuber 的教程的帮助下制作的。该示例将新年前夜硬编码到脚本中。但我想更进一步,要求用户输入他们的特殊日期 - 例如,让计时器倒计时到他们的生日。

到目前为止,我已经设法使计数器从给定日期开始倒计时,而不仅仅是硬编码日期,而且我已经设法为用户生成的数据创建了输入表单。 但是一旦我试图将两者结合起来,就出了问题。我猜我需要将用户生成的数字输入到其中一个函数中,而不仅仅是将它们列在顶部作为 let、var 和 const?

哦,理想情况下,我应该想出一种方法,让输入表单在用户单击 'enter' 按钮后立即消失。

对于我之前的 Whosebug 问题,有人非常友好地为我编写了完整的答案。但由于这在很大程度上是一个学习过程,如果能提供一些正确方向的提示和指示,我会非常满意。

        let userYear = userYearEntered;
        let userMonth = userMonthEntered;
        let userDay = userDayEntered;

        const userDate = new Date(userYear, userMonth, userDay, 0, 0, 0);
        const userOccasion = 'I need to present this project';


        function enterSpecialDate() {
            var userYearEntered = document.getElementById('userYear').value;
            console.log(userYearEntered);

            var userMonthEntered = document.getElementById('userMonth').value;
            console.log(userMonthEntered);

            var userDayEntered = document.getElementById('userDay').value;
            console.log(userDayEntered);
        }

        /*create countdown timer using substraction*/
        function updateCountdowntime() {
            const currentTime = new Date();
            const diff = userDate - currentTime;
            console.log(diff);

            /* we've been given the difference in milliseconds, so some division is needed */
            const d = Math.floor(diff / 1000 / 60 / 60 / 24);
            const h = Math.floor(diff / 1000 / 60 / 60) % 24;
            const m = Math.floor(diff / 1000 / 60) % 60;
            const s = Math.floor(diff / 1000) % 60;

            /* send values back into HTML document */

            document.getElementById('days').innerHTML = d;
            document.getElementById('hours').innerHTML = h;
            document.getElementById('minutes').innerHTML = m;
            document.getElementById('seconds').innerHTML = s;

            document.getElementById('userOccasion').innerHTML = userOccasion;
        }

        setInterval(updateCountdowntime, 1000);



       * {
            box-sizing: border-box;
        }

        body {
            background-color: rgb(44, 48, 48);
            font-family: sans-serif;
            color: rgb(239, 239, 239);
            font-size: 3em;
            font-weight: 300;
            height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        div {
            margin-top: 1vh;
        }

        label {
            font-size: 0.4em;
        }

<div>
        <label for="userYear">year</label>
        <input id="userYear" type="number" value="" placeholder="e.g. 2021">

        <label for="userMonth">month</label>
        <input id="userMonth" type="number" value="" placeholder="e.g. 8">

        <label for="userDay">day</label>
        <input id="userDay" type="number" value="" placeholder="17">

        <button onclick="enterSpecialDate()">Enter</button>

    </div>

    <div>

        <p>there are</p>

        <div class="time">
            <span id="days"></span>
            <span>days</span>
        </div>

        <div class="time">
            <span id="hours"></span>
            <span>hours</span>
        </div>

        <div class="time">
            <span id="minutes"></span>
            <span>minutes</span>
        </div>

        <div class="time">
            <span id="seconds"></span>
            <span>seconds</span>
        </div>

        <p>until <span id="userOccasion"></span></p>

    </div>

您应该能够通过几个简单的提示或文本输入字段来完成此操作。

例如:

要求用户输入一个月,然后是一天,然后是一年。 您将这些输入保存为单独的变量。然后你使用 const newYearTime 但不是使用硬编码日期,而是使用变量作为日期。

现在你有 const newYearTime = new Date('january' ,1,当前年份等...)

根据提示你可以做:

let year = number(prompt: enter year)
let day = number(prompt: enter day)
let month = prompt: enter month

然后您只需将 const newYearTime 更改为

Const newYearTime = new Date(month, day, year)

我知道我的代码不正确。我不在我的电脑前,所以我没有我的编辑来写它应该的样子,但我想你明白我的意思了。

我也是 javascript 的新手,但如果我认为我知道该怎么做,我会尽力提供帮助

Fraku 的回答似乎符合您的要求。为了补充他的回答,您还想使用 LocalStorage。

因此,您可以将用户输入的特殊日期存储到 LocalStorage 中。所以你不需要每次用户进入页面时都询问用户。

以下是如何将数据存储到 LocalStorage 的示例。 dtUserDate 是用户输入的特殊日期。

window.localStorage.setItem("Some Name", JSON.stringify( { "SpecialDate" : dtUserDate } ));

您也可以仅使用一个变量和 .substring JS 方法来解析用户的日期字符串。会有点难以阅读,但如果存储是一个因素,你可以做到这一点。例如,将占位符与要求 MM/DD/YYYY 的输入一起使用,您可以使用:

userDate.substring(0, 2); = 月

userDate.substring(3, 5); = 天

userDate.substring(6, userDate.length); = 年

并获取日期:

var newYearTime = new Date(userDate.substring(6, userDate.length), (userDate.substring(0, 2) - 1), userDate.substring(3, 5));

所以我在我的编辑器中重新创建了您的代码。正如我现在看到的那样,您遇到的问题是当用户按下回车键(或单击它)时它不会更新 html。

你在测试的时候检查过你的主机吗?因为我是第一次尝试打开控制台,马上就发现了问题:

Uncaught ReferenceError: userYearEntered is not defined

有了这个你应该可以自己找到问题的答案。我会给你一点提示:第一次加载页面时,var userYearEntered 没有值。这从一开始就破坏了您的代码。想一想如何改变这一点。这个问题有多种解决方案。

此外,我看到您想在按下或单击输入后立即隐藏输入。这可以很容易地完成,只需在输入的父 div 上添加一个隐藏的 属性。只要 onclick 没有发生,它就是错误的。如果发生了 onclick,则将其更改为 true。

这是为最终用户使用 date input, which is more semantic, accessible and more comfortable to use 的解决方案。

它使用内联样式在表单和倒计时之间切换,但同样可以使用 classList.toggle() 和 class 来显示或隐藏特定视图。

你还应该实现某种形式的错误处理(例如,现在它在没有设置日期的情况下点击按钮时什么都不做,它还支持过去的日期,导致负数)。

关于 setInterval() 的注释: 这还不够 reliable/exact,可能会导致秒数被跳过或更改得太快。有关此问题的更多背景知识和可靠的解决方案,我推荐视频 "JavaScript 以艰难的方式反击 - HTTP 203 " 在 YouTube 上。该解决方案也可作为 reusable code snippet in this gist

现在您可以很容易地为场合文本实现额外的输入。

let userDate = null;
const userOccasion = 'I need to present this project';
const userDateInput = document.getElementById('user-date');
const formView = document.getElementById('form-view');
const counterView = document.getElementById('counter-view');

function enterSpecialDate() {
  userDate = userDateInput.valueAsDate;
  if (userDate) {
    // fire the function once, so we start with filled in numbers right away
    updateCountdowntime();
    // see the note on setInterval() in the answer
    setInterval(updateCountdowntime, 1000);
    // switch between the form and the counter view
    formView.style.display = 'none';
    counterView.style.display = 'block';
  }
}

/*create countdown timer using substraction*/
function updateCountdowntime() {
  const currentTime = new Date();
  const diff = userDate - currentTime;

  /* we've been given the difference in milliseconds, so some division is needed */
  const d = Math.floor(diff / 1000 / 60 / 60 / 24);
  const h = Math.floor(diff / 1000 / 60 / 60) % 24;
  const m = Math.floor(diff / 1000 / 60) % 60;
  const s = Math.floor(diff / 1000) % 60;

  /* send values back into HTML document */

  document.getElementById('days').innerHTML = d;
  document.getElementById('hours').innerHTML = h;
  document.getElementById('minutes').innerHTML = m;
  document.getElementById('seconds').innerHTML = s;

  document.getElementById('userOccasion').innerHTML = userOccasion;
}
* {
  box-sizing: border-box;
}

body {
  background-color: rgb(44, 48, 48);
  font-family: sans-serif;
  color: rgb(239, 239, 239);
  font-size: 2em;
  font-weight: 300;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

div {
  margin-top: 1vh;
}
<div id="form-view">
  <input type="date" id="user-date">
  <button onclick="enterSpecialDate()">Enter</button>
</div>

<div id="counter-view" style="display: none;">

  <p>there are</p>

  <div class="time">
    <span id="days"></span>
    <span>days</span>
  </div>

  <div class="time">
    <span id="hours"></span>
    <span>hours</span>
  </div>

  <div class="time">
    <span id="minutes"></span>
    <span>minutes</span>
  </div>

  <div class="time">
    <span id="seconds"></span>
    <span>seconds</span>
  </div>

  <p>until <span id="userOccasion"></span></p>

</div>