动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网页制作 > Javascript教程
网页制作:Dreamweaver教程,FrontPages教程,Javascript教程,HTML教程,CSS教程,心得技巧,DHTML教程,网页特效,Discuz!论坛
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ Javascript教程 ]的信息

本月文章推荐
.60秒倒计时的一个小JAVASCRIPT.
.PHP与JavaScript对多项选择的处理.
.JavaScript FSO属性大全.
.Javascript实例教程(19) 使用HoT.
.JavaScript中try...catch和异常处.
.Javascript实现的自动验证函数.
.用JavaScript制作多彩的弹出式说.
.用 JavaScript 迁移目录.
.百度源代码里的精妙javascript图.
.用javascript控制复选框的个数.
.VBScript和JavaScript中的正则基.
.javascript 对层下的表格加快捷键.
.Javascript实例教程(7) 利用Java.
.JavaScript利用ActiveX导出Excel.
.经典正则表达式 (收藏整理).
.Javascript简易调色板效果.
.JavaScript常用检测脚本.
.Javascript实例教程(19) 使用HoT.
.URL编码转换,escape() encodeURI.
.跨子域页面间的JavaScript访问.

Javascript下的日历控件(Calendar)

发表日期:2008-8-25 |


    曾经,我发布过《几个Javascript类》,得到部分朋友的支持;有道是,授之予鱼,不如授之予渔。同时结合朋友们的评价,我对该日历控件做了兼容性检查,已经“基本”支持火狐浏览器应用了;遗留一个小问题,火狐下面“日”提取有问题,不知道有兴趣的朋友能不能在读完本文后自己动手修正该漏洞(提示:火狐不支持 element.innerText,但支持 innerHTML :))。

    每个人都是从“不会”到“会”(或者,从无到有)走过来的。当初为了这样一个在静态 html 文件可应用的轻量级控件,找了不少站点。源于自己出身于 c#,故在应用方式上做了类 c# 包装。

    先谈怎么应用,然后说我是怎么实现的。以下是我在源码包中的演示代码:

