So animieren Sie ng-repeat-Elemente relativ zu Klickereignissen, die die Änderung verursachen

Lesezeit: 8 Minuten

Ich versuche, einen Benutzer zu animieren, Elemente aus verschiedenen Gruppen von Elementen auszuwählen. Das Element sollte von dem angeklickten Satz zu seiner neuen Position in der Liste der ausgewählten Elemente animiert werden.

Betrachten Sie in der folgenden Demo die rosa Kästchen als verfügbare Elemente und das umrandete Kästchen als Liste der ausgewählten Elemente (blaue Kästchen). Der Benutzer kann ein Element auswählen, indem er auf eines der rosa Kästchen klickt:

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>

Nun, es funktioniert irgendwie – aber ich verwende jQuery-ui, um die Startposition herauszufinden (Die Position der rosa Kästchen wird in einem responsiven Design vorsichtig sein) und die jquery animate-Methode, um das Element zu animieren.

Außerdem muss ich die angeklickte Richtung im Bereich speichern und ich setze sowohl die Anfangsposition als auch die Animation zur Endposition in der enter Ereignis-Listener.

Ich habe viel mit eingebauten Animationshaken in Winkeln gelesen und experimentiert, konnte aber keinen richtigen Weg finden, Elemente aus relativen/dynamischen Positionen zu animieren.

Gibt es einen besseren Weg, um die gleiche Benutzererfahrung auf eckige js-Weise zu erreichen?

  • Versuchen Sie, dasselbe Verhalten zu erreichen, ohne eine Jquery-Benutzeroberfläche zu verwenden?

    – Kiran Shakya

    25. Januar 2016 um 6:37 Uhr

  • @kiran Die Verwendung der jQuery-Benutzeroberfläche zum Ermitteln der Position ist in Ordnung. Ich dachte, es wird eine bessere Möglichkeit geben, dies in Winkeln zu strukturieren, z. B. ohne dass angeklickte Anweisungen im Controller-Bereich gespeichert werden müssen … Ich glaube auch nicht, dass das Ganze in ausgeführt wird $animate.on('enter' ist der richtige Weg

    – TJ

    25. Januar 2016 um 6:40 Uhr

  • Es könnte von Vorteil sein, sich ng-animate-ref anzusehen, da es dazu gedacht ist, ein Element über Anwendungsbereiche hinweg nach Belieben zu animieren. Ich denke, es ist normalerweise für eine 1-zu-1-Beziehung gedacht. Wenn Ihr Element also mehrere Instanzen wie Ihre Demo hervorbringen kann, müssen Sie möglicherweise das Ende der Animation einhaken und die Referenz herausziehen, sobald sie abgeschlossen ist, damit die nächste Iteration erfolgt animiert nicht mehrere Elemente. Dokumente: docs.angularjs.org/api/ngAnimate

    – Colton McCormack

    25. Januar 2016 um 16:55 Uhr

  • @ColtMcCormack Das funktioniert nur beim Wechseln zwischen Ansichten …

    – TJ

    26. Januar 2016 um 14:05 Uhr

  • Es scheint in Ordnung zu sein, Sie möchten vielleicht nur das Modell an das Div anhängen, damit Sie die Einkäufe einfach durchlaufen können und dann das Modell und die darin enthaltenen Datensätze entsprechend durchlaufen und verarbeiten können.

    – Fallenreaper

    27. Januar 2016 um 19:07 Uhr

Benutzer-Avatar
GHB

wenn ich Ihre Frage richtig verstanden habe (bitte sagen Sie mir, wenn nicht); Ich denke, eine Möglichkeit, das Problem zu lösen, geht so:

unter der Annahme, dass die Größe (Breite) Ihrer Produkte konstant ist – auf 50 Pixel oder so eingestellt -; Sie können die Position der rosa Elemente auf absolut setzen; Verwenden Sie dann ng-repeat für rosa Elemente mit einem kurzen Attribut im ng-Stil innerhalb des HTML-Codes wie folgt:

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

und zu den gekauften Produkten: Anstatt ng-repeat für das Array “gekauft” zu verwenden, können Sie das Produkt in der Funktion “zu gekauften hinzufügen”, nachdem Sie das Produkt in das Array “gekauft” verschoben haben, einfach nach oben animieren : ‘der Höhenabstand zum umrandeten Element'” und “links” gleich {$scope.purchased.length*50 + ‘px’}. fügen Sie dann eine Klasse mit ng-class (mit einem Schalter) zum Färben und anderen CSS-Sachen hinzu … (Sie können auch den Übergang für Farbänderungen in Betracht ziehen. wie Sie wahrscheinlich wissen)

Ich denke auch, dass Sie mit einer ng-Klasse, die Klassen mit neuen “Top” -Werten hinzufügt, basierend auf: ($index> some- Nummer) und eine weitere ng-Klasse für das obere Element (das Element, das sich über dem umrandeten Element befindet), das seine Höhe ändert …

Ich hoffe, das war hilfreich


Aktualisieren:

leider hatte ich die frage nicht richtig verstanden. Aber wenn ich mir das Problem jetzt anschaue, denke ich, dass es eine Möglichkeit gibt, dies dynamischer zu tun.

innerhalb der $scope.purchase Funktion, mit der Sie Ihre Anweisung senden können $broadcast und das angeklickte Element wie folgt übergeben (für jedes Element auf Lager, entweder mit ng-repeat erstellt oder nicht):

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

und:

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

und fügen Sie in Ihre Direktive den Ereignis-Listener ein:

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

Ich denke, Sie können auch verwenden target.getBoundingClientRect() um die Position des Elements relativ zum Ansichtsfenster zu erhalten (.top , .left ,…) anstelle von jquery-ui’s .position falls Sie es wollen…

ist es näher an der Lösung?

  • Sie haben viele fragliche Dinge übersehen. 1) Dies ist ein ansprechendes Design, also ist nichts konstant 2) Die Verwendung von ng-repeat ist keine Option (andere externe Anweisungen wie ui-sortable verlassen Sie sich darauf), deshalb habe ich speziell gefragt, “Wie man ng-Wiederholungselemente animiert”. Wenn alles konstant wäre, könnte ich einfach die Pixelpositionen in CSS-Klassen definieren und sie umschalten 3) die geklickte Mausposition erkennen

    – TJ

    23. Januar 2016 um 5:13 Uhr


  • “Sie können das Produkt einfach nach oben animieren: ‘der Höhenabstand zum umrandeten Element'” und “links” gleich {$scope.purchased.length*50 + ‘px’}” – wie man dies auf eckige Weise macht, während man es benutzt ng-repeat und Responsive Design ist die Frage. Angenommen, wir können die aktuelle Position von Lagerbeständen und Produkten mit jquery ui finden position() Methode, aber dafür sollten wir zuerst die angeklickte Aktie erkennen. und dann frage ich mich, wie man diese dynamischen Informationen für Animationen in Winkel-NG-Wiederholung verwendet, auf eine bessere Art und Weise, als ich das alles bereits getan habe

    – TJ

    23. Januar 2016 um 5:15 Uhr


  • Was ich bereits habe, funktioniert besser als Ihr Vorschlag: 1) Geht nicht davon aus, dass etwas konstant ist 2) erkennt die angeklickte Position (indem sie im Controller-Bereich gespeichert wird, was ich für eine schlechte Methode halte) 3) funktioniert mit ng-repeat . Ich dachte, es gibt einen besseren Weg, dies in Angular zu tun, also werde ich die Angular-Experten fragen und etwas Neues lernen

    – TJ

    23. Januar 2016 um 5:22 Uhr


  • ich glaube ich habe deine Frage gerade verstanden! Lassen Sie mich also noch ein Detail fragen. Besteht der Warenbestand immer in dieser Form aus zwei Elementen, oder ist das auch nur ein Beispiel? Ich meine, in echten Codes, wirst du ng-repeat auch für sie verwenden? Weil ich an einen anderen Weg für das Problem gedacht habe.

    – GHB

    23. Januar 2016 um 6:14 Uhr


  • In meinem speziellen Fall sind es nur zwei davon. Aber eine allgemeine Lösung könnte in Zukunft jemand anderem helfen

    – TJ

    23. Januar 2016 um 6:34 Uhr

