Skip to content

❓ 问题

H5 提供的日期选择器用法,以及如何辨析 getTime()new Date()

🤖 回复

代码实现:HTML5 日期输入框

html
    <input 
        type="date" 
        id="countdown-date" 
        class="countdown-input countdown-date"
    >

代码实现:数据存储结构

js
    const date = dateInput.value;
    const newCountdown = {
        id: Date.now(),
        name: name,
        date: date  // 存储格式:'2024-12-31'
    };

代码实现:Date 对象与时间戳的操作

javascript
// 创建当前时间的 Date 对象
const now = new Date();
console.log(now);  // Wed Dec 25 2024 10:30:00 GMT+0800

// 获取时间戳(毫秒)
console.log(now.getTime());  // 1703473800000

// 从字符串创建 Date 对象
const christmas = new Date('2024-12-25');
console.log(christmas);  // Wed Dec 25 2024 00:00:00 GMT+0800

要点:type="date" 输入框提示

💡 新手提示:type="date" 输入框

<input type="date"> 是 HTML5 提供的日期选择器,用户可以点击选择日期,浏览器会自动显示日历界面。

它的值格式是 YYYY-MM-DD,例如 2024-12-31


❓ 问题

view 切换逻辑的具体实现方式是什么?(注意使用 id 而非 section)

🤖 回复

代码实现:视图导航切换逻辑

js
function initNavigation() {
    // 获取要显示的视图名称(从 data-view 属性读取)
    const targetView = this.getAttribute('data-view');
        
    ...           
    // 隐藏所有视图
    views.forEach(function(view) {
        view.classList.remove('active');
    });
    
    // 显示目标视图
    const targetViewElement = document.getElementById(targetView + '-view');//妙在这里
    if (targetViewElement) {
        targetViewElement.classList.add('active');
    }
}

❓ 问题

如何验证日期的有效性?isNaN(targetDate.getTime()) 的原理是什么?

🤖 回复

代码实现:日期有效性验证

js
    // 验证日期是否有效
    const targetDate = new Date(date);
    if (isNaN(targetDate.getTime())) {
        alert('请输入有效的日期!');
        return;
    }

步骤:验证逻辑的标准拆解

这几行代码是 JavaScript 中处理 “日期验证” 的标准写法,虽然看着奇怪,但逻辑非常严密。我们可以分三步来破解这个“谜团”:

  1. new Date(date) —— “尝试解析”

    • 动作date 是你从输入框拿到的字符串(比如 "2025-01-01")。
    • 逻辑:JS 尝试把这个字符串转换成一个真正的“日期对象”。
    • 风险:如果用户乱输入(比如 "2025-13-45" 或者字母),JS 虽然不会直接报错崩溃,但它会生成一个特殊的、残废的对象,叫做 Invalid Date(非法日期)。
  2. targetDate.getTime() —— “换算成毫秒”

    • 作用:如果是正常日期,它会返回从 1970 年到现在经过 the 毫秒数(一长串数字)。
    • 重点:如果这个日期是上一步说的那个“残废”的 Invalid Date,那么 getTime() 就会返回一个特殊的值:NaN(Not a Number,不是一个数字)。
  3. isNaN(...) —— “终极终审”

    • 作用:专门用来检查一个值是不是 NaN
    • 逻辑
      • 如果 getTime() 拿到了数字 -> isNaN 返回 false -> 验证通过 ✅
      • 如果 getTime() 拿到了 NaN -> isNaN 返回 true -> 进入 if 块报错 ❌

知识点:为什么不直接写 if (targetDate === 'Invalid Date')

这是 JS 的一个大坑:Invalid Date 也是一个对象。如果你直接打印 targetDate,它可能显示 "Invalid Date"。但如果你用 typeof 去看,它依然会告诉你它是个 "object"。只有通过 getTime() 把它逼到“算数”这一步,它才会露出马脚(变成 NaN)。

形象比喻:Date 对象与“熔铸金条”

是的,完全正确!在 JavaScript 里,Date 对象就像是一个复杂的“多功能机械表”,里面存着年、月、日、时、分、秒、时区等各种信息。而 getTime() 就相当于把这块表直接熔掉,铸成了一块“金条”——也就是一串长长的数字。

要点:时间戳的定义

  1. 这个数字到底代表什么? 它代表从 1970 年 1 月 1 日 00:00:00(计算机世界的“元年”)到现在,一共过去了多少 毫秒。比如现在的时间戳可能是:1704067200000。

要点:将日期转换为数字的核心原因

  • 原因 A:方便计算(减法) 你想算“今天”距离“新年”还有多久。 用对象算:新年对象 - 今天对象 = 报错(对象不能直接相减)。 用数字算:新年毫秒数 - 今天毫秒数 = 剩下的毫秒数。拿到剩下的毫秒数,你再除以 1000(秒),除以 60(分)... 就能算出天数了。
  • 原因 B:方便判断(非法日期) 正常日期:能熔成一根实心的金条(一个大数字)。 非法日期 (Invalid Date):因为它是虚假的,它熔不出任何东西,只会剩下一滩空气(也就是 NaN)。所以我们检查这个结果是不是 NaN,就能断定这块“表”是不是假的。

