javascript - mlab教學 - nodejs express js




如何針對導致更改的單擊事件設置ng-repeat項目的動畫 (2)

我正在嘗試為用戶設置動畫,從不同的項目集中選擇項目。 該項目應從所單擊的集合設置為所選項目列表中的新位置。

在下面的演示中,將粉紅色框視為可用項目,將邊框視為所選項目列表(藍色框)。 用戶可以通過單擊任一粉紅色框來選擇項目:

angular.module('test', ['ngAnimate'])
  .controller('testCtrl', function($scope) {
    $scope.products = [{}, {}, {}, {}];
    $scope.purchased = [{}];
    $scope.purchase = function(dir) {
      $scope.direction = dir
      $scope.purchased.push($scope.products.pop());
    };
  })
  .directive('testDir', function($animate) {
    return {
      link: function(scope, element) {
        $animate.on('enter', element, function(element, phase) {
          $target = scope.direction == 'left' ? $('.stock:first') : $('.stock:last');
          element.position({
            my: 'center',
            at: 'center',
            of: $target,
            using: function(pos, data) {
              $(this).css(pos);
              $(this).animate({
                top: 0,
                left: 0
              });
            }
          });
        });
      }
    };
  });
.stock {
  display: inline-block;
  width: 50px;
  height: 50px;
  background: hotpink;
}
.stock.right {
  margin-left: 100px;
}
.product {
  height: 50px;
  width: 50px;
  border: 1px solid;
}
.purchased {
  height: 60px;
  margin-top: 100px;
  border: 2px dotted;
}
.purchased .product {
  display: inline-block;
  margin: 5px;
  background: dodgerblue;
}
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
<div ng-app="test" ng-controller="testCtrl">
  <div class="stock" ng-click="purchase('left')"></div>
  <div class="stock right" ng-click="purchase('right')"></div>
  <div class="purchased clearfix">
    <div class="product" ng-repeat="product in purchased" data-test-dir>
    </div>
  </div>
</div>

嗯,它有點工作 - 但我使用jQuery-ui找出起始位置(粉紅色框的位置在響應式設計中會保持警惕)和jquery動畫方法來動畫元素。

此外,我必須將單擊的方向存儲在範圍內,並且我將初始位置和動畫設置為enter事件偵聽器中的結束位置。

我一直在閱讀和試驗很多內置動畫鉤子的角度,但無法找出一種從相對/動態位置動畫元素的正確方法。

有沒有更好的方法來實現角js方式相同的用戶體驗..?


如果我正確理解你的問題(如果沒有,請告訴我); 我認為解決問題的一種方法是這樣的:

假設您的產品的尺寸(寬度)恆定 - 設置為50px或其他 - ; 你可以將粉紅元素的位置設置為絕對; 然後使用ng-repeat為粉紅色元素,在html中使用簡短的ng-style屬性,如下所示:

<div ng-repeat="item in products" ng-style="{'left': $index*50 + 'px'}" ng-click="add-to-purchased($index)"></div>

以及購買的產品:在“購買”陣列中使用ng-repeat而不是在“添加購買”功能中使用ng-repeat,在將產品推送到“已購買”陣列後,您可以簡單地將產品設置為“頂部” :'與邊界元素'和“左”的高度距離等於{$ scope.purchased.length * 50 +'px'}。 然後使用ng-class(帶有切換)為著色和其他css內容添加一個類...(你也可以考慮轉換顏色變化。你可能知道)

我還認為你可以處理不同的高度和頂部問題(如果產品的數量超過一行的容量),使用ng-class,根據以下內容添加具有新“頂部”值的類:($ index> some-數字),以及上部元素的另一個ng-class(位於邊界元素頂部的元素),改變它的高度......

我希望這可以幫到你

更新:

不幸的是,我沒有理解這個問題。 但現在看問題,我認為有一種方法可以更加動態地做到這一點。

$scope.purchase函數中,你可以使用$broadcast你的指令發送消息,並像這樣傳遞被點擊的元素(對於庫存中的任何元素,無論是否使用ng-repeat創建):

<div class="stock" ng-click="purchase($event)"></div>

和:

$scope.purchase = function(event) {
  $scope.purchased.push($scope.products.pop());
  $scope.$broadcast('purchaseHappened', event.target);
};

在你的指令中,放入事件監聽器:

scope.$on('purchaseHappened', function(event, target) {
     //catch target in here, and then use it's position to animate the new elements...
})

我想你也可以使用target.getBoundingClientRect()來獲取元素相對於視口( .left.left ,...)的位置,而不是jquery-ui的.position如果你想...

它離解決方案更近了嗎?


此解決方案的一個改進是,它消除了在Purchase函數中向作用域添加信息的需要,並且它避免了通過使用“source”指令和將源信息存儲在控制器屬性中來混合模型數據和UI細節。 這個例子很簡單,當然可以改進。 關鍵是管理流程所需的數據永遠不會通過範圍公開。

如果目標元素被從DOM中刪除(即它是ng-repeat的一部分,那麼必須稍微修改此解決方案以計算並存儲動畫起始位置作為monitor.click處理程序的一部分而不是存儲目標元素本身。

動畫的方法在我看來是任意的。 這個例子使用了OP的jqueryUI動畫方法,但是它可以與css過渡或使用$ animate一樣好用。

here一個完整的例子

angular.module('app', [])
.controller('main', function($scope) {
  $scope.products = [{},{}];
  $scope.purchased = [{}];
  $scope.Purchase = function() {
    $scope.purchased.push({});
  };
})
.directive('source', function(){
  return {
    controller: function($scope) {
    }
  };
})
.directive('originator', function(){
  return{
    require: '^source',
    priority: 1,
    link:{
      pre: function(scope, element, attr, ctrl){
        element.on('click', function(evt){
          ctrl.target = evt.target;    
        });
      } 
    }
  };
})
.directive('sink', function(){
  return {
    require: '^source',
    link: function(scope, element, attr, ctrl){
      var target = ctrl.target;
      if(target){
        var $target = $(target);
        //animate from target to current position
        element.position({
            my: 'center',
            at: 'center',
            of: $target,
            using: function(pos, data) {
              $(this).css(pos);
              $(this).animate({
                top: 0,
                left: 0
              });
            }
          });
        ctrl.target = undefined;
      }
    }
  };
});




jquery-ui