Skip to content

时间选择器 TimePicker

时间选择器是用于选择时间的输入组件。

基础用法

基础时间选择器

html
<div class="glass-timepicker">
  <input type="time" class="glass-input" value="12:00">
</div>

预览效果:

带标签的时间选择器

html
<div class="form-group">
  <label class="form-label">选择时间</label>
  <div class="glass-timepicker">
    <input type="time" class="glass-input" value="09:30">
  </div>
</div>

自定义时间选择器

html
<div class="glass-timepicker custom">
  <div class="timepicker-input">
    <input type="text" class="glass-input" placeholder="选择时间" readonly>
    <span class="timepicker-icon">🕐</span>
  </div>
  <div class="timepicker-dropdown">
    <div class="time-columns">
      <div class="time-column hours">
        <div class="time-item active">09</div>
        <div class="time-item">10</div>
        <div class="time-item">11</div>
        <div class="time-item">12</div>
      </div>
      <div class="time-separator">:</div>
      <div class="time-column minutes">
        <div class="time-item">00</div>
        <div class="time-item">15</div>
        <div class="time-item active">30</div>
        <div class="time-item">45</div>
      </div>
    </div>
  </div>
</div>

时间格式

12小时制

html
<div class="glass-timepicker format-12">
  <div class="timepicker-input">
    <input type="text" class="glass-input" value="2:30 PM" readonly>
    <span class="timepicker-icon">🕐</span>
  </div>
  <div class="timepicker-dropdown">
    <div class="time-columns">
      <div class="time-column hours">
        <div class="time-item">01</div>
        <div class="time-item active">02</div>
        <div class="time-item">03</div>
      </div>
      <div class="time-separator">:</div>
      <div class="time-column minutes">
        <div class="time-item active">30</div>
        <div class="time-item">45</div>
      </div>
      <div class="time-column period">
        <div class="time-item">AM</div>
        <div class="time-item active">PM</div>
      </div>
    </div>
  </div>
</div>

24小时制

html
<div class="glass-timepicker format-24">
  <div class="timepicker-input">
    <input type="text" class="glass-input" value="14:30" readonly>
    <span class="timepicker-icon">🕐</span>
  </div>
  <div class="timepicker-dropdown">
    <div class="time-columns">
      <div class="time-column hours">
        <div class="time-item">13</div>
        <div class="time-item active">14</div>
        <div class="time-item">15</div>
      </div>
      <div class="time-separator">:</div>
      <div class="time-column minutes">
        <div class="time-item active">30</div>
        <div class="time-item">45</div>
      </div>
    </div>
  </div>
</div>

时间选择器状态

禁用状态

html
<div class="glass-timepicker disabled">
  <input type="time" class="glass-input" value="12:00" disabled>
</div>

只读状态

html
<div class="glass-timepicker readonly">
  <input type="time" class="glass-input" value="12:00" readonly>
</div>

CSS 类名

基础类名

  • .glass-timepicker - 时间选择器容器
  • .timepicker-input - 输入区域
  • .timepicker-icon - 时间图标
  • .timepicker-dropdown - 下拉面板
  • .time-columns - 时间列容器
  • .time-column - 时间列
  • .time-item - 时间项
  • .time-separator - 时间分隔符

修饰类名

格式修饰符

  • .format-12 - 12小时制
  • .format-24 - 24小时制
  • .custom - 自定义样式

状态修饰符

  • .active - 选中状态
  • .disabled - 禁用状态
  • .readonly - 只读状态

JavaScript 增强

时间选择器组件

javascript
class TimePicker {
  constructor(element, options = {}) {
    this.element = element;
    this.options = {
      format: '24', // 12 or 24
      step: 15, // 分钟步长
      minTime: null,
      maxTime: null,
      defaultTime: null,
      ...options
    };
    
    this.isOpen = false;
    this.selectedTime = null;
    this.init();
  }
  
  init() {
    this.createStructure();
    this.bindEvents();
    this.updateDisplay();
  }
  
  createStructure() {
    this.input = this.element.querySelector('input') || this.createElement('input');
    this.input.readOnly = true;
    this.input.placeholder = '选择时间';
    
    this.dropdown = this.createElement('div', 'timepicker-dropdown');
    this.createTimeColumns();
    
    this.element.appendChild(this.dropdown);
  }
  
