mattrothenberg / vue-flip-toolkit

A Vue.js port of the wonderful react-flip-toolkit by @aholachek
https://keen-davinci-e49eba.netlify.com/
315 stars 17 forks source link

inverseFlipId transition not work properly in v-for loop #22

Closed Razz21 closed 4 years ago

Razz21 commented 4 years ago

Hi. I am trying to implement flip to list items using v-for loop, but unfortunately inverseFlipId does not prevent from content scaling. Transition works fine using simple v-if directive for every item in array, but it is not what i am after. example code

<template>
  <Flipper :flip-key="active" style="display:flex">
    <div v-for="(item,idx) in items" :key="idx">
      <button @click="active=idx">{{idx}}</button>
        <Flipped flip-id="square" scale translate v-if="active===idx">
          <div class="item">
           <Flipped inverse-flip-id="square" scale >
             <div>
              <component :is="current"/>
             </div>
           </Flipped>
         </div>
       </Flipped>
    </div>
  </Flipper>
</template>
<script>
import { Flipper, Flipped } from "vue-flip-toolkit";
import one from "@/components/one";
import two from "@/components/two";

export default {
  components: { Flipper, Flipped, one, two},
  data() {
    return {
      items: [{ component: one }, { component: two }],
      active: 0
    };
  },
  computed: {
    current() {
      return this.items[this.active].component;
    }
  },
};
</script>

Thanks.

mattrothenberg commented 4 years ago

What "doesn't work" in this instance? I'm not sure I understand from your Codesandbox what type of transition you're looking to achieve.

Razz21 commented 4 years ago

Thanks for quick response. I need to prevent content scaling during transition. In example code text scale with container and I want to avoid this.

mattrothenberg commented 4 years ago

Gotcha. This one will require some deeper investigation.

I'm observing some pretty big differences between Vue/React implementations of your example.

In the meantime, PRs are welcome if you notice something glaringly wrong in my implementation here!

mattrothenberg commented 4 years ago

One thing to watch out for is that the Flipped component makes some naïve assumptions about your markup.

For instance, when an inversed element gets registered, it emits the following payload to its parent Flipper

this.addInvertedElement({
  element: this.$el,
  parent: this.$parent.$el,
  opacity: this.opacity,
  scale: this.scale,
  translate: this.translate
});

If $this.parent.$el corresponds to the wrong DOM node, you'll likely get a funky transition.

I also encourage you to read the react-flip-toolkit docs where Alex calls out a few gotchas around inversion.

By default, both the scale and the translation transforms of the parent will be counteracted (this allows children components to make their own FLIP animations without being affected by the parent). But for many use cases, you'll want to additionally specify the scale prop to limit the adjustment to the scale and allow the positioning to move with the parent.

Note: the DOM element with the inverse transform should lie flush against its parent container for the most seamless animation.

That means any layout styles — padding, flexbox, etc—should be applied to the inverted container (the element wrapped with a Flipped component with an inverseFlipId) rather than the parent Flipped container.

Razz21 commented 4 years ago

Good explanation, but still does not resolve my problem. I do not understand why (and how) v-for affects this plugin, because outside loop everything works fine.

mattrothenberg commented 4 years ago

@Razz21 What makes you certain it's the v-for that's causing your issue? You'll note there are multiple examples in this repository that leverage v-for plus inverseFlipId.

Moreover, by combining v-if and v-for you're violating the following ESLint Rule which can absolutely cause some weird rendering scenarios. – https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-use-v-if-with-v-for.md

I'd wager it has something to do with your use of slots and dynamic components, given the naïve way in which Flipped components register themselves. Remember that by rendering a slot, you're adding an extra div to your markup which you would then need to account for in the eyes of flip-toolkit.

Razz21 commented 4 years ago

Yes, I am aware of combining v-for and v-if in Vue. In your examples you usually use different flip-ids for every item, but I am trying to implement something similar to this example from 'react-flip-toolkit' where every item has own dropdown and share component. Maybe I missed something, I am not an expert in Vue.

mattrothenberg commented 4 years ago

The trick with Vue is that if you use a <slot />, you're necessarily adding an extra div to your markup. This is troublesome for vue-flip-toolkit, as the library assumes that the parent of a <Flipped /> instance with an inverseFlipId is indeed the parent whose animation you're trying to cancel out.

With the <slot /> in the mix, you're now reference the wrong parent element and hence no cancelling out of the animation.

Razz21 commented 4 years ago

I am not sure, creating flip this way

<item flipId="square" v-if="active===1">// Flipped wrapper with <slot/>
    <two/>//example content
</item>

<item flipId="square" v-else>
    <one/>//example content
</item>

slot do not interfere Flipped component. InverseFlipId inside example <item> component also works nice.

mattrothenberg commented 4 years ago

@Razz21 All I'm suggesting to you is that if you use a slot, you're potentially adding an additional div to your markup. This has the potential to confuse flip-toolkit, as the library expects a certain hierarchy of DOM elements in order to coordinate animations/cancellations accordingly.

Feel free to clone repo locally and tinker with the components in storybook (yarn storybook) if you think there's a bug to be worked out. I welcome your pull request!

mattrothenberg commented 4 years ago

@Razz21 Take a look at https://codesandbox.io/s/beautiful-dust-97bdx and let me know if this is the correct effect.

I noticed that by omitting the key from the Flipped component, I was able to get a smoother transition.

Razz21 commented 4 years ago

Yes, this is an effect I am after, nice solution btw. It seems the key property or v-for loop somehow conflicts with Flipped component, but at least it is working now. Thank you for your help!