❓ 问题

倒数日如何准确计算?setHours(0, 0, 0, 0) 的必要性是什么?

🤖 回复

代码实现:倒数日天数计算

js
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    // 解析目标日期
    const targetDate = new Date(dateString);
    targetDate.setHours(0, 0, 0, 0);
    
    // 计算时间差(毫秒)
    const timeDiff = targetDate.getTime() - today.getTime();
    
    // 转换为天数
    // 1天 = 24小时 × 60分钟 × 60秒 × 1000毫秒 = 86400000毫秒
    const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));

要点:应对日期计算中的“精度陷阱”

这行 setHours(0, 0, 0, 0) 解决的是日期计算中一个非常阴险的“精度陷阱”。如果不加这一行,你的倒数日计算可能会出现 “少算一天” 或者 “时间对不上” 的奇怪 Bug。

步骤:原理与后果拆解

  1. 为什么要这么做? 默认情况下,执行 const today = new Date() 拿到的是当前的精确时间(包含时、分、秒、毫秒)。比如现在是:2024-12-25 15:30:45。但你输入的“目标日期”(比如圣诞节 2024-12-25),JS 默认解析出来的时间是那天的凌晨零点:即:2024-12-25 00:00:00。
  2. 如果不设置 0 的后果: 假设现在是 12 月 25 日下午 3 点,你想算距离 12 月 26 日还有几天:今天:12-25 15:00,明天:12-26 00:00。计算差值:00:00 减去 15:00 = 只有 9 个小时。结果:因为不足 24 小时,程序可能会告诉你距离明天还有 0 天!这显然不符合我们的直觉(明明还有 1 天才到明天)。
  3. setHours(0, 0, 0, 0) 的作用 这行代码相当于给时间做了一个 “归零手术”。它把今天的 时、分、秒、毫秒 全部强行改成了 0。手术后:今天的日期变成了 2024-12-25 00:00:00。这样一来,我们就是在用 “今天的凌晨” 对比 “目标日期的凌晨”。差值正好是整整的 24 小时(也就是 1 天)。计算出来的天数就会非常精准,不会因为你是早上 8 点还是下午 5 点打开网页而产生偏差。

❓ 问题

CSS 中的 line-height 是什么?为什么大数字显示要用 line-height: 1

🤖 回复

代码实现:数字文本样式

css
.countdown-number {
  font-size: 42px;
  font-weight: 700;
  color: #5dade2;
  line-height: 1;
}

[1 tool called]

要点:什么是 line-height

line-height: 1; 是控制行高的 CSS 属性。详细解释:line-height 控制文本行的高度,也就是一行文字占据的垂直空间。

知识点:line-height 的各种取值方式

css
line-height: 1;      /* 1倍字体大小(无单位) */
line-height: 1.5;    /* 1.5倍字体大小 */
line-height: 20px;   /* 固定20像素 */
line-height: normal; /* 浏览器默认值,通常是1.2左右 */

步骤:代码中的实际换算

css
.countdown-number {
  font-size: 42px;      /* 字体大小42px */
  font-weight: 700;
  color: #5dade2;
  line-height: 1;       /* 行高 = 1 × 42px = 42px */
}