  createElement(tag, className = '') {
    const element = document.createElement(tag);
    if (className) element.className = className;
    return element;
  }
  
  createTimeColumns() {
    const columns = this.createElement('div', 'time-columns');
    
    // 小时列
    const hourColumn = this.createElement('div', 'time-column hours');
    this.createHourItems(hourColumn);
    columns.appendChild(hourColumn);
    
    // 分隔符
    const separator = this.createElement('div', 'time-separator');
    separator.textContent = ':';
    columns.appendChild(separator);
    
    // 分钟列
    const minuteColumn = this.createElement('div', 'time-column minutes');
    this.createMinuteItems(minuteColumn);
    columns.appendChild(minuteColumn);
    
    // 12小时制的AM/PM
    if (this.options.format === '12') {
      const periodColumn = this.createElement('div', 'time-column period');
      this.createPeriodItems(periodColumn);
      columns.appendChild(periodColumn);
    }
    
    this.dropdown.appendChild(columns);
  }
  
  createHourItems(container) {
    const hours = this.options.format === '12' ? 
      Array.from({length: 12}, (_, i) => (i + 1).toString().padStart(2, '0')) :
      Array.from({length: 24}, (_, i) => i.toString().padStart(2, '0'));
    
    hours.forEach(hour => {
      const item = this.createElement('div', 'time-item');
      item.textContent = hour;
      item.dataset.value = hour;
      container.appendChild(item);
    });
  }
  
  createMinuteItems(container) {
    const step = this.options.step;
    for (let i = 0; i < 60; i += step) {
      const minute = i.toString().padStart(2, '0');
      const item = this.createElement('div', 'time-item');
      item.textContent = minute;
      item.dataset.value = minute;
      container.appendChild(item);
    }
  }
  
  createPeriodItems(container) {
    ['AM', 'PM'].forEach(period => {
      const item = this.createElement('div', 'time-item');
      item.textContent = period;
      item.dataset.value = period;
      container.appendChild(item);
    });
  }
  
  bindEvents() {
    this.input.addEventListener('click', () => this.toggle());
    
    document.addEventListener('click', (e) => {
      if (!this.element.contains(e.target)) {
        this.close();
      }
    });
    
    this.dropdown.addEventListener('click', (e) => {
      if (e.target.classList.contains('time-item')) {
        this.selectTimeItem(e.target);
      }
    });
  }
  
  selectTimeItem(item) {
    const column = item.parentNode;
    
    // 移除同列其他选中状态
    column.querySelectorAll('.time-item').forEach(i => {
      i.classList.remove('active');
    });
    
    // 设置当前选中
    item.classList.add('active');
    
    this.updateSelectedTime();
  }
  
  updateSelectedTime() {
    const hourItem = this.dropdown.querySelector('.hours .time-item.active');
    const minuteItem = this.dropdown.querySelector('.minutes .time-item.active');
    const periodItem = this.dropdown.querySelector('.period .time-item.active');
    
    if (hourItem && minuteItem) {
      let hour = hourItem.dataset.value;
      const minute = minuteItem.dataset.value;
      const period = periodItem ? periodItem.dataset.value : '';
      
      this.selectedTime = {
        hour: hour,
        minute: minute,
        period: period
      };
      
      this.updateDisplay();
      this.triggerChange();
    }
  }
  
  updateDisplay() {
    if (this.selectedTime) {
      const { hour, minute, period } = this.selectedTime;
      const timeString = this.options.format === '12' ? 
        `${hour}:${minute} ${period}` : 
        `${hour}:${minute}`;
      
      this.input.value = timeString;
    }
  }
  
  triggerChange() {
    this.element.dispatchEvent(new CustomEvent('time-change', {
      detail: {
        time: this.selectedTime,
        timeString: this.input.value
      }
    }));
  }
  
  open() {
    if (this.isOpen) return;
    this.isOpen = true;
    this.dropdown.classList.add('show');
  }
  
  close() {
    if (!this.isOpen) return;
    this.isOpen = false;
    this.dropdown.classList.remove('show');
  }
  
  toggle() {
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }
  
