实时截止日期倒计时功能实现求助:需结合DOM与LocalStorage
解决方案:实时截止倒计时 + DOM操作 + LocalStorage存储
现有代码的核心问题
- 自定义元素
DeadLine的update方法仅返回时间差数组,未更新DOM显示 - 点击事件中获取用户输入的逻辑顺序错误(先清空输入框再取值,导致
newTitle为空) - 时间计算方式有误(使用
Date对象的getDate()会受时区影响,无法正确计算总天数) - 未实现LocalStorage数据持久化逻辑
- 重复添加同一元素实例到DOM,导致渲染异常
完整修正代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>截止倒计时</title> </head> <body> <div> <input type="text" id="titleElem" placeholder="输入任务名称"> <input type="datetime-local" id="timeElem"> <button id="btn">添加倒计时</button> </div> <div id="deadlineElem"></div> <script> // 自定义倒计时元素 class DeadLine extends HTMLElement { constructor() { super(); // 创建shadow DOM隔离样式 this.attachShadow({ mode: 'open' }); } connectedCallback() { this.title = this.getAttribute('title') || '未命名任务'; this.deadline = this.getAttribute('deadline'); // 初始化渲染 this.render(); // 每秒更新一次 this.intervalId = setInterval(() => this.update(), 1000); } // 计算剩余时间 calculateRemainingTime() { const now = new Date().getTime(); const deadlineTime = new Date(this.deadline).getTime(); const diff = deadlineTime - now; if (diff <= 0) { return { expired: true }; } // 转换为天、时、分、秒 const days = Math.floor(diff / (1000 * 60 * 60 * 24)); const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); return { days, hours, minutes, seconds, expired: false }; } // 更新DOM显示 update() { const timeData = this.calculateRemainingTime(); this.render(timeData); } // 渲染元素内容 render(timeData = null) { let timeHtml = ''; if (timeData) { if (timeData.expired) { timeHtml = '<p style="color: red;">已过期</p>'; } else { timeHtml = `<p>剩余:${timeData.days}天 ${timeData.hours}时 ${timeData.minutes}分 ${timeData.seconds}秒</p>`; } } this.shadowRoot.innerHTML = ` <div style="border: 1px solid #ccc; padding: 10px; margin: 10px 0;"> <h3>${this.title}</h3> ${timeHtml} <button onclick="this.parentElement.parentElement.remove()">删除</button> </div> `; } disconnectedCallback() { // 清除定时器,避免内存泄漏 clearInterval(this.intervalId); } } customElements.define('my-deadline', DeadLine); // DOM元素引用 const titleElem = document.getElementById('titleElem'); const timeElem = document.getElementById('timeElem'); const btn = document.getElementById('btn'); const deadlineElem = document.getElementById('deadlineElem'); // 从LocalStorage加载已保存的倒计时项 function loadDeadlines() { const savedDeadlines = JSON.parse(localStorage.getItem('deadlines')) || []; savedDeadlines.forEach(item => { addDeadlineElement(item.title, item.deadline); }); } // 添加单个倒计时元素到DOM function addDeadlineElement(title, deadline) { const deadlineItem = document.createElement('my-deadline'); deadlineItem.setAttribute('title', title); deadlineItem.setAttribute('deadline', deadline); deadlineElem.appendChild(deadlineItem); } // 保存倒计时项到LocalStorage function saveDeadline(title, deadline) { const savedDeadlines = JSON.parse(localStorage.getItem('deadlines')) || []; savedDeadlines.push({ title, deadline }); localStorage.setItem('deadlines', JSON.stringify(savedDeadlines)); } // 监听删除事件,同步更新LocalStorage deadlineElem.addEventListener('click', (e) => { if (e.target.tagName === 'BUTTON') { const deadlineElement = e.target.closest('my-deadline'); const title = deadlineElement.getAttribute('title'); const deadline = deadlineElement.getAttribute('deadline'); // 从LocalStorage移除对应项 let savedDeadlines = JSON.parse(localStorage.getItem('deadlines')) || []; savedDeadlines = savedDeadlines.filter(item => !(item.title === title && item.deadline === deadline)); localStorage.setItem('deadlines', JSON.stringify(savedDeadlines)); deadlineElement.remove(); } }); // 点击添加按钮事件 btn.addEventListener('click', () => { const title = titleElem.value.trim(); const deadline = timeElem.value; if (!title || !deadline) { alert('请填写完整的任务名称和截止日期'); return; } // 添加到DOM addDeadlineElement(title, deadline); // 保存到LocalStorage saveDeadline(title, deadline); // 清空输入框 titleElem.value = ''; timeElem.value = ''; }); // 页面加载时加载已保存的项 window.addEventListener('load', loadDeadlines); </script> </body> </html>
关键功能说明
自定义元素优化
- 使用Shadow DOM隔离组件样式,避免全局样式冲突
connectedCallback初始化属性并启动定时器,disconnectedCallback清除定时器防止内存泄漏- 拆分
calculateRemainingTime和render方法,逻辑更清晰
时间计算修复
- 通过时间戳计算差值,避免时区影响
- 处理截止日期过期的情况,显示红色提示
LocalStorage持久化
loadDeadlines:页面加载时读取本地存储的任务并渲染saveDeadline:新增任务时保存到本地存储- 监听删除事件,同步删除本地存储中的对应项
DOM操作优化
- 正确获取用户输入(先取值再清空输入框)
- 统一封装
addDeadlineElement方法创建自定义元素 - 为每个倒计时项添加删除按钮,点击后同步更新DOM和LocalStorage
内容的提问来源于stack exchange,提问作者gnehgo
相关产品推荐
相关产品推荐

