最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

仿Angular Bootstrap TimePicker創(chuàng)建分鐘數(shù)-秒數(shù)的輸入控件

 更新時間:2016年07月01日 15:02:51   作者:dm_vincent  
這篇文章主要為大家詳細介紹了仿Angular Bootstrap TimePicker創(chuàng)建分鐘數(shù)-秒數(shù)的輸入控件的相關(guān)資料,感興趣的小伙伴們可以參考一下

在一個項目中需要一個用來輸入分鐘數(shù)和秒數(shù)的控件,然而調(diào)查了一些開源項目后并未發(fā)現(xiàn)合適的控件。在Angular Bootstrap UI中有一個類似的控件TimePicker,但是它并沒有深入到分鐘和秒的精度。
因此,決定參考它的源碼然后自己進行實現(xiàn)。 
最終的效果如下:

 

首先是該directive的定義:

 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(ngModelCtrl) {
  minuteSecondPickerCtrl.init(ngModelCtrl, element.find('input'));
  }
 }
 };
}); 

在以上的link函數(shù)中,ctrls是一個數(shù)組: ctrls[0]是定義在本directive上的controller實例,ctrls[1]是ngModelCtrl,即ng-model對應(yīng)的controller實例。這個順序?qū)嶋H上是通過require: ['minuteSecondPicker', '?^ngModel']定義的。
注意到第一個依賴就是directive本身的名字,此時會將該directive中controller聲明的對應(yīng)實例傳入。第二個依賴的寫法有些奇怪:"?^ngModel",?的含義是即使沒有找到該依賴,也不要拋出異常,即該依賴是一個可選項。^的含義是查找父元素的controller。
然后,定義該directive中用到的一些默認(rèn)設(shè)置,通過constant directive實現(xiàn):

app.constant('minuteSecondPickerConfig', {
 minuteStep: 1,
 secondStep: 1,
 readonlyInput: false,
 mousewheel: true
}); 

緊接著是directive對應(yīng)的controller,它的聲明如下:

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

在directive的link函數(shù)中,調(diào)用了此controller的init方法:

 this.init = function(ngModelCtrl_, inputs) {
 ngModelCtrl = ngModelCtrl_;
 ngModelCtrl.$render = this.render;

 var minutesInputEl = inputs.eq(0),
  secondsInputEl = inputs.eq(1);

 var mousewheel = angular.isDefined($attrs.mousewheel) ? 
  $scope.$parent.$eval($attrs.mousewheel) : minuteSecondPickerConfig.mousewheel;
 if(mousewheel) {
  this.setupMousewheelEvents(minutesInputEl, secondsInputEl);
 }

 $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ?
  $scope.$parent.$eval($attrs.readonlyInput) : minuteSecondPickerConfig.readonlyInput;
 this.setupInputEvents(minutesInputEl, secondsInputEl);
 }; 

init方法接受的第二個參數(shù)是inputs,在link函數(shù)中傳入的是:element.find('input')。 所以第一個輸入框用來輸入分鐘,第二個輸入框用來輸入秒。
然后,檢查是否覆蓋了mousewheel屬性,如果沒有覆蓋則使用在constant中設(shè)置的默認(rèn)mousewheel,并進行相關(guān)設(shè)置如下:

