想要实现的效果
实现思路
为了组件的可复用性,需要用面向对象的思想。
每个日历组件都是一个日历对象,主要包括日期选择框,日期控制显示栏,还有日历格子,为了保持日期控制显示栏和日历格子日期同步变化,日期控制栏和日历里面的每个格子都应该包含一个Date属性,点击日历里的格子,将格子存的Date属性作为函数参数,调用函数改变日期控制栏显示的时间。同理,日期控制栏时间变化时,也将Date属性作为参数调用函数,函数重新绘制日历格子。
上码:
function Calendar(parentId) { this.parentElement = document.getElementById(parentId); this.init(); } Calendar.prototype = { init: function() { this.contains = document.createElement("div"); this.contains.onselectstart = function(){return false}; //让按钮点击时不会出现文字被选中的蓝色块 this.dateInput = document.createElement("input"); this.datePicker = document.createElement("div"); this.showDateBar = document.createElement("div"); this.dateBox = document.createElement("div"); this.icon = document.createElement("i"); this.contains.className = 'datepicker-container'; this.dateInput.className = 'date-input'; this.dateInput.readOnly = true; var parent = this; this.dateInput.onclick = function(event){ parent.onDateInputClick(event); //点击日期选择框时显示日历格子 }; this.contains.onblur = function(){ parent.datePicker.style.display = 'none'; } this.datePicker.className = 'date-picker'; this.datePicker.style.display = 'none'; this.showDateBar.className = 'show-date'; this.dateBox.className = 'date-box'; this.icon.className = 'date-icon'; this.icon.innerHTML = '\'; //iconfont这里用的阿里图标,可以自行替换 this.datePicker.appendChild(this.showDateBar); this.datePicker.appendChild(this.dateBox); this.contains.appendChild(this.dateInput); this.contains.appendChild(this.icon); this.contains.appendChild(this.datePicker); this.parentElement.appendChild(this.contains); }, }
初始化日期控制栏:
drawShowDateBar: function(parentElement){ var parent = this; var nowDate = new Date(); parentElement.date = nowDate; var nowYear = nowDate.getFullYear(); var nowMonth = nowDate.getMonth(); var nowDay = nowDate.getDate(); //showDateBar内容拼接 var contentStr ='<div class="year-input"><span>'+nowYear+'年</span><i class="select-year-btn">Z</i><ul class="year-select-box" style="display : none">'; for(var i=0;i<150;i++){ contentStr+='<li>'+(i+1900)+'年</li>'; } contentStr+='</ul></div>' +'<div class="month-input"><i class="prev-month">[</i><select class="months-options">' for(var i=0;i<12;i++){ contentStr+='<option>'+(i+1)+'月</option>'; } contentStr+='</select><i class="next-month">\</i></div>' +'<div class="day-input"><i class="prev-day">[</i><select class="days-options"></select>' +'<i class="next-day">\</i></div>' +'<button class="today-btn">今天</button>' +'<div class="days-title">'; var weekday = ['日', '一', '二', '三', '四', '五', '六']; for (var i = 0; i < 7; i++) { contentStr+='<span class="day-title">'+weekday[i]+'</span>'; } contentStr+='</div>'; parentElement.innerHTML = contentStr; this.changeShowDateBar(nowDate); //插入到showTimeBar之后,初始化,传入的参数是现在的时间 var yearInput = parentElement.firstChild; //年选择框点击显示和隐藏选择列表 yearInput.onclick = function(){ //target和this的区别 target是触发事件的元素,this是处理事件的元素 var ul = this.lastChild; ul.style.display==='none'||ul.style.display==='none'? ul.style.display='inline-block':ul.style.display='none'; }; //为年选择下拉框绑定点击事件 var yearSelectBox = yearInput.lastChild; var yearLi = yearSelectBox.children; for(var i=0;i<yearLi.length;i++){ yearLi[i].onclick = function(){ parent.showDateBar.date.setFullYear(this.innerText.slice(0,-1)); parent.changeShowDateBar(parent.showDateBar.date); //时间改变之后都要重新调用,因为不同年,不同月,某个月的天数不全一样 }; } //为month的前后按钮添加点击事件 var monthInput = yearInput.nextSibling; monthInput.firstChild.onclick = function(){ var monthOptions = this.nextSibling; if(monthOptions.selectedIndex>0){ parent.showDateBar.date.setMonth(--monthOptions.selectedIndex); }else{ monthOptions.selectedIndex = 11; parent.showDateBar.date.setFullYear(parent.showDateBar.date.getFullYear()-1); parent.showDateBar.date.setMonth(11); } parent.changeShowDateBar(parent.showDateBar.date); }; monthInput.lastChild.onclick = function(){ var monthOptions = this.previousSibling; if(monthOptions.selectedIndex<11){ parent.showDateBar.date.setMonth(++monthOptions.selectedIndex); }else{ monthOptions.selectedIndex = 0; parent.showDateBar.date.setFullYear(parent.showDateBar.date.getFullYear()+1); parent.showDateBar.date.setMonth(0); } parent.changeShowDateBar(parent.showDateBar.date); } monthInput.children[1].onchange = function(){ parent.showDateBar.date.setMonth(this.selectedIndex); parent.changeShowDateBar(parent.showDateBar.date) }; //为day的前后按钮添加点击事件 var dayInput = monthInput.nextSibling; dayInput.firstChild.onclick = function(){ var dayOptions = this.nextSibling; if(dayOptions.selectedIndex>0){ parent.showDateBar.date.setDate(dayOptions.selectedIndex--); }else{ parent.showDateBar.date.setMonth(parent.showDateBar.date.getMonth()-1); parent.showDateBar.date.setDate(parent.getDaysOfMonth(parent.showDateBar.date)); } parent.changeShowDateBar(parent.showDateBar.date); }; dayInput.lastChild.onclick = function(){ var dayOptions = this.previousSibling; if(dayOptions.selectedIndex < dayOptions.length-1){ dayOptions.selectedIndex++; parent.showDateBar.date.setDate(dayOptions.selectedIndex+1); }else{ parent.showDateBar.date.setDate(1); parent.showDateBar.date.setMonth(parent.showDateBar.date.getMonth()+1); } parent.changeShowDateBar(parent.showDateBar.date); }; dayInput.children[1].onchange = function(){ parent.showDateBar.date.setDate(this.selectedIndex+1); parent.changeShowDateBar(parent.showDateBar.date) }; //为今天按钮绑定点击事件 var todayBtn = dayInput.nextSibling; todayBtn.onclick = function(){ parent.drawPicker(new Date()); parent.changeShowDateBar(new Date()); } },
drawShowDateBar函数为日期控制栏的年份、月份、和天的点击按钮设置了点击事件处理函数。还有选择下拉框变化的处理函数。
在日期控制栏初始化时,或者改变showDateBar的Date时,都会调用changeShowDateBar 函数。这个函数主要根据传入的日期改变日期控制栏“日”下拉栏的天数,因为每个月的天数不尽相同,所以要根据传入的日期来改变。会计算出传入的日期对应的月份有多少天,使用getDaysOfMonth函数计算。
//计算一个月的天数 getDaysOfMonth: function(primalDate) { var date = new Date(primalDate); //要新建一个对象,因为会改变date var month = date.getMonth(); var time = date.getTime(); //计算思路主要是month+1,相减除一天的毫秒数 var newTime = date.setMonth(month + 1); return Math.ceil((newTime - time) / (24 * 60 * 60 * 1000)); },
changeShowDateBar : function(date){ var yearInput = this.showDateBar.firstChild; var monthInput = yearInput.nextSibling; var dayInput = monthInput.nextSibling; yearInput.firstChild.innerText = date.getFullYear()+'年'; var monthsOptions = monthInput.firstChild.nextSibling; monthsOptions.selectedIndex = date.getMonth(); var daysOptions = dayInput.firstChild.nextSibling; var days = this.getDaysOfMonth(date); var dayStr = ''; for(var i=1;i<=days;i++){ dayStr+='<option>'+i+'日</option>'; } daysOptions.innerHTML = dayStr; // console.log(date.toLocaleDateString()+'changeShowDateBar'); daysOptions.selectedIndex = date.getDate()-1; this.drawPicker(date); },
在日期控制栏的Date变化后,日历格子的日期也应该要改变,显示的日期要和日期控制栏的保持一致。所以在changeShowDateBar函数结尾处调用drawPicker函数,重新绘制日历格子。
绘制日历格子的思路
drawPicker函数要根据传入的日期绘制日历格子。
drawPicker函数:
drawPicker: function(primalDate) { var date = new Date(primalDate); //要新建一个对象,因为会改变date var nowMonth = date.getMonth()+1; var nowDate = date.getDate(); var spanContainer = []; var dateBox = this.dateBox; dateBox.innerHTML = ''; var time = date.getTime(); var days = this.getDaysOfMonth(date); //计算出这个月的天数 date.setDate(1); //将date的日期设置为1号 var firstDay = date.getDay(); //知道这个月1号是星期几 for (var i = 0; i < firstDay; i++) { //如果1号不是周日(一周的开头),则在1号之前要补全 var tempDate = new Date(date); tempDate.setDate(i - firstDay + 1); var span = document.createElement("span"); span.className = "unshow"; spanContainer.push({span : span, date : tempDate}); } for (var i = 1; i <= days; i++) { //1号到这个月最后1天 var span = document.createElement("span"); span.className = 'show'; spanContainer.push({span : span, date : new Date(date)}); date.setDate(i + 1); } for (var i = date.getDay(); i <= 6; i++) { //在这个月最后一天后面补全 var span = document.createElement("span"); span.className = "unshow"; spanContainer.push({span : span, date : new Date(date)}); date.setDate(date.getDate()+1); } for(var i=0;i<spanContainer.length;i++){ var spanBox = spanContainer[i]; var span = spanBox.span; span.year = spanBox.date.getFullYear(); //为每个span元素添加表示时间的属性 span.month = spanBox.date.getMonth() + 1; span.date = spanBox.date.getDate(); span.innerText = spanBox.date.getDate(); if(span.date === nowDate&&span.month === nowMonth) //如果这个span的日期为与传入的日期匹配,设置类名为select span.className+=" select"; var parent = this; span.onclick = function(){ //设置点击事件 var target = event.target; var selected = target.parentElement.getElementsByClassName("select"); for(var i=0 ;i<selected.length;i++){ selected[i].className = selected[i].className.replace(" select",""); }; target.className+=" select"; parent.changeDate(target.year, target.month, target.date); parent.changeShowDateBar(new Date(target.year, target.month-1, target.date)); }; dateBox.appendChild(span); //将span添加到dateBox中 } this.changeDate(primalDate.getFullYear(), primalDate.getMonth()+1, primalDate.getDate()) return; },
//日期框点击时显示日历 onDateInputClick: function(event) { var target = event.target; var value = target.value; var datePicker = this.datePicker; if(datePicker.style.display==='none'){ //这里必须要在js文件里将datePicker.style.display设置为none,如果是在css文件里设置为none,得到的display为"" datePicker.style.display = 'block'; }else{ datePicker.style.display = 'none'; return; } if (!value) this.drawShowDateBar(this.showDateBar); //绘制日历的显示栏 }, changeDate : function(year, month, date){ this.dateInput.value = year+"-"+(month<10?("0"+month):month)+"-"+(date<10?("0"+date):date); },
实现效果
有点丑......
实现中遇到的问题
用到的Date API
项目源码 https://github.com/wenkeShi/js-calendar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍原生js制作日历控件实例分享,包括了原生js制作日历控件实例分享的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了js实现一个简单的日历控件,供大家参考,具体内容如下 效果图: 具体代码: 希望本文所述对大家学习javascript程序设计有所帮助。
本文向大家介绍原生JavaScript实现日历功能代码实例(无引用Jq),包括了原生JavaScript实现日历功能代码实例(无引用Jq)的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了原生JavaScript实现日历功能代码实例(无引用Jq),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 成品显示,可左右切换月份 html 代码 c
本文向大家介绍原生JS实现左右箭头选择日期实例代码,包括了原生JS实现左右箭头选择日期实例代码的使用技巧和注意事项,需要的朋友参考一下 先上个效果图,就是用左右尖括号可改变中间日期的值。(点击中间显示区域有时间选择器弹框,用的插件就不说了,主要说自己原创的部分)
本文向大家介绍Vue结合原生js实现自定义组件自动生成示例,包括了Vue结合原生js实现自定义组件自动生成示例的使用技巧和注意事项,需要的朋友参考一下 就目前三大前端主流数据驱动框架(vue,ng,react)而言,均具有创建自定义组件的api,但都是必须先做到事先写好挂载点,这个挂载点可以是原有静态元素标签也可以是自定义模板;对于多种组件通过同一数据流生成的,如果事先在页面上写好挂载点(moun
本文向大家介绍原生js实现移动端瀑布流式代码示例,包括了原生js实现移动端瀑布流式代码示例的使用技巧和注意事项,需要的朋友参考一下 瀑布流布局已成为当今非常普遍的图片展示方式,无论是PC还是手机等移动设备上。最近使用到了“懒加载”,现在更新一般,因为平时主要使移动端的开发所以库文件使用的是zepto.js 。当然也可以和jQuery 通用。 代码如下: 以上所述就是本文给大家分享的全部内容了,希望
本文向大家介绍原生JS实现的放大镜效果实例代码,包括了原生JS实现的放大镜效果实例代码的使用技巧和注意事项,需要的朋友参考一下 这是我用原生js写的放大镜效果,与各种各样的框架技术相比,我喜欢使用原生的js,在这里,想和大家一起谈谈原生和框架技术的理解与个人喜好。 以上所述是小编给大家介绍的原生JS实现的放大镜效果实例代码,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,
本文向大家介绍原生js实现日期选择插件,包括了原生js实现日期选择插件的使用技巧和注意事项,需要的朋友参考一下 最近公司项目告一段落,想着写个小玩意打发下上班时间,就用js很粗糙的实现了下日期选择插件。间间断断历时1天多,实现了选择日期的功能,从写完的整体代码来看,耦合度还是蛮高的,我觉得还是我对js中的原型继承方式理解不深刻,一定有更优雅的方式再优化下这份粗糙的代码,各位前端小伙伴们在看完我的代
本文向大家介绍Java JTable 实现日历的示例,包括了Java JTable 实现日历的示例的使用技巧和注意事项,需要的朋友参考一下 效果图: 主要思想:日历最核心的功能就是能显示某年某月对应的日期和星期几。因此只要实现传入具体的年份和月份,得到一组存放了日期的数组a[ ]即可。其中数组的大小设置成42,要考虑的问题是当月的第一天对应星期几。日期数组中的前七个,肯定包含了当月的第一天,把这一