實現一個日期下拉菜單
這篇文章的主旨是弄清楚如何根據實際需求實現一個聯動菜單以及聯動菜單的原理,實例是實現一個日期選擇下拉菜單。本文調試環境為IE6/firefox1.5。
首先來分析一下日期下拉菜單的需求。建議大家在寫任何程序的時候都應該在動手編程之前想清楚自己需要些什么,這樣編程才有效率。
年份: 一般來說有一個有效年份,比如說1900年至當前年份才是為效的,這個要根據實際需求來確定,如果是該下拉菜單是用來選擇出生年月日還得把最大的年份減到一定的數目,如果有人的生日選擇了2005年(即當前的年份),那是不正常的。
月份:沒有什么特殊需求,不管是哪一年都是有十二個月。
天數:每個月的天數都可能是不定的,當然這可以根據一定的算法求出來,而它的根據就是當前選擇的年份和月份。月份都有一個固定的天數,即一、三、五、七、八、十、十二月是三十一天,而四、六、九、十一月是三十天,二月份要根據當年是否為閏年判斷是二十八天還是二十九天。求當月的天數我提出一個比較簡單的算法,可以只根據當前的年份和月份就可以求出當月的天數,這會在后邊講一講思路并將其實現。
好了,現在我們來具體實現這個日期聯動下拉菜單。
聯動下拉菜單是以兩個或多個select元素為單位的,為了讓這些菜單更多緊密的工作,我們可以實現一個類用來管理它們的初始化、事件,在這里就使用DateSelector為類名,它有三個屬性,分別為年、月、日的下拉菜單,而這三個select元素是由構造函數的參數傳進來的,另外為了更靈活地使用它,我們還可以再給DateSelector類的構造函數增加一個(Date對象)或三個參數(int數值),表示初始化的年月日。由于參數個數不定,我們可以不將另外增加的參數寫入參數表里,而是在運行時判斷arguments對象的length屬性來執行不同的操作。arguments對象存儲了當前函數的參數信息,可以查閱一下相關的資料比如說《Windows腳本技術》。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
}
</script>
</head>
<body>
</body>
</html>
接下來開始對聯動菜單進行初始化,首先是年份,我們可以給類增加一個MinYear屬性表示最小的年份,再增加一個MaxYear表示最大的年份,實現一個InitYearSelect方法初始化年份,實現一個InitMonthSelect方法初始化月份。由于這幾個屬性和方法的思路都是很簡單,就不一一講解,看看代碼是怎么寫的應該就能夠明白,如果對類方面有不清楚有地方可以參考我發表在無憂腳本另一篇文章《由淺到深了解JavaScript類》。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
this.InitYearSelect();
this.InitMonthSelect();
}
// 增加一個最大年份的屬性
DateSelector.prototype.MinYear = 1900;
// 增加一個最大年份的屬性
DateSelector.prototype.MaxYear = (new Date()).getFullYear();
// 初始化年份
DateSelector.prototype.InitYearSelect = function()
{
// 循環添加OPION元素到年份select對象中
for(var i = this.MaxYear; i >= this.MinYear; i--)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到年份select對象
this.selYear.appendChild(op);
}
}
// 初始化月份
DateSelector.prototype.InitMonthSelect = function()
{
// 循環添加OPION元素到月份select對象中
for(var i = 1; i < 13; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到月份select對象
this.selMonth.appendChild(op);
}
}
</script>
</head>
<body>
<select id="selYear"></select>
<select id="selMonth"></select>
<select id="selDay"></select>
<script type="text/javascript">
var selYear = window.document.getElementById("selYear");
var selMonth = window.document.getElementById("selMonth");
var selDay = window.document.getElementById("selDay");
// 新建一個DateSelector類的實例,將三個select對象傳進去
new DateSelector(selYear, selMonth ,selDay);
</script>
</body>
</html>
接下來要對天數進行初始化了,前邊有說過天數是不定的,那要如何準確求出它的天數呢?我們稍加分析就知道每個月的最后一天就是該月的天數,相當于下一個月的第一天的前一天,比如說我們要求2005年11月的天數,那我們只需要得到2005年12月一日的前一天即可得到2005年11月最后一天。可以給DateSelector添加一個方法DaysInMonth來實現該功能。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
this.InitYearSelect();
this.InitMonthSelect();
}
// 增加一個最大年份的屬性
DateSelector.prototype.MinYear = 1900;
// 增加一個最大年份的屬性
DateSelector.prototype.MaxYear = (new Date()).getFullYear();
// 初始化年份
DateSelector.prototype.InitYearSelect = function()
{
// 循環添加OPION元素到年份select對象中
for(var i = this.MaxYear; i >= this.MinYear; i--)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到年份select對象
this.selYear.appendChild(op);
}
}
// 初始化月份
DateSelector.prototype.InitMonthSelect = function()
{
// 循環添加OPION元素到月份select對象中
for(var i = 1; i < 13; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到月份select對象
this.selMonth.appendChild(op);
}
}
// 根據年份與月份獲取當月的天數
DateSelector.DaysInMonth = function(year, month)
{
var date = new Date(year, month, 0);
return date.getDate();
}
</script>
</head>
<body>
<select id="selYear"></select>
<select id="selMonth"></select>
<select id="selDay"></select>
<script type="text/javascript">
var selYear = window.document.getElementById("selYear");
var selMonth = window.document.getElementById("selMonth");
var selDay = window.document.getElementById("selDay");
// 新建一個DateSelector類的實例,將三個select對象傳進去
new DateSelector(selYear, selMonth ,selDay);
alert("2004年2月的天數為" + DateSelector.DaysInMonth(2004, 2));
alert("2005年2月的天數為" + DateSelector.DaysInMonth(2005, 2));
</script>
</body>
</html>
很明顯,這種方法根本不需要考慮到該年份是否為閏年就可以輕松求出指定月的天數。另外,有些網友可能會對“var date = new Date(year, month, 0);”這句代碼覺得奇怪,傳入的是2005,2,0,這看起來似乎是求二月份第一天的前一天即一月份的最后一天,為什么還會得到二月份的天數?這里必須說明一天,JavaScript的Date對象里的月份是由0開始到11結束,也就是說0表示一月,2表示三月,所以就有這種錯覺,在使用JavaScript的Date對象時要特別注意這一點。
好了,天數的算法也解決了,那么我們可以輕松寫出一個InitDaySelect方法來初始化天數了,在這個方法里要根據當前年份下拉菜單和月份下拉菜單的值算出該月的天數,由于天數是變動的,因此我們在該方法里也可事先清空天數下拉菜單的內容。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
this.InitYearSelect();
this.InitMonthSelect();
this.InitDaySelect();
}
// 增加一個最大年份的屬性
DateSelector.prototype.MinYear = 1900;
// 增加一個最大年份的屬性
DateSelector.prototype.MaxYear = (new Date()).getFullYear();
// 初始化年份
DateSelector.prototype.InitYearSelect = function()
{
// 循環添加OPION元素到年份select對象中
for(var i = this.MaxYear; i >= this.MinYear; i--)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到年份select對象
this.selYear.appendChild(op);
}
}
// 初始化月份
DateSelector.prototype.InitMonthSelect = function()
{
// 循環添加OPION元素到月份select對象中
for(var i = 1; i < 13; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到月份select對象
this.selMonth.appendChild(op);
}
}
// 根據年份與月份獲取當月的天數
DateSelector.DaysInMonth = function(year, month)
{
var date = new Date(year, month, 0);
return date.getDate();
}
// 初始化天數
DateSelector.prototype.InitDaySelect = function()
{
// 使用parseInt函數獲取當前的年份和月份
var year = parseInt(this.selYear.value);
var month = parseInt(this.selMonth.value);
// 獲取當月的天數
var daysInMonth = DateSelector.DaysInMonth(year, month);
// 清空原有的選項
this.selDay.options.length = 0;
// 循環添加OPION元素到天數select對象中
for(var i = 1; i <= daysInMonth ; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到天數select對象
this.selDay.appendChild(op);
}
}
</script>
</head>
<body>
<select id="selYear"></select>
<select id="selMonth"></select>
<select id="selDay"></select>
<script type="text/javascript">
var selYear = window.document.getElementById("selYear");
var selMonth = window.document.getElementById("selMonth");
var selDay = window.document.getElementById("selDay");
// 新建一個DateSelector類的實例,將三個select對象傳進去
new DateSelector(selYear, selMonth ,selDay);
</script>
</body>
</html>
現在已經寫好幾個方法用來初始化三個下拉菜單的選項了,我們需要做的是讓它們結合并動起來。如果年份或月份有變動,那么應該重新計算天數并且重新初始化天數,這可以通過selYear和selMonth的onchange來實現。由于這三個下拉菜單是要緊密聯動的,因此特地給它們增加一個屬性Selector,值為當前的DateSelector實例。同時實現selYear和selMonth的onchange,如果發生onchange則調用InitDaySelect重新初始化selDay下拉菜單。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
this.InitYearSelect();
this.InitMonthSelect();
this.InitDaySelect();
this.selYear.Group = this;
this.selMonth.Group = this;
// 給年份、月份下拉菜單添加處理onchange事件的函數
if(window.document.all != null) // IE
{
this.selYear.attachEvent("onchange", DateSelector.Onchange);
this.selMonth.attachEvent("onchange", DateSelector.Onchange);
}
else // Firefox
{
this.selYear.addEventListener("change", DateSelector.Onchange, false);
this.selMonth.addEventListener("change", DateSelector.Onchange, false);
}
}
// 增加一個最大年份的屬性
DateSelector.prototype.MinYear = 1900;
// 增加一個最大年份的屬性
DateSelector.prototype.MaxYear = (new Date()).getFullYear();
// 初始化年份
DateSelector.prototype.InitYearSelect = function()
{
// 循環添加OPION元素到年份select對象中
for(var i = this.MaxYear; i >= this.MinYear; i--)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到年份select對象
this.selYear.appendChild(op);
}
}
// 初始化月份
DateSelector.prototype.InitMonthSelect = function()
{
// 循環添加OPION元素到月份select對象中
for(var i = 1; i < 13; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到月份select對象
this.selMonth.appendChild(op);
}
}
// 根據年份與月份獲取當月的天數
DateSelector.DaysInMonth = function(year, month)
{
var date = new Date(year, month, 0);
return date.getDate();
}
// 初始化天數
DateSelector.prototype.InitDaySelect = function()
{
// 使用parseInt函數獲取當前的年份和月份
var year = parseInt(this.selYear.value);
var month = parseInt(this.selMonth.value);
// 獲取當月的天數
var daysInMonth = DateSelector.DaysInMonth(year, month);
// 清空原有的選項
this.selDay.options.length = 0;
// 循環添加OPION元素到天數select對象中
for(var i = 1; i <= daysInMonth ; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到天數select對象
this.selDay.appendChild(op);
}
}
// 處理年份和月份onchange事件的方法,它獲取事件來源對象(即selYear或selMonth)
// 并調用它的Group對象(即DateSelector實例,請見構造函數)提供的InitDaySelect方法重新初始化天數
// 參數e為event對象
DateSelector.Onchange = function(e)
{
var selector = window.document.all != null ? e.srcElement : e.target;
selector.Group.InitDaySelect();
}
</script>
</head>
<body>
<select id="selYear"></select>
<select id="selMonth"></select>
<select id="selDay"></select>
<script type="text/javascript">
var selYear = window.document.getElementById("selYear");
var selMonth = window.document.getElementById("selMonth");
var selDay = window.document.getElementById("selDay");
// 新建一個DateSelector類的實例,將三個select對象傳進去
new DateSelector(selYear, selMonth ,selDay);
</script>
</body>
</html>
到此為止我們已經基本實現DateSelector類要提供的功能了,為了更靈活地控制它,我們應該給它增加設定初始值的功能。一般來說有兩種需求,第一種是傳入一個Date對象,第二種是傳入三個值分別表示年、月、日,也就是說我們必須重載構造函數,形式如下:
function DateSelector(selYear, selMonth, selDay)
function DateSelector(selYear, selMonth, selDay, date)
function DateSelector(selYear, selMonth, selDay, year, month, day)
當然,JavaScript沒有重載的概念,但我們可以給它模擬出來,方法就是根據傳入參數的個數(即arguments對象的length)以及類型來判斷,這需要對原有的構造函數進行一定的改動使之更模塊化地實現這三種情況。由于年份和月份是固定不變的,參數只會改變selYear和selMonth的已選選項,而selDay則要根據selYear和selMonth的值再動態生成,因此我們將初始化菜單代碼再提出來寫一個InitSelector方法里,它有三個參數,分別是year, month, day,功能是根據這三個參數來生成相應的菜單選項,我們這次調試使用2004年2月29日為初始值。要設置初始值的時候一般我們會循環訪問option的值,但這里情況特殊,我們是可以根據一定的計算來得到默認選擇的option的下標的。
年份下標 = MaxYear - year
月份下標 = month - 1
天數下標 = day - 1
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>如何實現一個日期下拉菜單</title>
<script type="text/javascript">
function DateSelector(selYear, selMonth, selDay)
{
this.selYear = selYear;
this.selMonth = selMonth;
this.selDay = selDay;
this.selYear.Group = this;
this.selMonth.Group = this;
// 給年份、月份下拉菜單添加處理onchange事件的函數
if(window.document.all != null) // IE
{
this.selYear.attachEvent("onchange", DateSelector.Onchange);
this.selMonth.attachEvent("onchange", DateSelector.Onchange);
}
else // Firefox
{
this.selYear.addEventListener("change", DateSelector.Onchange, false);
this.selMonth.addEventListener("change", DateSelector.Onchange, false);
}
if(arguments.length == 4) // 如果傳入參數個數為4,最后一個參數必須為Date對象
this.InitSelector(arguments[3].getFullYear(), arguments[3].getMonth() + 1, arguments[3].getDate());
else if(arguments.length == 6) // 如果傳入參數個數為6,最后三個參數必須為初始的年月日數值
this.InitSelector(arguments[3], arguments[4], arguments[5]);
else // 默認使用當前日期
{
var dt = new Date();
this.InitSelector(dt.getFullYear(), dt.getMonth() + 1, dt.getDate());
}
}
// 增加一個最大年份的屬性
DateSelector.prototype.MinYear = 1900;
// 增加一個最大年份的屬性
DateSelector.prototype.MaxYear = (new Date()).getFullYear();
// 初始化年份
DateSelector.prototype.InitYearSelect = function()
{
// 循環添加OPION元素到年份select對象中
for(var i = this.MaxYear; i >= this.MinYear; i--)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到年份select對象
this.selYear.appendChild(op);
}
}
// 初始化月份
DateSelector.prototype.InitMonthSelect = function()
{
// 循環添加OPION元素到月份select對象中
for(var i = 1; i < 13; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到月份select對象
this.selMonth.appendChild(op);
}
}
// 根據年份與月份獲取當月的天數
DateSelector.DaysInMonth = function(year, month)
{
var date = new Date(year, month, 0);
return date.getDate();
}
// 初始化天數
DateSelector.prototype.InitDaySelect = function()
{
// 使用parseInt函數獲取當前的年份和月份
var year = parseInt(this.selYear.value);
var month = parseInt(this.selMonth.value);
// 獲取當月的天數
var daysInMonth = DateSelector.DaysInMonth(year, month);
// 清空原有的選項
this.selDay.options.length = 0;
// 循環添加OPION元素到天數select對象中
for(var i = 1; i <= daysInMonth ; i++)
{
// 新建一個OPTION對象
var op = window.document.createElement("OPTION");
// 設置OPTION對象的值
op.value = i;
// 設置OPTION對象的內容
op.innerHTML = i;
// 添加到天數select對象
this.selDay.appendChild(op);
}
}
// 處理年份和月份onchange事件的方法,它獲取事件來源對象(即selYear或selMonth)
// 并調用它的Group對象(即DateSelector實例,請見構造函數)提供的InitDaySelect方法重新初始化天數
// 參數e為event對象
DateSelector.Onchange = function(e)
{
var selector = window.document.all != null ? e.srcElement : e.target;
selector.Group.InitDaySelect();
}
// 根據參數初始化下拉菜單選項
DateSelector.prototype.InitSelector = function(year, month, day)
{
// 由于外部是可以調用這個方法,因此我們在這里也要將selYear和selMonth的選項清空掉
// 另外因為InitDaySelect方法已經有清空天數下拉菜單,因此這里就不用重復工作了
this.selYear.options.length = 0;
this.selMonth.options.length = 0;
// 初始化年、月
this.InitYearSelect();
this.InitMonthSelect();
// 設置年、月初始值
this.selYear.selectedIndex = this.MaxYear - year;
this.selMonth.selectedIndex = month - 1;
// 初始化天數
this.InitDaySelect();
// 設置天數初始值
this.selDay.selectedIndex = day - 1;
}
</script>
</head>
<body>
<select id="selYear"></select>
<select id="selMonth"></select>
<select id="selDay"></select>
<script type="text/javascript">
var selYear = window.document.getElementById("selYear");
var selMonth = window.document.getElementById("selMonth");
var selDay = window.document.getElementById("selDay");
// 新建一個DateSelector類的實例,將三個select對象傳進去
new DateSelector(selYear, selMonth ,selDay, 2004, 2, 29);
// 也可以試試下邊的代碼
// var dt = new Date(2004, 1, 29);
// new DateSelector(selYear, selMonth ,selDay, dt);
</script>
</body>
</html>
好了,日期下拉菜單已經能夠如我們想象的那樣開始工作了,在調用的時候我們只需要執行new DateSelector(selYear, selMonth ,selDay, 2004, 2, 29);就可以,而且它內部關系緊密,你同一個頁面可以同時運行好幾組日期下拉菜單而互不影響,這也是我要采用類的形式而不是采用一組函數來實現的緣由了,我以后寫的文章也會盡可能采用類的形式,這樣寫出來的代碼使用起來會更加方便。像以往一樣,我也得說88啦,希望大家能夠繼續支持無憂腳本的原創文章,并且踴躍參與到其中來。
posted on 2008-10-13 17:50 小卓 閱讀(450) 評論(0) 編輯 收藏 所屬分類: html and js