要点:视觉效果的直观对比

  • 不设置 line-height(默认 normal ≈ 1.2
    ┌─────────────┐
    │             │  ← 上方有额外空隙
    │     30      │  ← 数字
    │             │  ← 下方有额外空隙
    └─────────────┘
  • 设置 line-height: 1
    ┌─────────────┐
    │     30      │  ← 数字紧凑,上下空隙很小
    └─────────────┘

要点:为什么在这里选择 line-height: 1

因为这是一个大数字显示(42px),我们希望:

  1. 紧凑显示:数字上下不要有多余空白
  2. 精确控制间距:下面的"天后"标签用 margin-top: 4px 来精确控制间距
  3. 视觉对齐:大数字和周围元素更容易对齐

形象比喻:倒数日卡片的整体布局

倒数日卡片:
┌─────────────────────┐
│ 新年快乐            │
│ 目标日期:2025年1月1日│
│                     │
│        30           │  ← 这个数字用了 line-height: 1
│       天后          │  ← margin-top: 4px 控制与数字的距离
│                     │
└─────────────────────┘

步骤:对比实验与建议

  • 可以不写吗?可以不写,但效果会不同:
    css
    /* 不写 line-height: 1 */
    .countdown-number {
      font-size: 42px;
      /* line-height 默认为 normal,约 1.2 */
    }
    /* 结果:数字上下会有更多空白,看起来比较松散 */
    css
    /* 写了 line-height: 1 */
    .countdown-number {
      font-size: 42px;
      line-height: 1;
    }
    /* 结果:数字紧凑,看起来更精致 */

总结:保留该属性的最佳实践理由

保留它,因为:

  • ✅ 大数字显示时,line-height: 1 让布局更紧凑美观
  • ✅ 更容易控制元素间距
  • ✅ 这是做数字显示的常见最佳实践

如果去掉,你会发现数字和下方的"天后"之间的空隙变大了,不那么好看。


❓ 问题

什么是 escapeHtml 函数?它是如何防范 XSS 攻击的?

🤖 回复

代码实现:HTML 转义实用工具

js
/**
 * HTML 转义,防止 XSS 攻击
 * @param {string} text - 要转义的文本
 * @returns {string} 转义后的安全文本
 */
function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

要点:escapeHtml 的核心定义

防止 XSS(跨站脚本攻击),确保用户输入的内容只被当作纯文本显示,而不会被当作 HTML 代码执行。

步骤:执行原理解析

javascript
function escapeHtml(text) {
    const div = document.createElement('div');  // 1. 创建一个临时的 div 元素
    div.textContent = text;                     // 2. 把文本赋值给 textContent(浏览器自动转义)
    return div.innerHTML;                       // 3. 读取 innerHTML,得到转义后的字符串
}

知识点:对比 textContentinnerHTML

  • textContent:把内容当作纯文本处理,浏览器会自动转义特殊字符
  • innerHTML:把内容当作 HTML 代码处理,会解析标签

步骤:处理流程逐步演示

javascript
const div = document.createElement('div');

// 步骤1:用户输入了危险内容
const userInput = '<script>alert("hack")</script>';

// 步骤2:赋值给 textContent(浏览器自动转义)
div.textContent = userInput;
// 内部效果:浏览器把 < 转成 &lt;,> 转成 &gt;

// 步骤3:读取 innerHTML,获得转义后的字符串
console.log(div.innerHTML);
// 输出:&lt;script&gt;alert("hack")&lt;/script&gt;

要点:💥 实际攻击场景效果对比

假设用户在"事件名称"中输入:

javascript
'<img src=x onerror=alert("XSS攻击")>'
  • ❌ 不使用 escapeHtml(危险)

    javascript
    const name = '<img src=x onerror=alert("XSS攻击")>';
    html += `<div class="countdown-name">${name}</div>`;
    
    // 渲染结果:
    <div class="countdown-name">
      <img src=x onerror=alert("XSS攻击")> 这个标签会被执行!
    </div>
    
    // 后果:弹出警告框,或者更严重的恶意操作
  • ✅ 使用 escapeHtml(安全)

    javascript
    const name = '<img src=x onerror=alert("XSS攻击")>';
    html += `<div class="countdown-name">${escapeHtml(name)}</div>`;
    
    // 渲染结果:
    <div class="countdown-name">
      &lt;img src=x onerror=alert("XSS攻击")&gt;  ← 只是文字,不会执行
    </div>
    
    // 页面显示:<img src=x onerror=alert("XSS攻击")>(纯文本)

知识点:🎯 核心转义字符对照表

原字符转义后说明
<&lt;小于号
>&gt;大于号
&&amp;&符号
"&quot;双引号
'&#39;单引号

要点:📊 多场景实际使用示例

javascript
// 场景1:正常输入
escapeHtml('生日快乐');
// 返回:'生日快乐'(没有特殊字符,原样返回)

// 场景2:包含 HTML 标签
escapeHtml('<b>重要</b>');
// 返回:'&lt;b&gt;重要&lt;/b&gt;'
// 页面显示:<b>重要</b>(文字,不会加粗)

// 场景3:包含脚本
escapeHtml('<script>alert(1)</script>');
// 返回:'&lt;script&gt;alert(1)&lt;/script&gt;'
// 页面显示:<script>alert(1)</script>(文字,不会执行)

// 场景4:包含引号
escapeHtml('他说"你好"');
// 返回:'他说&quot;你好&quot;'
// 页面显示:他说"你好"

知识点:🤔 为什么不推荐正则替换?

你可能想:为什么不这样写?

javascript
// ❌ 不推荐的方式
function escapeHtml(text) {
    return text
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
}

问题

  1. 容易遗漏某些特殊字符
  2. 替换顺序很重要(& 必须先替换)
  3. 需要手动维护所有转义规则

浏览器原生方法的优势

  • ✅ 浏览器已经处理了所有边界情况
  • ✅ 性能更好
  • ✅ 更可靠

总结:🎓 技术要点汇总

方面说明
作用把用户输入转换成安全的 HTML 实体,防止 XSS 攻击
原理利用 textContent 自动转义 + innerHTML 读取结果
效果<script>&lt;script&gt;,只显示不执行
使用场景任何用户输入需要插入到 HTML 中的地方
重要性⭐⭐⭐⭐⭐ 生产环境必须使用