  setValue(timeString) {
    // 解析时间字符串并设置值
    const parts = timeString.match(/(\d{1,2}):(\d{2})(\s*(AM|PM))?/i);
    if (parts) {
      this.selectedTime = {
        hour: parts[1].padStart(2, '0'),
        minute: parts[2],
        period: parts[4] || ''
      };
      this.updateDisplay();
      this.updateSelection();
    }
  }
  
  updateSelection() {
    if (!this.selectedTime) return;
    
    const { hour, minute, period } = this.selectedTime;
    
    // 更新小时选择
    const hourItems = this.dropdown.querySelectorAll('.hours .time-item');
    hourItems.forEach(item => {
      item.classList.toggle('active', item.dataset.value === hour);
    });
    
    // 更新分钟选择
    const minuteItems = this.dropdown.querySelectorAll('.minutes .time-item');
    minuteItems.forEach(item => {
      item.classList.toggle('active', item.dataset.value === minute);
    });
    
    // 更新AM/PM选择
    if (this.options.format === '12') {
      const periodItems = this.dropdown.querySelectorAll('.period .time-item');
      periodItems.forEach(item => {
        item.classList.toggle('active', item.dataset.value === period);
      });
    }
  }
  
  getValue() {
    return this.input.value;
  }
}

// 使用示例
document.querySelectorAll('.glass-timepicker.custom').forEach(element => {
  new TimePicker(element, {
    format: '24',
    step: 15
  });
});

简单时间选择器

javascript
function initTimePickers() {
  document.querySelectorAll('.glass-timepicker').forEach(timepicker => {
    const input = timepicker.querySelector('input[type="time"]');
    if (!input) return;
    
    // 添加变化事件
    input.addEventListener('change', function() {
      const time = this.value;
      console.log('选择的时间:', time);
      
      // 触发自定义事件
      timepicker.dispatchEvent(new CustomEvent('time-select', {
        detail: { time: time }
      }));
    });
    
    // 添加焦点样式
    input.addEventListener('focus', function() {
      timepicker.classList.add('focused');
    });
    
    input.addEventListener('blur', function() {
      timepicker.classList.remove('focused');
    });
  });
}

// 格式化时间显示
function formatTime(timeString, format = '24') {
  if (!timeString) return '';
  
  const [hours, minutes] = timeString.split(':');
  const hour = parseInt(hours);
  
  if (format === '12') {
    const period = hour >= 12 ? 'PM' : 'AM';
    const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
    return `${displayHour}:${minutes} ${period}`;
  }
  
  return `${hours}:${minutes}`;
}

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initTimePickers);

应用场景

预约时间选择

html
<form class="glass-form">
  <div class="form-group">
    <label class="form-label">预约日期</label>
    <input type="date" class="glass-input">
  </div>
  
  <div class="form-group">
    <label class="form-label">预约时间</label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" min="09:00" max="18:00" step="1800">
    </div>
  </div>
  
  <button type="submit" class="glass-button primary">确认预约</button>
</form>

工作时间设置

html
<div class="work-schedule">
  <h3>工作时间设置</h3>
  
  <div class="schedule-item">
    <label class="form-label">上班时间</label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="09:00">
    </div>
  </div>
  
  <div class="schedule-item">
    <label class="form-label">下班时间</label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="18:00">
    </div>
  </div>
  
  <div class="schedule-item">
    <label class="form-label">午休开始</label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="12:00">
    </div>
  </div>
  
  <div class="schedule-item">
    <label class="form-label">午休结束</label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="13:00">
    </div>
  </div>
</div>

提醒时间设置

html
<div class="reminder-settings">
  <h3>设置提醒</h3>
  
  <div class="form-group">
    <label class="form-label">
      <input type="checkbox" class="glass-checkbox"> 
      每日提醒
    </label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="08:00">
    </div>
  </div>
  
  <div class="form-group">
    <label class="form-label">
      <input type="checkbox" class="glass-checkbox">
      会议提醒
    </label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="14:30">
    </div>
  </div>
  
  <div class="form-group">
    <label class="form-label">
      <input type="checkbox" class="glass-checkbox">
      下班提醒
    </label>
    <div class="glass-timepicker">
      <input type="time" class="glass-input" value="17:30">
    </div>
  </div>
</div>

Released under the MIT License.