$ timeout服务不从指令更新角度控制器

时间:2016-03-25 15:25:13

标签: angularjs angularjs-directive greensock



"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;
        }
      }
    }
  })
&#13;
#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;
}
&#13;
<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>
&#13;
&#13;
&#13;

Working Codepen Link

  

我在stackoverflow中遇到这个问题时遇到了一些麻烦,但提供了工作的codepen链接。我的问题是updateCurrentIndex(nextIndex)与$ timeout一起使用并在每个子时间轴的末尾发生onComplete似乎在播放时似乎没有传达索引的正常增量。

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

2 个答案:

答案 0 :(得分:0)

在demo中有很多代码需要排序,但是你有两个无效的函数引用,如:

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);
}

答案 1 :(得分:0)

我只是想通了。我的问题如下:onComplete:updateCurrentIndex,onCompleteParams:[nextIndex]

我传递了这个:onComplete:updateCurrentIndex(2)

是的,它立即执行。它现在有效。