首先声明一下,这个插件的原创作者是 MoBinni
GITHUB地址请访问:https://github.com/mobinni/material-date-picker
(function() { 'use strict'; /** * By Mo Binni */ var app, contains; app = angular.module('materialDatePicker', []); contains = function(container, contained) { var node; node = contained.parentNode; while (node !== null && node !== container) { node = node.parentNode; } return node !== null; }; app.directive("outsideClick", [ '$document', '$parse', function($document, $parse) { return { link: function($scope, $element, $attributes) { var onDocumentClick, scopeExpression; scopeExpression = $attributes.outsideClick; onDocumentClick = function(event) { if (!contains($element[0], event.target)) { $scope.$apply(scopeExpression); } }; $document.on("click", onDocumentClick); $element.on("$destroy", function() { $document.off("click", onDocumentClick); }); } }; } ]); app.directive('mbDatepicker', [ '$filter', function($filter) { return { scope: { elementId: '@', date: '=', dateFormat: '@', minDate: '@', maxDate: '@', inputClass: '@', inputName: '@', placeholder: '@', arrows: '=?', calendarHeader: '=?', utcMode: '=', ngDisabled: '=', label: '@', customInputClass: '@', rightclass: '=', // previousMonth:'@' }, template: '<div id="dateSelectors" class="date-selectors" outside-click="hidePicker()" style="display:inline-block;"> <label ng-bind="label" class="mb-input-label" for="{{inputName}}"></label> <input name="{{ inputName }}" type="text" ng-disabled="{{ngDisabled}}" ng-class="{disabled: ngDisabled}" class="mb-input-field {{customInputClass}}" ng-click="showPicker()" class="form-control" id="{{inputName}}" ng-model="date" placeholder="{{ placeholder }}" style="font-size: 14px"> <div class="mb-datepicker" ng-show="isVisible"> <table> <caption> <div class="header-year-wrapper"> <span style="display: inline-block; float: left; padding-left:20px; cursor: pointer" class="noselect" ng-click="previousYear(currentDate)"><img style="height: 10px;" ng-src="{{ arrows.year.left }}"/></span> <span class="header-year noselect" ng-class="noselect">{{ year }}</span> <span style="display: inline-block; float: right; padding-right:20px; cursor: pointer" class="noselect" ng-click="nextYear(currentDate)"><img style="height: 10px;" ng-src="{{ arrows.year.right }}"/></span> </div> <div ng-hide="onlyMonth" class="header-nav-wrapper"> <span class="header-item noselect" style="float: left; cursor:pointer" ng-click="previousMonth(currentDate)"><img style="height: 10px;" ng-src="{{ arrows.month.left }}"/></span> <span class="header-month noselect">{{ month }}</span> <span class="header-item header-right noselect" style="float: right; cursor:pointer" ng-click="nextMonth(currentDate)"> <img style="height: 10px;" ng-src="{{ arrows.month.right }}"/></span> </div> </caption> <tbody><tr ng-show="onlyMonth" class="days" ng-repeat="week in months"> <td ng-click="selectMonth(day)" class="noselect" ng-class="::day.class" ng-repeat="day in week" style="width: 50px;text-align: center"><div style="display: block;" ng-class="{selected: selectedDate === day.selected}"> {{ ::day}} </div> </td></tr><tr ng-hide="onlyMonth"><td class="day-head">{{ ::calendarHeader.monday }}</td> <td class="day-head">{{ ::calendarHeader.tuesday }}</td><td class="day-head">{{ ::calendarHeader.wednesday }}</td> <td class="day-head">{{ ::calendarHeader.thursday }}</td> <td class="day-head">{{ ::calendarHeader.friday }}</td> <td class="day-head">{{ ::calendarHeader.saturday }}</td><td class="day-head">{{ ::calendarHeader.sunday }}</td> </tr> <tr ng-hide="onlyMonth" class="days" ng-repeat="week in weeks"> <td ng-click="selectDate(day)" class="noselect" ng-class="::day.class" ng-repeat="day in week"><div style="display: block;" ng-class="{selected: selectedDate === day.selected}"> {{ ::day.value }} </div> </td> </tr></tbody></table> </div> </div>', restrict: 'E', transclude: true, link: function(scope, element, attrs) { if(attrs.startDate){ var formatStartTime; if (attrs.runTo) { formatStartTime = util.getFormatDate().year + '-' + util.getFormatDate().moth + '-' + util.getFormatDate().day; } else { formatStartTime = util.getFormatDate().year + '-' + util.getFormatDate().moth + '-' + '01'; } scope.date = formatStartTime } if(attrs.endDate){ var formatendTime = util.getFormatDate().year + '-' + util.getFormatDate().moth + '-' + util.getFormatDate().day scope.date = formatendTime } var getWeeks, init, selectors, today; selectors = document.querySelector('#dateSelectors'); today = moment(); if (scope.utcMode) { today.utc(); } scope.month = ''; scope.year = today.year(); if (scope.inputClass) { selectors.className = selectors.className + " " + scope.inputClass; } if (!scope.dateFormat) { scope.dateFormat = "YYYY-MM-DD"; } if (scope.minDate) { scope.minDate = moment(scope.minDate, scope.dateFormat); if (scope.utcMode) { scope.minDate.utc(); } } if (scope.maxDate) { scope.maxDate = moment(scope.maxDate, scope.dateFormat); if (scope.utcMode) { scope.maxDate.utc(); } } if (!scope.calendarHeader) { scope.calendarHeader = { monday: $filter('date')(new Date(moment().isoWeekday(1)), 'EEE'), tuesday: $filter('date')(new Date(moment().isoWeekday(2)), 'EEE'), wednesday: $filter('date')(new Date(moment().isoWeekday(3)), 'EEE'), thursday: $filter('date')(new Date(moment().isoWeekday(4)), 'EEE'), friday: $filter('date')(new Date(moment().isoWeekday(5)), 'EEE'), saturday: $filter('date')(new Date(moment().isoWeekday(6)), 'EEE'), sunday: $filter('date')(new Date(moment().isoWeekday(7)), 'EEE') }; } if (!scope.arrows) { scope.arrows = { year: { left: '../images/svg/white_arrow_left.svg', right: '../images/svg/white_arrow_right.svg' }, month: { left: '../images/svg/grey_arrow_left.svg', right: '../images/svg/grey_arrow_right.svg' } }; } function formateMonth(obj){ if(obj){ return obj.slice(0,-1); } } //月份选择 if(attrs.onlyMonth){ scope.onlyMonth=true; scope.arrows = { year: { left: '../images/svg/grey_arrow_left.svg', right: '../images/svg/grey_arrow_right.svg' }, }; scope.months=[{"day":"1月","day1":"2月","day2":"3月"},{"day":"4月","day1":"5月","day2":"6月"},{"day":"7月","day1":"8月","day2":"9月"},{"day":"10月","day1":"11月","day2":"12月"}]; scope.selectMonth = function(day) { if(day){ day=formateMonth(day) if(day<10) day='0'+day; scope.date = scope.year+'-'+day; return scope.isVisible = false; } return }; }else{ scope.onlyMonth=false; } getWeeks = function(monthLength, startDay, month) { var chunk_size, day, j, monthDays, newDate, ref, start, weeks; monthDays = []; for (day = j = 0, ref = monthLength; 0 <= ref ? j <= ref : j >= ref; day = 0 <= ref ? ++j : --j) { start = moment(startDay); if (scope.utcMode) { start.utc(); } newDate = start.add(day, 'd'); day = { date: newDate, value: newDate.format('DD') }; if (scope.minDate && moment(newDate, scope.dateFormat) <= moment(scope.minDate, scope.dateFormat)) { day.isToday = true; day.isEnabled = false; day["class"] = 'disabled'; monthDays.push(day); } else if (scope.maxDate && moment(newDate, scope.dateFormat) >= moment(scope.maxDate, scope.dateFormat)) { day.isToday = true; day.isEnabled = false; day["class"] = 'disabled'; } else if (newDate.format(scope.dateFormat) === moment().format(scope.dateFormat)) { day.isToday = true; day.isEnabled = true; day["class"] = 'day-item today'; } else if (newDate.month() === month) { day.isToday = false; day.isEnabled = true; day["class"] = 'day-item day'; } else if (newDate.day() === 0 || newDate.day() === 6) { day.isToday = false; day.isEnabled = true; day["class"] = 'day-item weekend'; } else { day.isToday = false; day.isEnabled = true; day["class"] = 'day-item'; } monthDays.push(day); } chunk_size = 7; weeks = monthDays.map(function(e, i) { if (i % chunk_size === 0) { return monthDays.slice(i, i + chunk_size); } else { return null; } }).filter(function(e) { return e; }); if (weeks) { return weeks; } else { return []; } }; scope.nextMonth = function(date) { var first_day, last_day, next_month; next_month = moment(date).date(0); last_day = moment(next_month).add(4, 'months').date(0); scope.year = last_day.year(); if (last_day.day() !== 7) { last_day = last_day.add(7 - last_day.day(), 'days'); } first_day = moment(next_month).add(2, 'months').startOf('isoweek'); scope.currentDate = first_day; scope.weeks = []; scope.weeks = getWeeks(last_day.diff(first_day, 'days'), first_day, next_month.add(3, 'months').month()); return scope.month = $filter('date')(new Date(next_month), 'MMM'); }; scope.previousMonth = function(date) { var first_day, last_day, last_month; last_month = moment(date).date(0); last_day = moment(last_month).add(2, 'months').date(0); scope.year = last_day.year(); if (last_day.day() !== 7) { last_day = last_day.add(7 - last_day.day(), 'days'); } first_day = moment(last_month).startOf('isoweek'); scope.currentDate = first_day; scope.weeks = []; scope.weeks = getWeeks(last_day.diff(first_day, 'days'), first_day, last_month.add(1, 'months').month()); return scope.month = $filter('date')(new Date(last_month), 'MMM'); }; scope.nextYear = function(date) { var first_day, last_day, next_month; next_month = moment(date).date(0); last_day = moment(next_month).add(1, 'year').add(3, 'months').date(0); scope.year = last_day.year(); if (last_day.day() !== 7) { last_day = last_day.add(7 - last_day.day(), 'days'); } first_day = moment(next_month).add(1, 'years').add(1, 'months').startOf('isoweek'); scope.currentDate = first_day; scope.weeks = []; scope.weeks = getWeeks(last_day.diff(first_day, 'days'), first_day, next_month.add(2, 'months').month()); return scope.month = $filter('date')(new Date(next_month), 'MMM'); }; scope.previousYear = function(date) { var first_day, last_day, last_month; last_month = moment(date).date(0); last_day = moment(last_month).subtract(1, 'years').add(3, 'months').date(0); scope.year = last_day.year(); if (last_day.day() !== 7) { last_day = last_day.add(7 - last_day.day(), 'days'); } first_day = moment(last_month).subtract(1, 'years').add(1, 'months').startOf('isoweek'); scope.currentDate = first_day; scope.weeks = []; scope.weeks = getWeeks(last_day.diff(first_day, 'days'), first_day, last_month.add(2, 'months').month()); return scope.month = $filter('date')(new Date(last_month), 'MMM'); }; scope.selectDate = function(day) { if (day.isEnabled) { scope.date = day.date.format(scope.dateFormat); // if (day.selected === scope.date) { scope.selectedDate = day.selected; // } } return scope.isVisible = false; }; //获取标签内的默认时间 if(attrs.nowDate){ scope.runMonth= attrs.value+'-01' } scope.isVisible = false; scope.showPicker = function() { //初始化的时候加载到默认时间 if(scope.runMonth){ scope.previousMonth(attrs.value); } scope.date = ""; scope.isVisible = true; if(scope.rightclass){ $('#dateSelectors .mb-datepicker').css('right','0px'); }else{ $('#dateSelectors .mb-datepicker').removeAttr('style'); } }; scope.hidePicker = function() { scope.isVisible = false; }; init = function() { var days, endDate, firstMonday; if (scope.utcMode) { firstMonday = moment.utc(moment.utc().date(1)).startOf('isoweek'); } else { firstMonday = moment(moment().date(1)).startOf('isoweek'); } if (firstMonday.date() === 1) { firstMonday.subtract(1, 'weeks'); } days = moment(moment().date(today.month())).daysInMonth(); endDate = moment().add(1, 'months').date(0); scope.month = $filter('date')(new Date(endDate), 'MMM'); if (endDate.day() !== 7) { endDate = endDate.add(7 - endDate.day(), 'days'); } scope.currentDate = firstMonday; return scope.weeks = getWeeks(endDate.diff(firstMonday, 'days'), firstMonday, today.month()); }; return init(); } }; } ]); }).call(this);说明:使用方法:
<mb-datepicker id="startTime" input-class="form-control input-medium input-item" calendar-header="header" only-month="true"></mb-datepicker>
这个自定义指令,主要是依赖于 attrs的属性和link方法进行关联。 only-month 这个属性存在时,执行的是日期选择的逻辑。当需求是显示年月的时候,可以组件标签上增加这个属性,如果需求是展示年月日的时候,这个属性直接不写就可以。
<mb-datepicker id="time_accounting" input-class="form-control input-medium input-item input-item-width180 no-padding" calendar-header="header" date-format="YYYY-MM-DD" now-date="true" value={{nowvalue}}></mb-datepicker>now-date 属性为true的时候,此功能是要触发日历的时候,自动定位到某个月份,具体的月份值存在 value的属性上,可以通过attrs.value来进行获取。
如果还需要进行选择范围的设定:比如选择日期只能选择某个月份,超出会提示。只需要定位到某个月份的时候,当文本框失去焦点的时候,对选择的内容进行截取,对比年月,如果不是统一月份就提示。
(、、、、编辑器粘代码比较乱,只提供个思路。谅解。。。有错误请指正。)