4
votes

vue.js insert block pour chaque 6ème élément de boucle

J'ai des offres de rendu de liste de cartes à travers la boucle. Tous les 3 éléments col (bootstrap), j'ajoute une ligne div. Maintenant, je dois ajouter un autre élément col (bloc de bannière) pour chaque 6ème élément. Pour rendre quelque chose comme ça:

 entrez la description de l'image ici

Comment puis-je implémenter cela?

Mon code maintenant

< pré> XXX


0 commentaires

7 Réponses :


4
votes

Cela devrait faire exactement ce que vous voulez .. J'ai dû manipuler les données car le langage de modélisation de Vue n'est pas conçu pour gérer la logique de ce type de cas d'utilisation

HTML

created () {
    while (this.items.length > 0) {
      const howMany = (this.rows.length % 3 === 0) ? 3 : 2
      const row = this.items.splice(0, howMany)
      if (howMany === 2) row.push('banner')
      this.rows.push(row)

    }
},


8 commentaires

S'il fait cela, le 6e disparaîtra,


Mais qu'en est-il des lignes div conduisant pour chaque ligne 3d?


Je suis désolé, mais le 6ème élément sera remplacé par une bannière. Est-ce ce qu'il veut?


@RaphaelParreira Je l'ai changé pour que cela ne se produise pas, mais j'essaie de comprendre le problème des 3 par ligne


Ok je pense que je l'ai compris :)


Ne marche pas. Je pense parce que je reçois mes offres du serveur par axios (en méthode)


Ah ok bien vous pouvez simplement mettre cette boucle while créée dans la réponse de votre serveur


Parfait mais un dernier moment, la bannière n'a pas de paramètres d'offres (comme le nom, la description, l'url, etc.) que j'appelle en html {{offer.name}} ...



1
votes

Je suppose que vous voulez ajouter une bannière tous les 6 éléments, mais vous voulez afficher le 6e. Je gérerais cela sur mon objet de données, en insérant la bannière à l'intérieur. C'est plus facile. Vous pouvez diviser votre tableau de cette façon.

let firstPart = myData.slice(0,5)
let lastPart = myData.slice(5,)

let newData = [...firstPart, banner, ...lastPart]

Maintenant, il vous suffit de le faire tous les 6 éléments.


0 commentaires

2
votes

pour la boucle:

.mycol:nth-child(3n+1){
 clear:left;
}

pour une nouvelle ligne pour chaque troisième col, vous pouvez utiliser css

    <div class="mycol" v-for="(offer,ind) in offers">
      <template v-if="ind % 5 == 0">
       <h2>banner</banner>
      </template>
      <template v-else>
       <h2>{{offer.name}}</h2>
       <h2>{{offer.desc}}</h2>
      </template>
    </div>


1 commentaires

c'est assez facile et simple,



4
votes

Je vous recommande de faire moins de programmation dans la vue et plus dans le modèle de vue. Créez un calculé qui divise vos données en séries d'offres et de bannières, ainsi qu'en lignes, puis utilisez-le de manière simple.

<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div class="row" v-for="row in rows">
    <div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="item in row">
      <div v-if="item.type === 'Banner'" class="banner box">
        <h2>{{item.name}}</h2>
      </div>
      <div v-else class="offer box">
        <h2>{{item.name}}</h2>
      </div>
    </div>
  </div>
</div>
#app {
  display: grid;
}

.row {
  display: grid;
  grid-gap: 2rem;
  grid-template-columns: repeat(3, auto);
  justify-content: left;
}

.box {
  width: 8rem;
  height: 8rem;
}

.banner {
  background-color: #f9c;
}

.offer {
  background-color: #99f;
}
const chunk = (arr, size) =>
  arr
  .reduce((acc, _, i) =>
    (i % size) ?
    acc :
    [...acc, arr.slice(i, i + size)], []);
    
new Vue({
  el: '#app',
  data: {
    offers: []
  },
  computed: {
    rows() {
      const withBanners = chunk(this.offers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b), []);

      return chunk(withBanners, 3);
    }
  },
  mounted() {
    setTimeout(() => {
      this.offers = [{
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      },
      {
        name: 'offer'
      }
    ];
    }, 500);
  }
});


5 commentaires

Mais je reçois des offres du serveur via axios


Peu importe d'où vous l'obtenez. Le calcul sera correct lorsque les offres seront attribuées.


J'ai mis à jour l'extrait pour attribuer des offres après le démarrage du programme.


Et encore un problème, la bannière ne remplace pas (dans la requête) la 6ème offre et cette offre tombe dans une nouvelle ligne et j'ai 7 cols, pas 6. Plus la bannière s'ajoute à la fin, peu importe le nombre d'offres dans la liste


Ce sont toutes des choses que vous pouvez gérer dans le calcul. Faites-lui générer les données avec lesquelles vous souhaitez travailler.



0
votes

Je recommande d'utiliser flex si c'est possible. Le code ressemblera donc à: http://jsfiddle.net/n89dbo37/

new Vue({
  el: '#app',
  data() {
    return {
        items: _.times(20, i => ({type: 'offer'})),
    };
  },
  computed: {
    itemsWithBanners() {
      let result = [];
      this.items.forEach((item, idx) => {
        if (idx && idx % 5 === 0) {
            result.push({type: 'banner'});
        }
        result.push(item);
      });
      return result;
    },
  },
});


0 commentaires

0
votes

Merci pour tout le monde, j'ai pris la solution Roy J, reconstruire pour mon cas et obtenir le résultat. Mon code:

<template>
  <div class="section-space80 results-col" >
    <div class="container" >
      <div class="row">
          <div class="col-md-12">
            <div class="wrapper-content bg-white pinside40">
              <div class="row" v-for="row in rows">
                <div v-for="offer in row" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">
                  <div class="lender-listing" v-if="offer.type && offer.type === 'Banner'">
                    <div class="lender-head">
                        Banner
                    </div>
                  </div>
                  <div class="lender-listing" v-if="offer.mfoName">
                    <div class="lender-head">
                        <div class="lender-logo">Offer</div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
      </div>
    </div>
  </div>
</template>

<script>
  const chunk = (arr, size) =>
  arr
  .reduce((acc, _, i) =>
    (i % size) ?
    acc :
    [...acc, arr.slice(i, i + size)], []);

  import axios from 'axios'
  export default {
    data() {
      return {
        showOffers: true,
        loanOffers: [],
        isVisible: false,
        loadMore: true,
        offset: 0,
        rows: ''

      }
    },

    methods: {
      getOffersList: function () {
        let dataElements = this
        dataElements.loading = true
        axios.get('/api/v1/getUserOffers')
          .then(function (response) {
            dataElements.loanOffers = response.data
            const withBanners = chunk(dataElements.loanOffers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b));
            dataElements.rows = chunk(withBanners, 3);
          })
      },
    },
    beforeMount(){
      this.getOffersList()
    }
  }

</script>


0 commentaires

-2
votes

Je propose d'utiliser un modèle et de faire une boucle dessus. Ensuite, à l'intérieur, vous vérifiez v-if = "i% 6" -> votre article v-else -> votre annonce.


1 commentaires

Veuillez fournir un exemple de code