function CalendarDemon(){  
/// <summary>  
/// 如何使用 Calendar 类的演示代码. 参见代码 JsLibrary/Html/Calendar.js.  
/// 请尊重作者劳动, 引用需注明出处.  
/// Howard.Queen@hotmail.com, 2008-07-03.  
/// http://howard-queen.cnblogs.com/  
/// </summary>  
 
 
    //全局变量  
    window.myCalendar = null;        //日历控件  
    window.currentDay = null;        //当前选择日期  
    window.myTextBox = null;         //当前显示日期的控件  
    window.DayChangedCallback = null;//日历选择日期的回调方法  
    window.MyCalendarPerforms = null;//激活日历的方法, 通过显示控件的相关事件调用  
 
    //日历选择日期的回调方法  
    DayChangedCallback = function(sender, args){  
        try{  
            currentDay = args;  
            myTextBox.value = currentDay.GetText("年", "月", "日");//输出所选日期. 自定义日期序列化.  
            //myCalendar.Hidden();//掩藏控件          
        }  
        catch(e){  
            alert(e.message);  
        }  
    }  
      
    //激活日历的方法  
    MyCalendarPerforms = function(textBox){  
        try{  
            if(myCalendar.IsVisible())  
                myCalendar.Hidden();//掩藏控件  
            else{  
                if(myTextBox.value != '')//注意: myTextBox == textBox  
                    currentDay.FromText(myTextBox.value, "年", "月", "日");//获取已有日期. 注意根据日期的格式, 让系统进行反序列.  
                myCalendar.Show(myTextBox, currentDay);//设置日历显示日期. Show(sender, currentDay), 日历将显示在 sender 附近, 初始化时显示 currentDay.  
            }  
        }  
        catch(e){  
            alert(e.message);  
        }  
    }  
      
    //日历显示容器  
    document.write("<div id='calendarPannel' style='position:absolute; z-index:1; dispay:none;'></div>");  
    var pannel = document.getElementById('calendarPannel');   
      
    //日期显示绑定的控件  
    document.write('<input id="myTextBox" type="text" onclick="javascript:MyCalendarPerforms(this);" />');  
    myTextBox = document.getElementById('myTextBox');  
      
    //本地化, 缺省为英文  
    var months = new CalendarMonths(["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]);  
    var weekdays = new CalendarWeekDays(["日","一","二","三","四","五","六"]);  
         
    //设置初始日期. 缺省参数则为今天.  
    currentDay = new CalendarDay();//currentDay = new CalendarDay(2008, 5, 12);  
      
    //创建日历控件. 注意自定义日历显示位置的位移差, 此处用了(5, -150).  
    myCalendar = new Calendar('myCalendar', pannel, DayChangedCallback, 5, -150, currentDay, months, weekdays);  

    应用它涉及到 5 个关键全局变量的定义。该控件实例,当前所选择的日期实例,显示当前日期的绑定控件,日期选择后的回调函数以及激活日历的方法。月份等显示支持本地化设置,甚至当前日期的输出也支持本地化。


--------------------------------------------------------------------------------

    “揭密该控件的实现内幕”:

/// <reference path="Tooltip.js"/>  
 
function Calendar(Id, pannel, SelectedDayChangedEvent, toper, lefter, selectedDay, calendarMonths, calendarWeekDays){  
/// <summary>  
/// 日期选择控件. 月份从 1 开始.使用方法参见示例代码 JsDemons/Html/CalendarDemon.js.  
/// 参考版本《日期选择 - BY ziyue, By Jiang Hongbin等》.  
/// <see cref="http://web-v.com/article.asp?id=3"/>  
/// <seealso cref="http://web-v.com/trackback.asp?tbID=3&action=addtb&tbKey=2fefac8959f18cceb46771512eff082b27e97c09"/>  
/// 请尊重作者劳动, 引用需注明出处.  
/// Howard.Queen@hotmail.com, 2008-07-03.  
/// http://howard-queen.cnblogs.com/  
/// 2008-07-10   
///     1, 修改 node.innerText 为 node.innerHTML. 完美支持 Firefox.  
///     2, 添加年份无上下限功能.  
///     3, 添加当前所选日期亮显功能.  
///     4, 更改了自定义日期序列化与反序列化, 使得更加友好.  
///     5, 采用显示缓存策略以提高性能.  
///     6, 一些方法的命名更改.  
/// </summary>  
/// <param name="Id" type="string">当前控件名称.</param>  
/// <param name="pannel" type="control">显示容器.</param>  
/// <param name="SelectedDayChangedEvent" type="event">选择日期更改事件.</param>  
/// <param name="selectedDay" type="CalendarDay">所选日期.</param>  
/// <param name="calendarMonths" type="CalendarMonths">月名称.</param>  
/// <param name="calendarWeekDays" type="CalendarWeekDays">周中日名称.</param>  
    this._Init(Id, pannel, SelectedDayChangedEvent, toper, lefter, selectedDay, calendarMonths, calendarWeekDays);  
}  
 
Calendar.prototype = {  
    _Init: function(Id, pannel, SelectedDayChangedEvent, toper, lefter, selectedDay, calendarMonths, calendarWeekDays){  
    },  
    _DrawCallback: function(sender, args){  
    /// <summary>回调显示.</summary>  
    },  
    _Render: function(temp){  
    /// <summary>[私有]</summary>    
    },  
    _RenderYear: function(temp){  
    /// <summary>[私有]</summary>  
    },  
    _RenderMonth: function(temp){  
    /// <summary>[私有]</summary>      
    },  
    _RenderWeek: function(temp){  
    /// <summary>[私有]</summary>  
    },  
    _RenderDay: function(temp){  
    /// <summary>[私有]</summary>  
    },  
    _OnCurrentDayChanging: function(dayCell){  
    },  
    _Refresh: function(year, month) {  
    /// <summary>[私有]</summary>         
    },  
     _CreateCalenday: function(year, month) {  
    /// <summary>[私有]</summary>  
    },  
    _OnYearChanging: function(sender, args){  
    },  
    _OnMonthChanging: function(sender, args){   
    },  
    _OnDayChanging: function(sender, args){  
    },  
    IsVisible: function(){  
    },  
    Hidden: function(){  
    },  
    Show: function(sender, args){  
    }  
}  
 
function CalendarDay(year, month, day){  
/// <summary>Calendar中的日期.</summary>  
    this._Init(year, month, day);  
}  
 
CalendarDay.prototype = {  
    _daysCountOfMonths: new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),  
    _Init: function(year, month, day){  
    },  
    _GetSubNumber: function(string, head, tail){  
    },  
    CheckDate: function(year, month, day){  
    /// <summary>检查日期合法性.</summary>  
    /// <param name="year" type="int">年份.</summary>  
    /// <param name="month" type="int">月份.</summary>  
    /// <param name="day" type="int">月中日数.</summary>  
    /// <returns>是否合法.</returns>  
    },  
    GetDayInWeek: function(){  
    },  
    IsLeapYear: function(year){  
    /// <summary>是否闰年</summary>  
    /// <param name="year" type="int">年份.</param>  
    /// <returns>是否闰年.</returns>  
    },     
    GetMonthDays: function(year, month){  
    /// <summary>获取月的天数</summary>  
    /// <param name="year" type="int">年份.</param>  
    /// <param name="month" type="int">月份.</param>  
    /// <returns>天数.</returns>  
    },  
    FromText: function(text, yearCaption, monthCaption, dayCaption){  
    /// <summary>设置选定日期.</summary>  
    /// <param name="text" type="string">日期表达式, 顺序为年、月、日.</summary>  
    },  
    GetText: function(yearCaption, monthCaption, dayCaption){  
    /// <summary>获取选定日期.</summary>  
    },  
    GetLocalMonth: function(calendarMonths){  
    },  
    GetLocalWeekDay: function(calendarWeekDays){  
    }  
}  
 
function CalendarMonths(names){  
/// <summary>月枚举.</summary>  
/// <param name="names" type="Array">月自定义名称数组.</param>  
}  
 
function CalendarWeekDays(names){  
/// <summary>周中日枚举.</summary>  
/// <param name="names" type="Array">周中日自定义名称数组.</param>  

    如上所示,我将该控件分解为三个类进行实现,Calendar 只负责绘制子控件以及事件收集,CalendarDay 负责对时间进行核准、计算以及输出,剩下两个类似枚举的辅助类。对于 Tooltip,这是我早前包装的,不是为日历控件特制。这些都有别于原始素材(注意类 Calendar 注释中的 see 以及 seealso 部分),感兴趣的朋友可以就可复用性进行对比。

    Calendar 只对外透露三个方法: Show(),Hidden(),IsVisible()。何时显示、何时掩藏,都由应用开发者定制,这给开发人员在不同场合的应用制造了便利。


--------------------------------------------------------------------------------

    在控件核心类 Calendar 的绘制算法上,我将年(_RenderYear())、月(_RenderMonth())、周(_RenderWeek())、日(_RenderDay())独立为方法进行输出,有利于代码的自说明,更方便朋友们的定制与修正。在后期的更新中,我在“年”下拉框上增加了“更多过去”与“更多将来”下拉选项,使得年份也不会拘泥于某个特定时间段,而扩展到了无限。而在显示控件(Show())时,为了防止大量重复计算,只在初次加载控件时进行绘制;但这造成一个小问题,用户当前输入框中的内容只在初始化会同步到控件,其他时刻,控件将忽略。如下代码:

Show: function(sender, args){  
    /// <summary>显示控件.</summary>  
    /// <param name="sender" type="control">发送者.</param>  
    /// <param name="args" type="CalendarDay">当前日期.</param>  
        if(this._yearsSelect == undefined){//第一次加载. Tooltip 中有对当前控件的缓存, 因此这里没有必要重复计算.  
            this.selectedDay = args;  
            this.offsetTop = sender.offsetTop;  
            this.offsetLeft = sender.offsetLeft;  
            this.clientHeight = sender.clientHeight;  
            this.clientWidth = sender.clientWidth;  
            this._toolTip.Show(sender, this);  
            this._yearsSelect = document.getElementById([this.Id, '_yearsSelect'].join(''));  
            this._monthsSelect = document.getElementById([this.Id, '_monthsSelect'].join(''));  
            this._daysTable = document.getElementById([this.Id, '_daysTable'].join(''));  
            for (var weekIndex = 0, dayInWeek = 0; weekIndex < this._daysTable.rows.length; weekIndex++){  
                for (; dayInWeek < this._daysTable.rows[weekIndex].cells.length; dayInWeek ++){   
                    cell = this._daysTable.rows[weekIndex].cells[dayInWeek];   
                    switch(dayInWeek){  
                        case 0://星期日  
                            cell.style.color = 'red';  
                            break;  
                        case 6://星期六  
                            cell.style.color = 'green';   
                            break;  
                        default://其他  
                            break;  
                    }  
                }  
                dayInWeek = 0;  
            }  
            this._CreateCalenday(this._yearsSelect.value, this._monthsSelect.value);  
        }  
        else{  
            this._toolTip.Show(sender, this);  
        }  
    } 

--------------------------------------------------------------------------------

    在日期类 CalendarDay 的设计上,针对日期的输出形式仍有较大开发空间。在后期的更新中,我只是简单的加了对年月日的重命名输出,以及对该输出的反向识别,但没有实现类 c# 的 ToString("yyMMdd") 等方法。看我的具体实现:

FromText: function(text, yearCaption, monthCaption, dayCaption){  
    /// <summary>设置选定日期.</summary>  
    /// <param name="text" type="string">日期表达式, 顺序为年、月、日.</summary>  
        if(text == undefined || text == null || text == ''){  
            throw {name:"ArgumentNullException", message:"参数为空, 参数名 text."};  
        }  
        if(yearCaption == undefined || yearCaption == null || yearCaption == '')  
            yearCaption = '-';  
        if(monthCaption == undefined || monthCaption == null || monthCaption == '')  
            monthCaption = '-';  
        if(dayCaption == undefined || dayCaption == null)  
            dayCaption = '';  
        var year = parseInt(this._GetSubNumber(text, '', yearCaption));  
        var month = parseInt(this._GetSubNumber(text, yearCaption, monthCaption));  
        var day = parseInt(this._GetSubNumber(text, monthCaption, dayCaption));       
        this.CheckDate(year, month, day);  
        this.year = year;  
        this.month = month;  
        this.day = day;  
        this._dayInWeek = -1;  
    },  
    GetText: function(yearCaption, monthCaption, dayCaption){  
    /// <summary>获取选定日期.</summary>  
        if(yearCaption == undefined || yearCaption == null || yearCaption == '')  
            yearCaption = '-';  
        if(monthCaption == undefined || monthCaption == null || monthCaption == '')  
            monthCaption = '-';  
        if(dayCaption == undefined || dayCaption == null)  
            dayCaption = '';  
        return [this.year, yearCaption, this.month, monthCaption, this.day, dayCaption].join('');  
    }, 

--------------------------------------------------------------------------------

    开发过程的乐趣在于,你所做的给自己或者别人带来了一些便利;对于学习开发的入门兄弟来说更是如此。总是说程序员大概都是懒人,能复用的代码,绝不写第二遍;有些人甚至因此偏执于搞复用:用最少的现有代码,延用过去做好的“控件”。但能否在各种场景下复用,就看你对经验的总结了。

    虽然都是小把戏,但还是善意的提醒朋友们:将一个计算过程分滩给多个方法,每个方法短而功能明确,这对以后追加功能或是查找漏洞都会很有帮助。什么时候,我能把设计模式给搞透?

上一篇:JavaScript面向对象之方法重载 人气:725
下一篇:常用的JavaScript验证正则表达式 人气:1069
浏览全部Javascript的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-11-21 AutoIndex v2.2.4 多国语言版
2008-11-21 ASBLOG v2.5 bulid 081118
2008-11-21 phpwebsite v1.60
2008-11-21 DreamArticle 文章管理系统 v3.0
2008-11-21 DreamArticle 文章管理系统 v3.0
2008-11-21 Piwik ( PHP统计系统,可以和GOOG
2008-11-21 CMS001 v2.2 Beta
2008-11-21 magento开源电子商务平台 v1.1.7
2008-11-21 开良马克思影视下载插件 v1.1
2008-11-21 傲游(Maxthon) 2.1.5 正式版
2008-11-21 Skype v3.8.0.188 Final
2008-11-21 AirPlay OpenAlpha 2008.11.20
2008-11-21 屏幕文字抓取工具 DWMouse1.3.510
2008-11-21 Vista一键还原(Vista Ghost)1.
2008-11-21 SP Photo Fix照片修改1.2破解版
2008-11-21 QQ腾讯聊天工具 v1.2正式版
2008-11-21 FlightTrack航班信息v1.0破解版
2008-11-21 RealPiano仿真钢琴1.0破解版
  发表评论
姓 名: 验证码:
内 容:
站长工具:网站收录查询 | Google PR查询 | ALEXA排名查询 | CSS在线编辑器 | 广告代码 | js/vbs加密 | md5加密 | 进制转换 | UTF-8 转换工具 | Html转换js | Html转换asp | Html转换php | Html转换perl
实用工具:汉字翻译拼音 | 拼音字典 | 符号对照表 | 个税计算 | 实时汇率查询换算 | 经典小工具 | 汉字简繁转换 | 普通单位换算 | 公制单位换算 | 生辰老黄历 | 国内电话区号 | 国家代码与域名缩写 | 文字加密解密 | 健康查询 | 万年历 | 汉字横竖排版 | 手机号码查询 | 计算器 | ip搜索
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵
SEO対策 中国語教室 ホームページ作成