Animating views before destruction in Emberjs

前端 未结 3 835
走了就别回头了
走了就别回头了 2021-01-12 22:53

There is currently no way to delay view destruction in Ember. This presents a problem when you want to animate the view before destroying it.

So, I currently have th

相关标签:
3条回答
  • 2021-01-12 23:41

    Try this

    Ember.Route.extend({
    actions: {
    willTransition: function(transition) {
            $.each(Ember.View.views, function(index, value) {
                var popUpView = value.get('classNames').find(function(item) {
                    return item == '[nameofyourclass]';
                });
                if(!Em.isEmpty(popUpView) && value.get('visible')) {
                    value.set('visible', false);
                    value.get('controller').set('previousTransition', transition);
                    transition.abort();
                }
            });
            return true;
    },
     }
        });
    
    Ember.View.extend({
    classNames: ['nameofyourclass'],
    classNameBindings: ['visible:element-visible'],
    
    visible: false,
    
    didInsertElement: function() {
        var t = this,
                controller = this.get('controller');
        this.$()
        .on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() {
            if(!t.get('visible')) {
                var previousTransition = controller.get('previousTransition');
                if(!Em.isEmpty(previousTransition)) {
                    controller.set('previousTransition', null);
                    previousTransition.retry();
                } else { // fallback
                    controller.transitionToRoute('index');
                }
            }
        });
        Em.run.next(this, function() {
            this.set('visible', true);
        });
    },
    });
    
    0 讨论(0)
  • 2021-01-12 23:49

    This is just an spontaneous idea from my side:

    This is the implementation of destroyElement in Ember.View (Link to Source):

     destroyElement: function() {
        return this.currentState.destroyElement(this);
      },
    

    You could try to override this method to do your animation:

    destroyElement: function() {
        var completeCallback = function(){
            return this.currentState.destroyElement(this);
        }
        this.$().fadeOut(completeCallback); //or whatever animation
    },
    
    0 讨论(0)
  • 2021-01-12 23:54

    My preferred method for handling pre-destroy animation is using Em.Evented. Have the view listen for an event that is called in the method or action that will start destruction of the view and delay the destruction until the method triggered by the event is complete (using the run loop). For example:

    SomeView = Em.View.extend({
    
      _listen: function() {
        this.get('controller').on('closeChildView', this, this.hide);
      }.on('willInsertElement'),
    
      hide: function() {
        this.$().fadeOut(this.get('controller.duration'));
      }
    
    });
    

    And then in the controller:

    Em.ObjectController.extend(
      Em.Evented, { // Important mixin!
    
      duration: 500,
    
      actions: {
        removeSomeChildView: function() {
          this.trigger('closeChildView');
    
          Em.run.later(this, function() {
            // Then do the stuff to destroy the view here.
          }, this.get('duration'));
        }
      }
    
    });
    

    Alternatively, you can use the this.removeFromParent() method in the view to consolidate the hiding and removing of the view.

    If the destruction is actually started in the view itself, you could use these same principles before you call the destroy method and use .on('willDestroyElement') to send an action to the controller or route should you need a callback after the view has been removed.

    Pre-destroy animation can be done in the same way by running this.$().hide on didInsertElement and then using a show() method to transition the view element.

    Aligning JS and CSS transition times

    If you doing some of all of your transitions in CSS you'll want to make sure the transition times between the CSS and JS are aligned. This is pretty simple. In your view, make sure the CSS transition takes place on the view's element and then:

    SomeView = Em.View.extend({
      transitionDuration: Em.computed.alias('controller.transitionDuration'),
    
      setTransitionDuration: function() {
        var ms = parseFloat(this.$().css('transition-duration')) * 1000; // In milliseconds
    
        if (ms) {
          this.set('transitionTime', ms);
        }
      }.on('didInsertElement'),
    });
    

    This will update the transition duration on your view and controller to match whatever you write in your CSS. Whatever value you specify for transitionDuration on the controller is the fallback value for transitionDuration and you could add an if () in the above method should you want to do some validating before overriding the default JS transitionDuration.

    0 讨论(0)
提交回复
热议问题