$timeout 服务未根据指令更新 angular 控制器

$timeout service not updating angular controller from directive

"use strict";
angular.module("appBanner", [])
  .controller('bannerCtrl', function($scope) {

     $scope.slides = ["auto", "boatowners", "commercial"];

  $scope.currentIndex = 0;
        $scope.setCurrentSlideIndex = function (index) {
            $scope.currentIndex = index;
   $scope.currentSlideIndex = $scope.slides[$scope.currentIndex];
        }

        $scope.isCurrentSlideIndex = function (index) {
            return $scope.currentIndex === index;
        };

        $scope.prevSlide = function () {
   $scope.currentIndex = ($scope.currentIndex > 0) ? --$scope.currentIndex : $scope.slides.length - 1;
   $scope.setCurrentSlideIndex($scope.currentIndex);
        };

        $scope.nextSlide = function () {
           $scope.currentIndex = ($scope.currentIndex < $scope.slides.length - 1) ? ++$scope.currentIndex : 0;
     $scope.setCurrentSlideIndex($scope.currentIndex);
        };
  })
  .directive('banner', function($timeout) {
    return {
     
      link: function postLink(scope, element, attrs) {
        var progressBar = angular.element(".progress");
        var bannerNav = angular.element(".bannerNav");
        var navCircle = angular.element(".bannerNav.navCircle");
        var imgSlides = angular.element(".imgSlide");
        var slideTime = 1.5;

        TweenMax.set(imgSlides, {
          autoAlpha: 0,
          display: "none"
        });
        TweenMax.set(progressBar, {
          autoAlpha: 0
        });

        var tlMaster = initMasterTimeline(imgSlides, progressBar, slideTime);

        scope.getWidth = function() {
          return $(element).width();
        };

        scope.play = function(newIndexValue) {
          tlMaster.play(newIndexValue);
        };

        scope.$watch('slideshowHover', function(newValue) {
          if (newValue === true) TweenMax.to(bannerNav, 0.5, {
            autoAlpha: 0.85
          })
          else TweenMax.to(bannerNav, 0.5, {
            autoAlpha: 0.25
          })
        });

        scope.$watch('currentSlideIndex', function(newIndexValue) {
          scope.play(newIndexValue);
        });

        scope.$watch(scope.getWidth, function(width) {
          element.css('height', width * 0.4);
        });

        function updateCurrentIndex(index) {
          $timeout(function() {
            scope.setCurrentSlideIndex(index);
          });

        }

        function setProgress(timeline, progressBar) {
          TweenMax.set(progressBar, {
            scaleX: timeline.progress()
          });
        }

        function initMasterTimeline(imgSlides, progressBar, slideTime) {
          var tlAuto = initAutoTimeline(imgSlides, progressBar, slideTime);
          var tlBoatowners = initBoatownersTimeline(imgSlides, progressBar, slideTime);
          var tlCommercial = initCommercialTimeline(imgSlides, progressBar, slideTime);

          var tlMaster = new TimelineMax({
            repeat: -1
          });
          tlMaster.set(progressBar, {
              scaleX: 0,
              transformOrigin: "left"
            })
            .add(tlAuto, "auto")
            .add(tlBoatowners, "boatowners")
            .add(tlCommercial, "commercial");

          return tlMaster;
        }

        function initAutoTimeline(imgSlides, progressBar, slideTime) {
          var stayTime = 10; //for now, can make each timeline as long as you want later

          var tlAuto = new TimelineLite({
            onUpdate: setProgress,
            onUpdateParams: ["{self}", progressBar]
          });

          var autoNavCircle = $(".navCircle")[0];
          tlAuto.set(imgSlides[0], {
              display: "block"
            })
            .to(progressBar, slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[0], slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[0], slideTime, {
              autoAlpha: 0
            }, stayTime)
            .to(progressBar, slideTime, {
              autoAlpha: 0
            }, stayTime)
            .set(imgSlides[0], {
              display: "none",
              onComplete: updateCurrentIndex(1)
            })

          return tlAuto;
        }

        function initBoatownersTimeline(imgSlides, progressBar, slideTime) {
          var stayTime = 10; //for now, can make each timeline as long as you want later

          var tlBoatowners = new TimelineLite({
            onUpdate: setProgress,
            onUpdateParams: ["{self}", progressBar]
          });

          var boatownersNavCircle = $(".navCircle")[1];

          tlBoatowners.set(imgSlides[1], {
              display: "block"
            })
            .to(progressBar, slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[1], slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[1], slideTime, {
              autoAlpha: 0
            }, stayTime)
            .to(progressBar, slideTime, {
              autoAlpha: 0
            }, stayTime)
            .set(imgSlides[1], {
              display: "none",
              onComplete: updateCurrentIndex(2)
            });

          return tlBoatowners;
        }

        function initCommercialTimeline(imgSlides, progressBar, slideTime) {
          var stayTime = 10; //for now, can make each timeline as long as you want later

          var tlCommercial = new TimelineLite({
            onUpdate: setProgress,
            onUpdateParams: ["{self}", progressBar]
          });

          var commercialNavCircle = $(".navCircle")[2];
          tlCommercial.set(imgSlides[2], {
              display: "block"
            })
            .to(progressBar, slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[2], slideTime, {
              autoAlpha: 1
            }, 0)
            .to(imgSlides[2], slideTime, {
              autoAlpha: 0
            }, stayTime)
            .to(progressBar, slideTime, {
              autoAlpha: 0
            }, stayTime)
            .set(imgSlides[2], {
              display: "none",
              onComplete: updateCurrentIndex(0)
            });

          return tlCommercial;
        }
      }
    }
  })
#slideshow{
 position: relative;
}

.imgSlide{
 position: absolute;
 width: 100%;
}

.progress{
  position: absolute;
  width: 100%;
  height:3px;
  background: #F1F1F1;
  z-index: 5;
}

.navCircleContainer {
 position: absolute; 
 display: flex;
    justify-content: space-between;
 padding: 5px;
 bottom: 2.5px;
 left: 12.5%;
 width: 75%;
 height: auto;
}

.navCircle {
 opacity: 0.25;
}

div.navCircle {
  position: relative;
  border-radius: 100%;
  background:#F1F1F1;
}

.navCircle.active  {
 opacity:1;
}

@media only screen and (min-width: 768px) {
 div.navCircle{
  width: 30px;
  height: 30px;
 }
}

@media only screen and (max-width: 767px) {
 div.navCircle{
  width: 15px;
  height: 15px;
 }
}

.navCircle span {
 position: absolute;
 color:#F1F1F1;
 font-weight: bold;
 left: 50%;
 -moz-transform: translateX(-50%);
 -webkit-transform: translateX(-50%);
 -ms-transform: translateX(-50%);
 -o-transform: translateX(-50%);
 transform: translateX(-50%);
}



@media only screen and (min-width: 768px) {
 .navCircle span {
  bottom: 30px;
 }
}

@media only screen and (max-width: 767px) {
 .navCircle span {
  bottom: 20px;
 }
}

.navArrow {
 position: absolute;
 top: 50%;
 color:#F1F1F1;
 -moz-transform: translateY(-50%);
 -webkit-transform: translateY(-50%);
 -ms-transform: translateY(-50%);
 -o-transform: translateY(-50%);
 transform: translateY(-50%);
}

#navArrowLeft {
 left: 0%;
}

#navArrowRight {
 right: 0%;
}

img {
 width: 100%;
 height: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.15.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/jquery.gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div ng-app="appBanner" ng-controller="bannerCtrl"  banner id="slideshow" ng-mouseover="slideshowHover = true" ng-mouseleave="slideshowHover = false" ng-init="slideshowHover = false">
  <!-- green field with lake -->
 <img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/08/l/14089545069hw66.jpg" >
  
 <!-- waterfall -->
 <img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_09_09/file3231347173227.jpg" >
  
  <!-- red sunset -->
 <img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_07_22/file541342984669.jpg" >
 <div class="progress"></div>
 <div id="navArrowLeft" class="navArrow bannerNav" ng-click="prevSlide()">
  <div class="hidden-xs">
   <i class="fa fa-angle-double-left fa-5x"></i>
  </div>
  <div class="hidden-sm hidden-md hidden-lg">
   <i class="fa fa-angle-double-left fa-2x"></i>
  </div>
 </div>
 <div id="navArrowRight" class="navArrow bannerNav" ng-click="nextSlide()">
  <div class="hidden-xs">
   <i class="fa fa-angle-double-right fa-5x"></i>
  </div>
  <div class="hidden-sm hidden-md hidden-lg">
   <i class="fa fa-angle-double-right fa-2x"></i>
  </div>
 </div>
 <div class="navCircleContainer">              
  <div  class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 0" ng-mouseover="navCircleAutoHover = true" ng-mouseleave="navCircleAutoHover = false" ng-init="navCircleAutoHover = false"  ng-click="play('auto')"><span class="bannerNav fade" ng-show="navCircleAutoHover === true">Lake</span></div>
  <div  class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 1" ng-mouseover="navCircleBoatownersHover = true" ng-mouseleave="navCircleBoatownersHover = false" ng-init="navCircleBoatownersHover = false"  ng-click="play('boatowners')"><span class="bannerNav  fade" ng-show="navCircleBoatownersHover === true">Waterfall</span></div>
  <div  class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 2" ng-mouseover="navCircleCommercialHover = true" ng-mouseleave="navCircleCommercialHover = false" ng-init="navCircleCommercialHover = false"  ng-click="play('commercial')"><span class="bannerNav fade" ng-show="navCircleCommercialHover === true"> Sunset</span></div>

 </div>
</div>

Working Codepen Link

I had some trouble getting this to work here in Whosebug, but the working codepen link is provided. My problem is that the updateCurrentIndex(nextIndex) that works in conjunction with $timeout and happens onComplete at the end of each child timeline does not seem to communicate the normal increments of the index when it plays.

因此,如果您在时间轴有时间转到下一张幻灯片(索引在用户控制之外递增)之前单击下一张、上一张或底部的任何直接转到圆圈按钮,这将正常工作。但是,当时间轴播放下一张幻灯片时,控制器中的索引并不知道此更改,并且变得不同步。有人指出我使用 $timeout 服务来解决这个问题,但它仍然无法正常工作。非常感谢任何帮助。

演示中有相当多的代码需要整理,但您有两个无效的函数引用,例如:

onComplete: updateCurrentIndex(2)

首先,这些是硬编码的值,其次,它们将立即被调用,而不是在 onComplete 触发时如您所期望的那样:

要将函数作为引用传递,您不能使用 (),因此正确的方法是:

onComplete: updateCurrentIndex

但是由于您需要传递参数,因此您需要这样的东西:

onComplete: function(arg1,arg2){ // not sure what arguments are available
   var newIndex = // I'm not sure how to get index in this event
   updateCurrentIndex(newIndex);
}

我刚刚弄明白了。我的问题如下:onComplete:updateCurrentIndex、onCompleteParams:[nextIndex]

我是这样传递的:onComplete: updateCurrentIndex(2)

是的,它正在立即执行。现在可以使用了。