前言
由于我在一开始很傻的自己刻了日曆,想说版面看起来很简单,但没有考虑到动态互动选择日期的功能,自以为这么简单,自己刻一刻就好,头都洗一半了,只好继续完成,花了一些时间把start date动态互动完成后,由于end date要做的事一模一样,不可能重新写一次,这样太傻了,我想一定可以共用程式码的吧!于是找啊找,恩...原来这叫封装,而且就是套件的原理来着,还好自己似乎没有太笨XD窃喜一下,但...知道要做什么却不见得做得出来,东试试西trytry,已经封到不知道哪去了,可能自己会先疯掉,瞥眼一见,馒头先生到了,用渴望的眼神向他求救,他竟然用闭包解决了我本来卡在constructor绕不出来的窘境,原来这么简单啊!好想跟他的脑交换一下XD
先介绍datePicker功能
起始画面,预设日期为当日calender: 点击日期栏位会跳出Calendar,当日会反底色,其他日期hover后会反底色,标题栏位之左右方箭头可切换月份,标题"March 2024"按下后会跳出另一个可单独选择月份的monthPanelmonthPanel:动态互动效果与calendar类似,中间标题"2024"按下后会跳出另一个可单独选择年份的yearPanel
yearPanel:同理
使用者点击自己欲指定年份,会跳回monthPanel,指定月份后跳回calendar,指定日期后,calendar消失,选取完起始画面的日期必须跟着变动
实作步骤
首先把html跟javascript的程式码并排对照整理程式码,单纯函式不影响,其他程式码就要考虑放的位置是否合适,例如:原本calendar,monthPanel跟yearPanel里与起始画面日期连动的程式码如下,我写在init()之外,其实照理说应该在包在init()中。菜菜如我傻傻不自知,馒头先生就帮我把它整理进去 let dayElement = document.querySelector(`${targetSelector} #dayElement`); dayElement.addEventListener("click", function(event) { if (event.target.className.includes("visible_date")) { datePicked.setDate(event.target.textContent); datePicked.setMonth(state.current.getMonth()); datePicked.setYear(state.current.getFullYear()); showDatePicked(datePicked, datePicker); render(); } }); let monthElement = document.querySelector(`${targetSelector} #monthElement`); monthElement.addEventListener("click", function(event) { if (event.target.className.includes("visible_month")) { let monthOrder = monthAbbreviation.indexOf(event.target.textContent); datePicked.setMonth(monthOrder); datePicked.setYear(state.current.getFullYear()); showDatePicked(datePicked, datePicker); monthChange(monthOrder); render(); } }); let yearElement = document.querySelector(`${targetSelector} #yearElement`); yearElement.addEventListener("click", function(event) { if (event.target.className.includes("visible_year")) { datePicked.setYear(event.target.textContent); showDatePicked(datePicked, datePicker); yearChange(event.target.textContent); render(); } });
确认封装範围,剪下HTML程式码创造函式renderHTML(element)刚才剪下的整串程式码即为renderHTML函式内容 function renderHTML(element){ element.innerHTML = `...刚刚剪下的程式码` }
再来加上下面程式码: const datePickerWrapper = document.querySelector('#datePickerFrom'); renderHTML(datePickerWrapper);
由于datePickerFrom是给start date用的,所以要改成变数,之后才可以再创一个datePickerTo给end date用,于是闭包就登场啦!登登登登登 function componentDatePicker(targetSelector) { function renderHTML (element) { element.innerHTML = `......` } const datePickerWrapper = document.querySelector(targetSelector); renderHTML(datePickerWrapper); }
再来就是呼叫 componentDatePicker("#datePickerFrom"); componentDatePicker("#datePickerTo");
基本上静态的html到此就已经ok了,之后再原封不动的把已完成的javascript程式码也搬到componentDatePicker内容接续在底下,该跟着加上targetSelector的地方记得加上就大功告成啰!举例:原本只有写#previousMonth,前面要加上${targetSelector}才能找到在targetSelector底下的dom element const previousMonth = document.querySelector(`${targetSelector} #previousMonth`) previousMonth.addEventListener('click', function() { state.current.setMonth(state.current.getMonth() - 1); render(); })
大致实作步骤就介绍到这里,讲个概念,也许有需要的人应该能有一点灵感,整包太繁杂就不放了。封装完成后,成就感满满ㄚ!太感动了
参考资料
可敬的馒头先生脑XD