Benutzer-Avatar
Joe Enzminger

Diese Lösung ist insofern eine Verbesserung, als sie das Hinzufügen von Informationen zum Umfang in der Kauffunktion überflüssig macht und das Mischen von Modelldaten und UI-Details vermeidet, indem eine “Quellen”-Direktive verwendet und Herkunftsinformationen in einer Controller-Eigenschaft gespeichert werden. Das Beispiel ist vereinfacht und kann natürlich verbessert werden. Der entscheidende Punkt ist, dass die zur Verwaltung des Prozesses erforderlichen Daten niemals über den Geltungsbereich offengelegt werden.

Wenn das Zielelement aus dem DOM entfernt werden soll (dh es ist Teil einer ng-Wiederholung), müsste diese Lösung leicht modifiziert werden, um die Startpositionen der Animation als Teil des monitor.click-Handlers zu berechnen und zu speichern, anstatt sie zu speichern das Zielelement selbst.

Die Methode der Animation erscheint mir willkürlich. Dieses Beispiel verwendet die jqueryUI-Animationsmethode des OP, aber es würde genauso gut mit CSS-Übergängen oder mit $animate funktionieren.

Ein vollständiges Beispiel ist hier

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

  • Der Unterschied, den ich sehe, besteht darin, dass die Eigenschaft schließlich zum Controller selbst hinzugefügt wird und nicht $scope zusammen mit zusätzlichen Anweisungen, Event-Handlern usw. … Das sieht aus wie eine komplexe Form dessen, was ich habe … Wie auch immer, ich gebe dies für die Zeit und Mühe, die ich investiert habe 🙂

    – TJ

    29. Januar 2016 um 6:10 Uhr


1130860cookie-checkSo animieren Sie ng-repeat-Elemente relativ zu Klickereignissen, die die Änderung verursachen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy