仿Angular Bootstrap TimePicker创建分钟数-秒数的输入控件_AngularJS_脚本之家

 app.controller('minuteSecondPickerController', ['$scope', '$attrs', '$parse', 'minuteSecondPickerConfig', function($scope, $attrs, $parse, minuteSecondPickerConfig) { ...}]); 

init方法接受的第二个参数是inputs,在link函数中传入的是:element.find。
所以第一个输入框用来输入分钟,第二个输入框用来输入秒。然后,检查是否覆盖了mousewheel属性,如果没有覆盖则使用在constant中设置的默认mousewheel,并进行相关设置如下:

在一个项目中需要一个用来输入分钟数和秒数的控件,然而调查了一些开源项目后并未发现合适的控件。在Angular
Bootstrap
UI中有一个类似的控件TimePicker,但是它并没有深入到分钟和秒的精度。因此,决定参考它的源码然后自己进行实现。最终的效果如下:

 app.directive('minuteSecondPicker', function() { return { restrict: 'EA', require: ['minuteSecondPicker', '?^ngModel'], controller: 'minuteSecondPickerController', replace: true, scope: { validity: '=' }, templateUrl: 'partials/directives/minuteSecondPicker.html', link: function(scope, element, attrs, ctrls) { var minuteSecondPickerCtrl = ctrls[0], ngModelCtrl = ctrls[1]; if { minuteSecondPickerCtrl.init(ngModelCtrl, element.find; 

在以上的link函数中,ctrls是一个数组:
ctrls[0]是定义在本directive上的controller实例,ctrls[1]是ngModelCtrl,即ng-model对应的controller实例。这个顺序实际上是通过require:
[‘minuteSecondPicker’,
‘?^ngModel’]定义的。注意到第一个依赖就是directive本身的名字,此时会将该directive中controller声明的对应实例传入。第二个依赖的写法有些奇怪:”?^ngModel”,?的含义是即使没有找到该依赖,也不要抛出异常,即该依赖是一个可选项。^的含义是查找父元素的controller。然后,定义该directive中用到的一些默认设置,通过constant
directive实现:

首先是该directive的定义:

紧接着是directive对应的controller,它的声明如下:

// respond on direct input this.setupInputEvents = function(minutesInputEl, secondsInputEl) { if { $scope.updateMinutes = angular.noop; $scope.updateSeconds = angular.noop; return; } var invalidate = function(invalidMinutes, invalidSeconds) { ngModelCtrl.$setViewValue; ngModelCtrl.$setValidity; $scope.validity = false; if(angular.isDefined { $scope.invalidMinutes = invalidMinutes; } if(angular.isDefined { $scope.invalidSeconds = invalidSeconds; } }; $scope.updateMinutes = function() { var minutes = getMinutesFromTemplate(); if(angular.isDefined { selected.minutes = minutes; refresh; } else { invalidate; } }; minutesInputEl.bind { if(!$scope.invalidMinutes && $scope.minutes < 10) { $scope.$apply { $scope.minutes = pad; } }); $scope.updateSeconds = function() { var seconds = getSecondsFromTemplate(); if(angular.isDefined { selected.seconds = seconds; refresh; } else { invalidate; } }; secondsInputEl.bind { if(!$scope.invalidSeconds && $scope.seconds < 10) { $scope.$apply { $scope.seconds = pad; } }); }; 

在directive的link函数中,调用了此controller的init方法:

 this.init = function { ngModelCtrl = ngModelCtrl_; ngModelCtrl.$render = this.render; var minutesInputEl = inputs.eq, secondsInputEl = inputs.eq; var mousewheel = angular.isDefined ? $scope.$parent.$eval : minuteSecondPickerConfig.mousewheel; if { this.setupMousewheelEvents(minutesInputEl, secondsInputEl); } $scope.readonlyInput = angular.isDefined ? $scope.$parent.$eval : minuteSecondPickerConfig.readonlyInput; this.setupInputEvents(minutesInputEl, secondsInputEl); }; 

init方法最后会对inputs本身进行一些设置:

app.constant('minuteSecondPickerConfig', { minuteStep: 1, secondStep: 1, readonlyInput: false, mousewheel: true}); 
// respond on mousewheel spin this.setupMousewheelEvents = function(minutesInputEl, secondsInputEl) { var isScrollingUp = function { if { e = e.originalEvent; } // pick correct delta variable depending on event var delta =  ? e.wheelData : -e.deltaY; return (e.detail || delta > 0); }; minutesInputEl.bind('mousewheel wheel', function { $scope.$apply ? $scope.incrementMinutes() : $scope.decrementMinutes; e.preventDefault; secondsInputEl.bind('mousewheel wheel', function { $scope.$apply ? $scope.incrementSeconds() : $scope.decrementSeconds; e.preventDefault; }; 

此方法中,声明了用于设置输入非法的invalidate函数,它会在scope中暴露一个validity

false属性让页面有机会做出合适的反应。如果用户使用了一个变量来表示minuteStep或者secondStep,那么还需要设置相应的watchers:

var minuteStep = minuteSecondPickerConfig.minuteStep; if { $scope.parent.$watch($parse, function { minuteStep = parseInt; } var secondStep = minuteSecondPickerConfig.secondStep; if { $scope.parent.$watch($parse, function { secondStep = parseInt; } 

完整的directive实现代码如下:

var app = angular.module("minuteSecondPickerDemo");app.directive('minuteSecondPicker', function() { return { restrict: 'EA', require: ['minuteSecondPicker', '?^ngModel'], controller: 'minuteSecondPickerController', replace: true, scope: { validity: '=' }, templateUrl: 'partials/directives/minuteSecondPicker.html', link: function(scope, element, attrs, ctrls) { var minuteSecondPickerCtrl = ctrls[0], ngModelCtrl = ctrls[1]; if { minuteSecondPickerCtrl.init(ngModelCtrl, element.find;app.constant('minuteSecondPickerConfig', { minuteStep: 1, secondStep: 1, readonlyInput: false, mousewheel: true});app.controller('minuteSecondPickerController', ['$scope', '$attrs', '$parse', 'minuteSecondPickerConfig', function($scope, $attrs, $parse, minuteSecondPickerConfig) { var selected = { minutes: 0, seconds: 0 }, ngModelCtrl = { $setViewValue: angular.noop }; this.init = function { ngModelCtrl = ngModelCtrl_; ngModelCtrl.$render = this.render; var minutesInputEl = inputs.eq, secondsInputEl = inputs.eq; var mousewheel = angular.isDefined ? $scope.$parent.$eval : minuteSecondPickerConfig.mousewheel; if { this.setupMousewheelEvents(minutesInputEl, secondsInputEl); } $scope.readonlyInput = angular.isDefined ? $scope.$parent.$eval : minuteSecondPickerConfig.readonlyInput; this.setupInputEvents(minutesInputEl, secondsInputEl); }; var minuteStep = minuteSecondPickerConfig.minuteStep; if { $scope.parent.$watch($parse, function { minuteStep = parseInt; } var secondStep = minuteSecondPickerConfig.secondStep; if { $scope.parent.$watch($parse, function { secondStep = parseInt; } // respond on mousewheel spin this.setupMousewheelEvents = function(minutesInputEl, secondsInputEl) { var isScrollingUp = function { if { e = e.originalEvent; } // pick correct delta variable depending on event var delta =  ? e.wheelData : -e.deltaY; return (e.detail || delta > 0); }; minutesInputEl.bind('mousewheel wheel', function { $scope.$apply ? $scope.incrementMinutes() : $scope.decrementMinutes; e.preventDefault; secondsInputEl.bind('mousewheel wheel', function { $scope.$apply ? $scope.incrementSeconds() : $scope.decrementSeconds; e.preventDefault; }; // respond on direct input this.setupInputEvents = function(minutesInputEl, secondsInputEl) { if { $scope.updateMinutes = angular.noop; $scope.updateSeconds = angular.noop; return; } var invalidate = function(invalidMinutes, invalidSeconds) { ngModelCtrl.$setViewValue; ngModelCtrl.$setValidity; $scope.validity = false; if(angular.isDefined { $scope.invalidMinutes = invalidMinutes; } if(angular.isDefined { $scope.invalidSeconds = invalidSeconds; } }; $scope.updateMinutes = function() { var minutes = getMinutesFromTemplate(); if(angular.isDefined { selected.minutes = minutes; refresh; } else { invalidate; } }; minutesInputEl.bind { if(!$scope.invalidMinutes && $scope.minutes < 10) { $scope.$apply { $scope.minutes = pad; } }); $scope.updateSeconds = function() { var seconds = getSecondsFromTemplate(); if(angular.isDefined { selected.seconds = seconds; refresh; } else { invalidate; } }; secondsInputEl.bind { if(!$scope.invalidSeconds && $scope.seconds < 10) { $scope.$apply { $scope.seconds = pad; } }); }; this.render = function() { var time = ngModelCtrl.$modelValue ? { minutes: ngModelCtrl.$modelValue.minutes, seconds: ngModelCtrl.$modelValue.seconds } : null; // adjust the time for invalid value at first time if { time.minutes = 0; } if { time.seconds = 0; } var totalSeconds = time.minutes * 60 + time.seconds; time = { minutes: Math.floor, seconds: totalSeconds % 60 }; if { selected = time; makeValid; } }; // call internally when the model is valid function refresh { makeValid(); ngModelCtrl.$setViewValue({ minutes: selected.minutes, seconds: selected.seconds }); updateTemplate; } function makeValid() { ngModelCtrl.$setValidity; $scope.validity = true; $scope.invalidMinutes = false; $scope.invalidSeconds = false; } function updateTemplate { var minutes = selected.minutes, seconds = selected.seconds; $scope.minutes = keyboardChange === 'm' ? minutes : pad; $scope.seconds = keyboardChange === 's' ? seconds : pad; } function pad { return ( angular.isDefined && value.toString ? '0' + value : value; } function getMinutesFromTemplate() { var minutes = parseInt; return  ? minutes : undefined; } function getSecondsFromTemplate() { var seconds = parseInt; if { seconds = 59; } return  ? seconds : undefined; } $scope.incrementMinutes = function() { addSeconds; }; $scope.decrementMinutes = function() { addSeconds; }; $scope.incrementSeconds = function() { addSeconds; }; $scope.decrementSeconds = function() { addSeconds; }; function addSeconds { var newSeconds = selected.minutes * 60 + selected.seconds + seconds; if { newSeconds = 0; } selected = { minutes: Math.floor, seconds: newSeconds % 60 }; refresh(); } $scope.previewTime = function { var totalSeconds = parseInt * 60 + parseInt, hh = pad(Math.floor, mm = pad, ss = pad; return hh + ':' + mm + ':' + ss; };}]); 

对应的Template实现:

: {{ previewTime }}
  Highlight on {{ movieName }}   Start Time:    End Time:      Tags:      OK Cancel

如果大家还想深入学习,可以点击这里进行学习,再为大家附3个精彩的专题:

Bootstrap学习教程

Bootstrap实战教程

Bootstrap插件使用教程

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

发表评论

电子邮件地址不会被公开。 必填项已用*标注