全是干货,记得好评,嘿嘿

- 不要低于一块, 求你们了,创作不易 ,赞赏码留言: 日期时间选择器组件库 + 邮箱
- 我将源码发送到你邮箱
上干货,功能界面
最完整的选择器
可以根据配置选择不同的选择器

整体的目录结构
version01/
├── docs/ # 项目文档目录
│ ├── README.md # 文档导航首页
│ ├── quick-start.md # 快速开始指南
│ ├── project-analysis.md # 项目深度分析文档
│ ├── yearpicker.md # 年份选择器文档
│ ├── monthpicker.md # 月份选择器文档
│ ├── datepicker.md # 日期选择器文档
│ ├── timepicker.md # 时间选择器文档
│ ├── datetimepicker.md # 日期时间选择器文档
│ ├── screenshots-guide.md # 截图使用指南
│ └── screenshots/ # 截图存放目录
│ └── README.md # 截图说明
│
├── examples/ # 演示示例目录
│ ├── demo.html # 完整功能演示页面
│ └── test.html # 自动化测试页面
│
├── libs/ # 第三方库目录
│ └── jquery-3.6.0.min.js # jQuery 核心库(本地备份)
│
├── src/ # 源代码目录
│ ├── components/ # 组件库目录
│ │ ├── common.css # 组件通用样式
│ │ │
│ │ ├── yearpicker/ # 年份选择器组件
│ │ │ ├── jquery.yearpicker.js # 核心实现代码(~500行)
│ │ │ └── yearpicker.css # 组件样式
│ │ │
│ │ ├── monthpicker/ # 月份选择器组件
│ │ │ ├── jquery.monthpicker.js # 核心实现代码(~600行)
│ │ │ └── monthpicker.css # 组件样式
│ │ │
│ │ ├── datepicker/ # 日期选择器组件
│ │ │ ├── jquery.datepicker.js # 核心实现代码(~740行)
│ │ │ └── datepicker.css # 组件样式
│ │ │
│ │ ├── timepicker/ # 时间选择器组件
│ │ │ ├── jquery.timepicker.js # 核心实现代码(~670行)
│ │ │ └── timepicker.css # 组件样式
│ │ │
│ │ └── datetimepicker/ # 日期时间选择器组件(融合版)
│ │ ├── jquery.datetimepicker.js # 核心实现代码
│ │ └── datetimepicker.css # 组件样式
│ │
│ ├── pages/ # 页面目录(预留)
│ │ └── demo/ # 演示页面(预留)
│ │
│ └── utils/ # 工具函数目录(预留)
│
├── test/ # 测试目录
│ └── test-syntax.js # 语法验证测试脚本
│
├── README.md # 项目说明文档
├── start.md # 开发规范文档(详细教程)
├── start.txt # 开发规范纯文本版
└── TESTING.md # 测试报告文档
EasyUI 自定义选择器组件演示


EasyUI 选择器组件 - 自动化测试



EasyUI jQuery 日期时间选择器组件库深度解析
一个基于 EasyUI 和 jQuery 封装的企业级日期时间选择器组件库,采用标准的 jQuery 插件开发规范,实现了高度模块化和可复用的 UI 组件。
项目概述
在现代企业级 Web 应用开发中,日期时间选择是表单交互中最常见的需求之一。EasyUI 作为一款成熟的前端框架,其原生组件虽然功能强大,但在某些特定场景下仍显不足。本项目正是基于这样的背景,开发了一套完整、独立、易用的日期时间选择器组件库。
核心特性
- 完全独立:每个维度(年/月/日/时)都可独立使用
- 统一规范:遵循 jQuery 插件开发标准
- 配置驱动:丰富的配置选项满足各种业务场景
- 内存安全:完善的事件解绑和组件销毁机制
- 输入验证:实时格式校验和友好的错误提示
项目架构分析
目录结构
version01/
├── src/components/ # 组件库目录
│ ├── yearpicker/ # 年份选择器
│ ├── monthpicker/ # 月份选择器
│ ├── datepicker/ # 日期选择器
│ ├── timepicker/ # 时间选择器
│ ├── datetimepicker/ # 日期时间选择器
│ └── common.css # 通用样式
├── examples/ # 演示页面
├── libs/ # 第三方库
├── docs/ # 文档
└── test/ # 测试文件
设计原则
1. 单一职责原则
每个组件只负责一个维度的选择,通过组合实现复杂功能。
2. 开闭原则
通过配置项扩展功能,无需修改核心代码。
3. 依赖倒置原则
所有组件依赖 jQuery 接口,而非具体实现。
组件深度解析
一、YearPicker 年份选择器
核心功能
年份选择器支持分页显示和可配置布局,适合大范围年份选择场景。
技术亮点
分页算法实现
javascript
// 计算当前页的年份范围
const startIndex = (currentPage - 1) * options.pageSize;
let endIndex = startIndex + options.pageSize - 1;
if (endIndex >= totalYears) {
endIndex = totalYears - 1;
}
智能定位
javascript
// 打开时定位到包含当前选中年份的页
const currentValue = $target.val();
if (currentValue) {
const year = parseInt(currentValue);
const pageIndex = Math.floor((year - opts.startYear) / opts.pageSize) + 1;
instance.currentPage = Math.min(pageIndex, instance.totalPages);
}
配置选项
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| startYear | Number | 1900 | 起始年份 |
| endYear | Number | null | 结束年份 |
| pageSize | Number | 16 | 每页显示数量 |
| columns | Number | 4 | 每行显示列数 |
使用示例
javascript
// 4x4 布局 (默认 16 个年份每页)
$('#yearInput').yearpicker({
startYear: 1950,
endYear: 2050,
pageSize: 16,
columns: 4
});
// 3x3 紧凑布局
$('#yearInput').yearpicker({
startYear: 2000,
endYear: 2030,
pageSize: 9,
columns: 3,
panelWidth: 200
});
// 翻页方法
$('#yearInput').yearpicker('nextPage'); // 下一页
$('#yearInput').yearpicker('prevPage'); // 上一页
$('#yearInput').yearpicker('gotoPage', 2); // 跳转到第2页
二、MonthPicker 月份选择器
核心功能
支持年月组合和纯月份两种模式,可灵活配置输出格式。
技术亮点
多格式支持
javascript
switch (instance.options.format) {
case 'yyyy-MM':
newValue = instance.displayYear + '-' + month;
break;
case 'yyyy年MM月':
newValue = instance.displayYear + '年' + month + '月';
break;
case 'MM月':
newValue = parseInt(month) + '月';
break;
}
年份切换与范围限制
javascript
function changeYear($target, delta) {
instance.displayYear += delta;
// 年份范围限制
if (instance.options.startYear && instance.displayYear < instance.options.startYear) {
instance.displayYear = instance.options.startYear;
}
}
使用示例
javascript
// 年月格式
$('#monthInput').monthpicker({
format: 'yyyy-MM',
onSelect: function(value, data) {
console.log('选中的月份:', value); // 2025-06
console.log('年:', data.year, '月:', data.month);
}
});
// 仅月份格式
$('#monthInput').monthpicker({
format: 'MM月',
showYear: false
});
三、DatePicker 日期选择器
核心功能
完整的日历视图,支持年月日选择和日期范围限制。
技术亮点
日历网格算法
javascript
// 计算每月第一天前的空白天数
const firstDay = new Date(displayYear, displayMonth, 1);
const startDay = (firstDay.getDay() - options.firstDay + 7) % 7;
const totalDays = new Date(displayYear, displayMonth + 1, 0).getDate();
日期格式化与解析
javascript
function formatDate(date, format) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return format.replace('yyyy', year).replace('MM', month).replace('dd', day);
}
状态标识
javascript
// 今天、选中、禁用三种状态
if (isToday) classes += ' datepicker-today';
if (isSelected) classes += ' datepicker-selected';
if (isDisabled) classes += ' datepicker-disabled';
使用示例
javascript
// 基本用法
$('#dateInput').datepicker({
format: 'yyyy-MM-dd',
minDate: new Date(2025, 0, 1),
maxDate: new Date(2025, 11, 31),
onSelect: function(value, date) {
console.log('选中的日期:', value);
}
});
// 获取Date对象
var date = $('#dateInput').datepicker('getDate');
// 设置Date对象
$('#dateInput').datepicker('setDate', new Date(2025, 5, 15));
四、TimePicker 时间选择器
核心功能
时分秒独立选择,支持步进配置和确认机制。
技术亮点
时间列生成器
javascript
function createTimeColumn(type, label, step, min, max) {
let items = '';
for (let i = min; i <= max; i += step) {
const value = String(i).padStart(2, '0');
items += `<div class="timepicker-item" data-value="${value}">${value}</div>`;
}
return items;
}
时间解析与验证
javascript
function parseTime($target) {
const parts = value.split(/[::]/);
if (parts.length >= 2) {
instance.currentHours = String(parseInt(parts[0]) || 0).padStart(2, '0');
instance.currentMinutes = String(parseInt(parts[1]) || 0).padStart(2, '0');
}
}
使用示例
javascript
// 完整时间
$('#timeInput').timepicker({
format: 'HH:mm:ss',
showSeconds: true,
hourStep: 1,
minuteStep: 1,
secondStep: 1,
onSelect: function(value, data) {
console.log('选中的时间:', value); // 14:30:00
console.log('时:', data.hours, '分:', data.minutes, '秒:', data.seconds);
}
});
// 仅时分
$('#timeInput').timepicker({
format: 'HH:mm',
showSeconds: false
});
jQuery 插件开发规范
组件模板结构
javascript
(function($) {
'use strict';
// 1. 默认配置
const defaults = {
// 配置项...
};
// 2. 初始化函数
function init(target, options) {
// 防止重复初始化
if ($target.data('pluginName')) {
return;
}
// 合并配置
const opts = $.extend({}, defaults, options);
// 创建结构
createStructure($target, opts);
// 绑定事件
bindEvents($target, opts);
}
// 3. 创建 DOM 结构
function createStructure($target, opts) {
// 创建面板、图标等
}
// 4. 绑定事件
function bindEvents($target, opts) {
// 绑定所有交互事件
}
// 5. jQuery 插件定义
$.fn.pluginName = function(methodOrOptions) {
// 方法调用模式
if (typeof methodOrOptions === 'string') {
const $el = this.first();
const instance = $el.data('pluginName');
if (!instance) {
throw new Error('组件未初始化');
}
// 处理各种方法
switch (methodOrOptions) {
case 'getValue': return $el.val();
case 'setValue': /* ... */
case 'destroy': /* ... */
}
}
// 初始化模式
return this.each(function() {
init(this, methodOrOptions);
});
};
// 6. 暴露默认配置
$.fn.pluginName.defaults = defaults;
})(jQuery);
两种调用模式
初始化模式
javascript
$('#input').datepicker({
format: 'yyyy-MM-dd',
onSelect: function(value) {
console.log('选中:', value);
}
});
方法调用模式
javascript
const value = $('#input').datepicker('getValue');
$('#input').datepicker('setValue', '2025-06-15');
$('#input').datepicker('destroy');
生命周期管理
1. 初始化阶段
- 防重复初始化检查
- 配置合并与默认值处理
- DOM 结构创建
- 实例数据存储
javascript
const instance = $target.data('datepicker') || {};
instance.options = opts;
instance.isOpen = false;
$target.data('datepicker', instance);
2. 运行阶段
- 面板显示/隐藏
- 用户交互处理
- 值验证与格式化
3. 销毁阶段
javascript
case 'destroy':
const id = $el.attr('id');
$(document).off('.datepicker.' + id); // 解绑文档事件
$el.off('.datepicker'); // 解绑元素事件
if (instance.icon) {
instance.icon.off('.datepicker'); // 解绑图标事件
}
if (instance.panel) {
instance.panel.remove(); // 移除面板DOM
}
$el.removeClass('datepicker-text')
.removeData('datepicker'); // 清除数据
return $el;
事件处理机制
命名空间事件
所有事件都使用命名空间,便于精确控制和解绑:
javascript
// 绑定事件
$target.on('click.datepicker', handler);
$(document).on('click.datepicker.' + id, handler);
// 解绑事件
$target.off('.datepicker');
$(document).off('.datepicker.' + id);
事件冒泡控制
javascript
const openHandler = function(e) {
e.preventDefault();
e.stopPropagation();
// 打开面板逻辑
};
// 面板内部点击阻止冒泡
instance.panel.on('click.datepicker', function(e) {
e.stopPropagation();
});
点击外部关闭
javascript
$(document).on('click.datepicker.' + id, function(e) {
const $panel = instance.panel;
const $wrap = $target.closest('.datepicker-wrap');
if (!$panel.is(e.target) && $panel.has(e.target).length === 0 &&
!$wrap.is(e.target) && $wrap.has(e.target).length === 0) {
closePanel($target);
}
});
输入验证系统
实时验证
javascript
$target.on('input.datepicker', function() {
const value = $target.val().trim();
const minLen = opts.format.includes('-') ? 10 : 10;
if (value.length >= minLen) {
validateDateInput($target, opts);
}
});
$target.on('blur.datepicker', function() {
const value = $target.val().trim();
if (value) {
validateDateInput($target, opts);
}
});
错误提示机制
javascript
function showInputError($target, message) {
const $wrap = $target.closest('.datepicker-wrap');
let $tooltip = $wrap.find('.datepicker-error-tip');
if (!$tooltip.length) {
$tooltip = $('<div class="datepicker-error-tip"></div>');
$wrap.append($tooltip);
}
$tooltip.text(message).fadeIn(200);
// 2秒后自动隐藏
setTimeout(function() {
$tooltip.fadeOut(200);
}, 2000);
// 输入框错误样式
$target.addClass('datepicker-input-error');
setTimeout(function() {
$target.removeClass('datepicker-input-error');
}, 500);
}
公共 API 说明
公共配置项
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| placeholder | string | '请选择' | 占位提示文本 |
| showIcon | boolean | true | 是否显示图标 |
| iconCls | string | 'icon-calendar' | 图标样式类名 |
| required | boolean | false | 是否必填 |
| editable | boolean | true | 是否可编辑 |
| readonly | boolean | false | 是否只读 |
| disabled | boolean | false | 是否禁用 |
| onSelect | function | null | 选择回调函数 |
| onChange | function | null | 值改变回调函数 |
公共方法
| 方法 | 说明 | 示例 |
|---|---|---|
| getValue | 获取当前值 | $el.picker('getValue') |
| setValue | 设置值 | $el.picker('setValue', value) |
| enable | 启用组件 | $el.picker('enable') |
| disable | 禁用组件 | $el.picker('disable') |
| destroy | 销毁组件 | $el.picker('destroy') |
| options | 获取配置 | $el.picker('options') |
组合使用
各组件可以独立使用,也可以组合使用:
html
<input type="text" id="year" placeholder="年份">
<input type="text" id="month" placeholder="月份">
<input type="text" id="date" placeholder="日期">
<input type="text" id="time" placeholder="时间">
javascript
$('#year').yearpicker();
$('#month').monthpicker();
$('#date').datepicker();
$('#time').timepicker();
测试与质量保证
自动化测试覆盖
项目实现了全面的自动化测试,覆盖以下内容:
JavaScript 组件测试
- IIFE 包装结构
- 默认配置定义
- 初始化函数
- DOM 结构创建
- 事件绑定与解绑
- 公共方法实现
- 回调函数支持
CSS 样式测试
- 面板样式
- 输入框样式
- 图标样式
- 状态样式(选中、悬停、禁用)
测试结果
YearPicker: 全部通过 (18/18)
MonthPicker: 全部通过 (18/18)
DatePicker: 全部通过 (18/18)
TimePicker: 全部通过 (18/18)
性能优化
DOM 操作优化
- 批量更新 :使用
html()替代多次append() - 事件委托:面板内部事件使用委托绑定
- 缓存选择器:保存常用 jQuery 对象
javascript
// 批量生成并一次性插入
const cells = [];
for (let i = startIndex; i <= endIndex; i++) {
cells.push(`<div class="datepicker-day" data-day="${i}">${i}</div>`);
}
$body.html(cells.join(''));
内存管理
javascript
// 实例数据集中管理
const instance = {
options: opts,
panel: $panel,
icon: $icon,
isOpen: false,
// 其他状态...
};
$target.data('datepicker', instance);
// 销毁时完整清理
$el.removeData('datepicker')
.removeClass('datepicker-text');
最佳实践总结
1. 命名规范
- 组件名 :
datepicker、monthpicker - CSS 类 :
datepicker-panel、datepicker-selected - 事件命名空间 :
.datepicker - 数据键 :
datepicker
2. API 设计
javascript
// 初始化
$('#el').plugin({ option: value });
// 获取值
$('#el').plugin('getValue');
// 设置值
$('#el').plugin('setValue', value);
// 销毁
$('#el').plugin('destroy');
3. 配置设计
javascript
const defaults = {
// 基础配置
placeholder: '请选择',
showIcon: true,
// 行为配置
editable: true,
readonly: false,
disabled: false,
// 回调函数
onSelect: null,
onChange: null
};
4. 样式隔离
css
/* 组件前缀避免冲突 */
.datepicker-panel { }
.datepicker-header { }
.datepicker-body { }
.datepicker-selected { }
浏览器兼容性
- Chrome (推荐)
- Firefox
- Safari
- Edge
- IE 11+
项目文件说明
核心文件
src/components/
├── yearpicker/
│ ├── jquery.yearpicker.js # 年份选择器核心代码
│ └── yearpicker.css # 年份选择器样式
├── monthpicker/
│ ├── jquery.monthpicker.js # 月份选择器核心代码
│ └── monthpicker.css # 月份选择器样式
├── datepicker/
│ ├── jquery.datepicker.js # 日期选择器核心代码
│ └── datepicker.css # 日期选择器样式
├── timepicker/
│ ├── jquery.timepicker.js # 时间选择器核心代码
│ └── timepicker.css # 时间选择器样式
└── common.css # 通用样式
示例文件
examples/
├── demo.html # 完整演示页面
└── test.html # 测试页面
总结
这个项目展示了如何构建一个高质量、可维护的 jQuery 组件库。通过遵循标准化的开发规范、实现完善的生命周期管理、提供丰富的配置选项,使得每个组件都可以独立使用,也可以灵活组合。
核心价值
- 规范化:统一的开发模式和 API 设计
- 模块化:每个组件职责单一,高内聚低耦合
- 可测试:完善的测试覆盖保证代码质量
- 可维护:清晰的代码结构和完善的文档
适用场景
对于正在维护基于 EasyUI 的老系统的团队,这套组件库提供了很好的参考价值,展示了如何在不引入现代框架的情况下,依然可以写出优雅、可维护的前端代码。
学习要点
通过研究这个项目,可以学到:
- jQuery 插件开发的标准模式
- 组件生命周期管理
- 事件处理和命名空间的使用
- DOM 操作和内存管理最佳实践
- 输入验证和错误处理机制
- 如何设计灵活的配置系统
项目版本:1.0.0
技术栈:jQuery 3.6.0 + EasyUI
许可证:MIT License