// respond on mousewheel spin
 this.setupMousewheelEvents = function(minutesInputEl, secondsInputEl) {
 var isScrollingUp = function(e) {
  if(e.originalEvent) {
  e = e.originalEvent;
  }

  // pick correct delta variable depending on event
  var delta = (e.wheelData) ? e.wheelData : -e.deltaY;
  return (e.detail || delta > 0);
 };

 minutesInputEl.bind('mousewheel wheel', function(e) {
  $scope.$apply((isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes());
  e.preventDefault();
 });

 secondsInputEl.bind('mousewheel wheel', function(e) {
  $scope.$apply((isScrollingUp(e)) ? $scope.incrementSeconds() : $scope.decrementSeconds());
  e.preventDefault();
 });
 }; 

init方法最后會對inputs本身進行一些設(shè)置: 

// respond on direct input
 this.setupInputEvents = function(minutesInputEl, secondsInputEl) {
 if($scope.readonlyInput) {
  $scope.updateMinutes = angular.noop;
  $scope.updateSeconds = angular.noop;
  return;
 }

 var invalidate = function(invalidMinutes, invalidSeconds) {
  ngModelCtrl.$setViewValue(null);
  ngModelCtrl.$setValidity('time', false);
  $scope.validity = false;
  if(angular.isDefined(invalidMinutes)) {
  $scope.invalidMinutes = invalidMinutes;
  }
  if(angular.isDefined(invalidSeconds)) {
  $scope.invalidSeconds = invalidSeconds;
  }
 };

 $scope.updateMinutes = function() {
  var minutes = getMinutesFromTemplate();

  if(angular.isDefined(minutes)) {
  selected.minutes = minutes;
  refresh('m');
  } else {
  invalidate(true);
  }
 };

 minutesInputEl.bind('blur', function(e) {
  if(!$scope.invalidMinutes && $scope.minutes < 10) {
  $scope.$apply(function() {
   $scope.minutes = pad($scope.minutes);
  });
  }
 });

 $scope.updateSeconds = function() {
  var seconds = getSecondsFromTemplate();

  if(angular.isDefined(seconds)) {
  selected.seconds = seconds;
  refresh('s');
  } else {
  invalidate(undefined, true);
  }
 };

 secondsInputEl.bind('blur', function(e) {
  if(!$scope.invalidSeconds && $scope.seconds < 10) {
  $scope.$apply(function() {
   $scope.seconds = pad($scope.seconds);
  });
  }
 });
 }; 

此方法中,聲明了用于設(shè)置輸入非法的invalidate函數(shù),它會在scope中暴露一個validity = false屬性讓頁面有機會做出合適的反應(yīng)。
 如果用戶使用了一個變量來表示minuteStep或者secondStep,那么還需要設(shè)置相應(yīng)的watchers:

var minuteStep = minuteSecondPickerConfig.minuteStep;
 if($attrs.minuteStep) {
 $scope.parent.$watch($parse($attrs.minuteStep), function(value) {
  minuteStep = parseInt(value, 10);
 });
 }

 var secondStep = minuteSecondPickerConfig.secondStep;
 if($attrs.secondStep) {
 $scope.parent.$watch($parse($attrs.secondStep), function(value) {
  secondStep = parseInt(value, 10);
 });
 } 

完整的directive實現(xiàn)代碼如下:

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(ngModelCtrl) {
  minuteSecondPickerCtrl.init(ngModelCtrl, element.find('input'));
  }
 }
 };
});

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_, inputs) {
 ngModelCtrl = ngModelCtrl_;
 ngModelCtrl.$render = this.render;

 var minutesInputEl = inputs.eq(0),
  secondsInputEl = inputs.eq(1);

 var mousewheel = angular.isDefined($attrs.mousewheel) ? 
  $scope.$parent.$eval($attrs.mousewheel) : minuteSecondPickerConfig.mousewheel;
 if(mousewheel) {
  this.setupMousewheelEvents(minutesInputEl, secondsInputEl);
 }

 $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ?
  $scope.$parent.$eval($attrs.readonlyInput) : minuteSecondPickerConfig.readonlyInput;
 this.setupInputEvents(minutesInputEl, secondsInputEl);
 };

 var minuteStep = minuteSecondPickerConfig.minuteStep;
 if($attrs.minuteStep) {
 $scope.parent.$watch($parse($attrs.minuteStep), function(value) {
  minuteStep = parseInt(value, 10);
 });
 }

 var secondStep = minuteSecondPickerConfig.secondStep;
 if($attrs.secondStep) {
 $scope.parent.$watch($parse($attrs.secondStep), function(value) {
  secondStep = parseInt(value, 10);
 });
 }

 // respond on mousewheel spin
 this.setupMousewheelEvents = function(minutesInputEl, secondsInputEl) {
 var isScrollingUp = function(e) {
  if(e.originalEvent) {
  e = e.originalEvent;
  }

  // pick correct delta variable depending on event
  var delta = (e.wheelData) ? e.wheelData : -e.deltaY;
  return (e.detail || delta > 0);
 };

 minutesInputEl.bind('mousewheel wheel', function(e) {
  $scope.$apply((isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes());
  e.preventDefault();
 });

 secondsInputEl.bind('mousewheel wheel', function(e) {
  $scope.$apply((isScrollingUp(e)) ? $scope.incrementSeconds() : $scope.decrementSeconds());
  e.preventDefault();
 });
 };

 // respond on direct input
 this.setupInputEvents = function(minutesInputEl, secondsInputEl) {
 if($scope.readonlyInput) {
  $scope.updateMinutes = angular.noop;
  $scope.updateSeconds = angular.noop;
  return;
 }

 var invalidate = function(invalidMinutes, invalidSeconds) {
  ngModelCtrl.$setViewValue(null);
  ngModelCtrl.$setValidity('time', false);
  $scope.validity = false;
  if(angular.isDefined(invalidMinutes)) {
  $scope.invalidMinutes = invalidMinutes;
  }
  if(angular.isDefined(invalidSeconds)) {
  $scope.invalidSeconds = invalidSeconds;
  }
 };

 $scope.updateMinutes = function() {
  var minutes = getMinutesFromTemplate();

  if(angular.isDefined(minutes)) {
  selected.minutes = minutes;
  refresh('m');
  } else {
  invalidate(true);
  }
 };

 minutesInputEl.bind('blur', function(e) {
  if(!$scope.invalidMinutes && $scope.minutes < 10) {
  $scope.$apply(function() {
   $scope.minutes = pad($scope.minutes);
  });
  }
 });

 $scope.updateSeconds = function() {
  var seconds = getSecondsFromTemplate();

  if(angular.isDefined(seconds)) {
  selected.seconds = seconds;
  refresh('s');
  } else {
  invalidate(undefined, true);
  }
 };

 secondsInputEl.bind('blur', function(e) {
  if(!$scope.invalidSeconds && $scope.seconds < 10) {
  $scope.$apply(function() {
   $scope.seconds = pad($scope.seconds);
  });
  }
 });
 };

 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) {
  time.minutes = 0;
 }
 if(time.seconds < 0) {
  time.seconds = 0;
 }

 var totalSeconds = time.minutes * 60 + time.seconds;
 time = {
  minutes: Math.floor(totalSeconds / 60),
  seconds: totalSeconds % 60
 };

 if(time) {
  selected = time;
  makeValid();
  updateTemplate();
 }
 };

 // call internally when the model is valid
 function refresh(keyboardChange) {
 makeValid();
 ngModelCtrl.$setViewValue({
  minutes: selected.minutes,
  seconds: selected.seconds
 });
 updateTemplate(keyboardChange);
 }

 function makeValid() {
 ngModelCtrl.$setValidity('time', true);
 $scope.validity = true;
 $scope.invalidMinutes = false;
 $scope.invalidSeconds = false;
 }

 function updateTemplate(keyboardChange) {
 var minutes = selected.minutes,
  seconds = selected.seconds;

 $scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
 $scope.seconds = keyboardChange === 's' ? seconds : pad(seconds);
 }

 function pad(value) {
 return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
 }

 function getMinutesFromTemplate() {
 var minutes = parseInt($scope.minutes, 10);
 return (minutes >= 0) ? minutes : undefined;
 }

 function getSecondsFromTemplate() {
 var seconds = parseInt($scope.seconds, 10);
 if(seconds >= 60) {
  seconds = 59;
 }

 return (seconds >= 0) ? seconds : undefined;
 }

 $scope.incrementMinutes = function() {
 addSeconds(minuteStep * 60);
 };

 $scope.decrementMinutes = function() {
 addSeconds(-minuteStep * 60);
 };

 $scope.incrementSeconds = function() {
 addSeconds(secondStep);
 };

 $scope.decrementSeconds = function() {
 addSeconds(-secondStep);
 };

 function addSeconds(seconds) {
 var newSeconds = selected.minutes * 60 + selected.seconds + seconds;
 if(newSeconds < 0) {
  newSeconds = 0;
 }

 selected = {
  minutes: Math.floor(newSeconds / 60),
  seconds: newSeconds % 60
 };

 refresh();
 }

 $scope.previewTime = function(minutes, seconds) {
 var totalSeconds = parseInt(minutes, 10) * 60 + parseInt(seconds, 10),
  hh = pad(Math.floor(totalSeconds / 3600)),
  mm = pad(minutes % 60),
  ss = pad(seconds);

 return hh + ':' + mm + ':' + ss;
 };
}]); 

