简体   繁体   中英

Vue.js: best way to transition elements without using v-for and v-if simultaneously?

I am using v-for to create multiple <p> elements. The v-for is wrapped with the Vue <transition> component because I want each <p> to animate in if the v-if condition is satisfied. Here is that code below:

 <transition name="fade"> <p v-for="(quote, idx) in game.quotes" <-- game.quotes comes from VUEX :key="`game-quote-${idx}`" class="quote-box__current_quote" v-if="game.currentQuoteIdx === idx" >"{{ quote.content }}"</p> </transition>

However, I am getting ESLINT errors due to the vue/no-use-v-if-with-v-for rule.

After researching that rule I was pointed to the following Vue style guide: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential . The guide recommends to avoid using v-for and v-if on the same element. I would like to animate each element in / out using the <transition> wrapper component (only one <p> tag should be visible at one time). Is there a more ideal way to achieve what I am doing without using v-if and v-for on the same element?

Additional Issue: I am getting the following error in reference to game.quotes in v-for="(quote, idx) in game.quotes" :

The 'undefined' variable inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'.

game.quotes is coming from Vuex and the array does not need to be filtered. Why is ESLINT recommending that I create a computed property and return a filtered array?

FILE ON GITHUB - Line 10

The official documentation states that all conditional rendering within loops should be done through computed functions. Do your conditional sifting in the computed (coming from a getter if you're using Vuex) and then put that in the template.

Official style guide for this: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential

Create a computed property and return a filtered array. It's because your code is like filtering an array because of v-if attached inline with your v-for. In short, your just filtering the item you want to display in your loop. Why not usingcomputed properties ? It is safe and easy to handle.

Take this example, which is very similar to yours: Don't show the li 's that are not necessary. Combining v-for and v-if works perfectly fine, if not best practice. However, there is an easier way.

<h2>Items:</h2>
<ol id="list">
  <li v-for="item in items" v-if="visible.includes(item)" :id="'item-'+item">
    {{ item }}
  </li>
</ol>

https://jsfiddle.net/oLjuy5bv/1/

What we can do instead, as the two other answers state, is created a computed method and calculate the list for the v-for and remove the v-if .

<h2>Items:</h2>
<ol id="list">
  <li v-for="item in visible_items" :id="'item-'+item">
    {{ item }}
  </li>
</ol>

computed: {
  visible_items () {
    return this.items.filter(item => this.visible.includes(item))
  }
},

https://jsfiddle.net/17Ln5mw8/

What I think you're after then is something like this, which uses a method due to the idx and possibly game context (I don't know the logic specifically):

<transition name="fade">
  <p
    v-for="(quote, idx) in gameQuotesByIdx(idx)"
    :key="`game-quote-${idx}`"
    class="quote-box__current_quote"
  >"{{ quote.content }}"</p>
</transition>

methods: {
  gameQuotesByIdx(idx) {
    return ...
  }
},

Where I think you might have an issue is reactivity, meaning the component might not respond to changes in array state (which computed resolves above for me). To get to that then, you might want to consider that a refactor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM