angular倒计时指令

app.directive("CountDown",['$interval',function ($interval) {  
  return {
    restrict: "E",
    replace: true,
    template: '<span>' +

    //1还没开始阶段

    //1-0 今天
    '<span ng-if="returnState.period==1 && returnState.gap.natureDay==0" ng-show="options.showWhen.indexOf(100)!=-1">今天<span  class="timeTick">{{ returnState.date.hour}}</span> : <span class="timeTick">{{returnState.date.minute}} </span></span>' +
    //1-1 明天
    '<span  ng-if="returnState.period==1 && returnState.gap.natureDay==1"  ng-show="options.showWhen.indexOf(101)!=-1">明天<span class="timeTick"> {{returnState.date.hour}}</span> : <span class="timeTick">{{returnState.date.minute}}</span></span>' +
    // 1-2 后天
    '<span ng-if="returnState.period==1 && returnState.gap.natureDay==2"  ng-show="options.showWhen.indexOf(102)!=-1">后天<span class="timeTick"> {{returnState.date.hour}}</span> : <span class="timeTick">{{returnState.date.minute}}</span></span>' +
    //1-3 没有汉字能表达,除非你说几天后
    '<span ng-if="returnState.period==1 && returnState.gap.natureDay!=0&&returnState.gap.natureDay!=1&&returnState.gap.natureDay!=2" ng-show="options.showWhen.indexOf(99)!=-1"><span class="timeTick"> {{returnState.date.natureMonth}}</span> 月 <span class="timeTick">{{returnState.date.date}}</span>日</span>' +

    // 2 预倒计时和单时间倒计时
    '<span ng-if="returnState.period==2"  ng-show="options.showWhen.indexOf(200)!=-1" >' +
    '<span ng-if="returnState.gap.days!=0"><span class="timeTick"> {{returnState.gap.days}}</span> 天</span>'+
    '<span class="timeTick"> {{returnState.gap.hours}}</span> : ' +
    '<span class="timeTick">{{returnState.gap.minutes}} </span> : ' +
    '<span class="timeTick">{{returnState.gap.seconds}}</span>' +
    '</span>'+

    // 双时间区间中倒计时
    '<span  ng-if="returnState.period==3"  ng-show="options.showWhen.indexOf(300)!=-1" >' +
    '<span ng-if="returnState.gap.days!=0"><span class="timeTick"> {{returnState.gap.days}}</span> 天</span>'+
    '<span class="timeTick"> {{returnState.gap.hours}}</span> : ' +
    '<span class="timeTick">{{returnState.gap.minutes}}</span> : ' +
    '<span class="timeTick">{{returnState.gap.seconds}} </span>' +
    '</span>'+

    // 结束了

    '</span>',

    scope: {
      options: "=", //传入选项
      returnState: "=" //返回选项
    },
    link: function (scope, ele, attr) {

      var timer; 定时器
      // 这里用watch是因为有可能是在指令解析完毕后动态改变options,而此时指令惰性地不去更新 options导致无法发挥作用。
      scope.$watch('options',function(options){
        if(!options) return console.log("倒计时指令缺少必要参数");

        var opt={};
        /***参数过滤****/
        opt.startDate= validateDate(options.startDate); //开始时间,必要参数。可传入数字或者数字字符串,含义为时间戳。

        opt.endDate= validateDate(options.endDate); // 结束时间,可选参数。同上。

        opt.preCountMs= options.preCountMs || 2*3600*1000;  //双时间的时候可以预倒计时。

        opt.showWhen=options.endDate?(options.showWhen||[300]):(options.showWhen||[200]);  // 在什么阶段显示。可能值:99表示没开始要显示x月x日,100表示要显示今天x点x分,101表示要显示明天x点x分,102表示要显示后天x点x分,200表示要显示预计倒计时的时候显示,300表示区间倒计时要显示。400结束了,传或者不传都不会显示。

        opt.preFn = validateFn(options.preFn); //表示预倒计时开始那刻要执行的函数。

        opt.startFn = validateFn(options.startFn); //表示预开始那刻要执行的函数。

        opt.endFn = validateFn(options.endFn); //表示预结束那刻要执行的函数。

        //单时间倒计时。
        if(!opt.endDate){
          timer=$interval(function(){
            if(opt.startDate>new Date().getTime()){
              scope.returnState={
                period: 2,
                gap:transformDate(opt.startDate).gap
              };
              scope.reloadWhenStart=true;
            }
            else{
              if(scope.reloadWhenStart) scope.options.startFn();
              scope.returnState={
                period: 4,
                date:transformDate(options.startDate).date
              }
            }
          },1000)
        }
        //  双时间倒计时。
        else{
          timer=$interval(function () {
            scope.returnState= shortCut(opt);

            if(scope.returnState.period==1&&scope.returnState.gap.natureDay==0) scope.reloadWhenPreCount=true;
            if(scope.returnState.period==2) scope.reloadWhenStart=true;
            if(scope.returnState.period==3) scope.reloadWhenEnd=true;

            if(scope.reloadWhenPreCount&&scope.returnState.period==2) opt.preFn();
            if(scope.reloadWhenStart&&scope.returnState.period==3) opt.startFn();
            if(scope.reloadWhenEnd&&scope.returnState.period==4) opt.endFn();

          },1000)
        }
      })

      scope.$on('$destroy',function () {
        $interval.cancel(timer);
      });

      function validateDate(dateTime){
        dateTime= parseInt(dateTime);
        if (typeof dateTime != "number") return console.error ("需要整数作为参数");
        dateTime=parseInt(dateTime*Math.pow(10,13-dateTime.toString ().length));
        return dateTime;
      }
      function validateFn(fn){
        if (!fn || typeof fn !="function") return function(){window.location.reload()}
        else return fn;
      };
      function period (options) {
        if (typeof options != "object" || typeof options.length == "number") {
          console.error ("countDown传入的参数错误。\n应该是一个对象,key有startDate(起始时间戳), endDate(结束时间戳), preCountMs(预倒计时阈值,单位为毫秒)");
          console.log ("返回period为整数类型,1表示未开始且未进入倒计时,2表示进入开始倒计时,3表示结束倒计时,4表示已经结束");
          return
        }
        options.startDate=validateDate(options.startDate);
        options.endDate=validateDate(options.endDate);
        options.preCountMs=options.preCountMs || 2*3600*1000;

        if(options.startDate>options.endDate) return console.error("时间起始值矛盾");
        var now = new Date();
        var nowTime= now.getTime();

        if (nowTime>options.endDate) return 4;
        else if (options.endDate>=nowTime && nowTime>=options.startDate) return 3;
        else if (options.startDate>nowTime && nowTime> options.startDate-options.preCountMs) return  2;
        else if (options.startDate-options.preCountMs>=nowTime) return 1;
        else console.error("出错了,找少侠");
      };
      function transformDate (dateTime) {
        dateTime = validateDate(dateTime);
        var thisDate = new Date (dateTime);
        var gap = {};
        var now = new Date();
        var zeroThisDateTime= new Date(thisDate.getFullYear(),thisDate.getMonth(),thisDate.getDate()).getTime();
        var zeroNowDateTime= new Date(now.getFullYear(),now.getMonth(),now.getDate()).getTime();
        var _toString= function (num) {
          var str = num.toString();
          return str.length==1?"0"+str:str;
        };
        gap.Ms=dateTime-now.getTime();
        gap.days= _toString(parseInt(gap.Ms/(24*3600*1000)));
        gap.hours= _toString(parseInt((gap.Ms-gap.days*24*3600*1000)/(3600*1000)));
        gap.minutes=_toString(parseInt((gap.Ms-gap.days*24*3600*1000-gap.hours*3600*1000)/(60*1000)));
        gap.seconds=_toString(parseInt((gap.Ms-gap.days*24*3600*1000-gap.hours*3600*1000-gap.minutes*60*1000)/1000));
        gap.natureDay = _toString((zeroThisDateTime-zeroNowDateTime)/(24*3600*1000));

        return {
          date: {
            year: thisDate.getFullYear (),
            month: _toString(thisDate.getMonth ()),
            natureMonth: _toString(thisDate.getMonth () + 1),
            date: _toString(thisDate.getDate ()),
            hour: _toString(thisDate.getHours ()),
            minute: _toString(thisDate.getMinutes ()),
            second: _toString(thisDate.getSeconds ())
          },
          gap: gap
        }
      };
      function shortCut (options) {
        var _period = period(options);
        switch (_period){
          case 1:
            return {
              period: 1,
              gap: transformDate(options.startDate).gap,
              date:transformDate(options.startDate).date
            };
          case 2:
            return {
              period:2,
              gap:transformDate(options.startDate).gap
            };
          case 3:
            return{
              period:3,
              gap: transformDate(options.endDate).gap
            };
          case 4:
            return{
              period: 4,
              date:transformDate(options.startDate).date
            }
        }
      }
    }
  }
}])

有问题请入群454796847交流

licat

继续阅读此作者的更多文章