對應(yīng)的Template實現(xiàn): 

<table>
 <tbody>
 <tr class="text-center">
  <td>
  <a ng-click="incrementMinutes()" class="btn btn-link">
   <span class="glyphicon glyphicon-chevron-up"></span>
  </a>
  </td>
  <td>&nbsp;</td>
  <td>
  <a ng-click="incrementSeconds()" class="btn btn-link">
   <span class="glyphicon glyphicon-chevron-up"></span>
  </a>
  </td>
  <td>&nbsp;</td>
 </tr>
 <tr>
  <td style="width:50px;" class="form-group" ng-class="{'has-error': invalidMinutes}">
  <input type="text" ng-model="minutes" ng-change="updateMinutes()" class="form-control text-center" ng-mousewheel="incrementMinutes()" ng-readonly="readonlyInput" maxlength="3">
  </td>
  <td>:</td>
  <td style="width:50px;" class="form-group" ng-class="{'has-error': invalidSeconds}">
  <input type="text" ng-model="seconds" ng-change="updateSeconds()" class="form-control text-center" ng-mousewheel="incrementSeconds()" ng-readonly="readonlyInput" maxlength="2">
  <td>
  <!-- preview column -->
  <td>
  <span class="label label-primary" ng-show="validity">
   {{ previewTime(minutes, seconds) }}
  </span>
  </td>
 </tr>
 <tr class="text-center">
  <td>
  <a ng-click="decrementMinutes()" class="btn btn-link">
   <span class="glyphicon glyphicon-chevron-down"></span>
  </a>
  </td>
  <td>&nbsp;</td>
  <td>
  <a ng-click="decrementSeconds()" class="btn btn-link">
   <span class="glyphicon glyphicon-chevron-down"></span>
  </a>
  </td>
  <td>&nbsp;</td>
 </tr>
 </tbody>
