[AngularJS] 仿照Angular Bootstrap TimePicker创建一个分钟数-秒数的输入控件(minuteSecondPicker)

这篇博客讲述了作者在项目中找不到合适的分钟-秒数输入控件后,如何参考Angular Bootstrap TimePicker的源码,自定义了一个名为minuteSecondPicker的AngularJS指令。文章详细介绍了指令的定义、controller的初始化、默认设置、mousewheel处理以及输入验证等实现过程,并提供了完整代码和测试用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一个项目中需要一个用来输入分钟数和秒数的控件,然而调查了一些开源项目后并未发现合适的控件。在Angular Bootstrap UI中有一个类似的控件TimePicker,但是它并没有深入到分钟和秒的精度。

因此,决定参考它的源码然后自己进行实现。

最终的效果如下:

首先是该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函数中,ctrls是一个数组: ctrls[0]是定义在本directive上的controller实例,ctrls[1]是ngModelCtrl,即ng-model对应的controller实例。这个顺序实际上是通过require: ['minuteSecondPicker', '?^ngModel']定义的。

注意到第一个依赖就是directive本身的名字,此时会将该directive中controller声明的对应实例传入。第二个依赖的写法有些奇怪:"?^ngModel",?的含义是即使没有找到该依赖,也不要抛出异常,即该依赖是一个可选项。^的含义是查找父元素的controller。

然后,定义该directive中用到的一些默认设置,通过constant directive实现:

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

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

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

在directive的link函数中,调用了此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方法接受的第二个参数是inputs,在link函数中传入的是:element.find('input')。 所以第一个输入框用来输入分钟,第二个输入框用来输入秒。

然后,检查是否覆盖了mousewheel属性,如果没有覆盖则使用在constant中设置的默认mousewheel,并进行相关设置如下:

    // 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();
        });
    };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值