</table> 

測試代碼(即前面截圖dialog的源代碼):

 <div class="modal-header">
 <h3 class="modal-title">Highlight on <span class="label label-primary">{{ movieName }}</span></h3>
</div>
<div class="modal-body">

 <div class="row">
 <div id="highlight-start" class="col-xs-6">
  <h4>Start Time:</h4>
  <minute-second-picker ng-model="startTime" validity="startTimeValidity"></minute-second-picker>
 </div>

 <div id="highlight-end" class="col-xs-6">
  <h4>End Time:</h4>
  <minute-second-picker ng-model="endTime" validity="endTimeValidity"></minute-second-picker>
 </div>
 </div>
 <div class="row">
 <div class="col-xs-2">
  Tags:
 </div>
 <div class="col-xs-10">
  <tags model="tags" src="s as s.name for s in sourceTags" options="{ addable: 'true' }"></tags>
 </div>
 </div>
</div>
<div class="modal-footer">
 <button class="btn btn-primary" ng-click="ok()" ng-disabled="!startTimeValidity || !endTimeValidity || durationIncorrect(endTime, startTime)">OK</button>
 <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>

如果大家還想深入學(xué)習(xí),可以點擊這里進行學(xué)習(xí),再為大家附3個精彩的專題:

Bootstrap學(xué)習(xí)教程

Bootstrap實戰(zhàn)教程

Bootstrap插件使用教程

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • angularjs實現(xiàn)簡單的購物車功能

    angularjs實現(xiàn)簡單的購物車功能

    這篇文章主要為大家詳細介紹了angularjs實現(xiàn)簡單的購物車功能 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 深究AngularJS如何獲取input的焦點(自定義指令)

    深究AngularJS如何獲取input的焦點(自定義指令)

    本篇文章主要介紹了AngularJS如何獲取input的焦點(自定義指令),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 淺談angular.copy() 深拷貝

    淺談angular.copy() 深拷貝

    本篇文章主要介紹了淺談angular.copy() 深拷貝,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • AngularJS獲取json數(shù)據(jù)的方法詳解

    AngularJS獲取json數(shù)據(jù)的方法詳解

    這篇文章主要介紹了AngularJS獲取json數(shù)據(jù)的方法,結(jié)合實例形式詳細分析了AngularJS獲取json數(shù)據(jù)的詳細步驟、操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2017-05-05
  • angular動態(tài)表單制作

    angular動態(tài)表單制作

    通過實例代碼給大家詳細講述了angular動態(tài)表單的制作方法,對此有需要的朋友參考下。
    2018-02-02
  • angularjs請求數(shù)據(jù)的方法示例

    angularjs請求數(shù)據(jù)的方法示例

    這篇文章主要給大家介紹了關(guān)于angularjs請求數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用angularjs具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • AngularJS實現(xiàn)星星等級評分功能

    AngularJS實現(xiàn)星星等級評分功能

    這篇文章主要為大家詳細介紹了AngularJS實現(xiàn)星星等級評分功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • AngularJS 控制器 controller的詳解

    AngularJS 控制器 controller的詳解

    這篇文章主要介紹了AngularJS 控制器 controller的詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • Angular8路由守衛(wèi)原理和使用方法

    Angular8路由守衛(wèi)原理和使用方法

    這篇文章主要給大家介紹了關(guān)于Angular8路由守衛(wèi)原理和使用方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Angular8具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • AngularJS使用ng-inlude指令加載頁面失敗的原因與解決方法

    AngularJS使用ng-inlude指令加載頁面失敗的原因與解決方法

    這篇文章主要介紹了AngularJS使用ng-inlude指令加載頁面失敗的原因與解決方法,對比不同瀏覽器錯誤提示分析了加載失敗的原因及通過http訪問的解決方法,需要的朋友可以參考下
    2017-01-01

最新評論

乌鲁木齐市| 徐闻县| 洪泽县| 屯门区| 花垣县| 扶风县| 娱乐| 彭泽县| 雷山县| 西和县| 团风县| 美姑县| 元谋县| 镇雄县| 名山县| 五华县| 罗定市| 兴宁市| 淮阳县| 隆安县| 林西县| 兴安盟| 循化| 慈利县| 昭觉县| 嘉兴市| 长春市| 托克托县| 张掖市| 田林县| 昌黎县| 花莲市| 连州市| 奉化市| 敦煌市| 灯塔市| 石河子市| 吉首市| 铜川市| 右玉县| 乳山市|