Подсчитать вхождения дочернего компонента - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть один файловый компонент, подобный этому:

<template>
    <div>
        <template v-if="offers.length > 3">
            <a href="#">View all offers here</a>
        </template>

        <template v-else-if="offers.length > 1">
            <offer v-for="offer in offers" :data="offer"></offer>
        </template>

        <template v-else-if="offers.length == 1">
            <offer :title="The offer" :data="offers[0]"></offer>
        </template>
    </div>
</template>

Исходя из числа offers, я выбираю, сколько визуализировать.

Вопрос: Как эффективно получить / посчитать количество <offer> компонентов? Мне также нужно, чтобы этот номер был реактивным.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Нет чистого пути как.

Вы можете сосчитать потомков текущего экземпляра, которые имеют определенный тип. Но вам придется вызывать логику «пересчета» на update hook (а также mounted).

Пример:

Vue.component('offer', {
  name: 'Offer',
  template: '<span> offer </span>'
})
new Vue({
  el: '#app',
  data: {
    offers: [1, 2],
    offerCount: 0
  },
  methods: {
    updateOfferCount() {
      this.offerCount = this.$children.filter(child => child.constructor.options.name === 'Offer').length;
    }
  },
  updated() {
    this.updateOfferCount()
  },
  mounted() {
    this.updateOfferCount()
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <div>
    <template v-if="offers.length > 3">
        <a href="#">View all offers here</a>
    </template>

    <template v-else-if="offers.length > 1">
        <offer v-for="offer in offers" :data="offer"></offer>
    </template>

    <template v-else-if="offers.length == 1">
        <offer :data="offers[0]"></offer>
     </template>
  </div>
  <br>
  <button @click="offers.push(123)">Add Offer</button> offerCount: {{ offerCount }}
</div>
0 голосов
/ 26 апреля 2018

Я отвечаю на это, основываясь исключительно на идее, что вы хотите считать экземпляры и разрушения Offer компонентов. Я не уверен, почему ты не считаешь offers.length. Может быть, другие вещи могут вызвать создание экземпляров.

Компонент должен генерировать события при создании и уничтожении и соответственно иметь родительский трек.

В качестве альтернативы (и, возможно, излишества) вы можете использовать Vuex и создать магазин, который Offer обязуется создавать и уничтожать. Это означает, что вам не нужно вручную прикреплять директивы @offer-created/destroyed каждый раз, когда вы помещаете <offer> в вашу разметку.

Оба метода включены в следующий пример:

const store = new Vuex.Store({
  strict: true,
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    }
  }
});

const Offer = {
  props: ["data"],
  template: "<div>{{data.name}}</div>",
  created() {
    console.log("Created");
    this.$emit("offer-created");

    this.$store.commit("increment");
  },
  destroyed() {
    console.log("Destroyed");
    this.$emit("offer-destroyed");

    this.$store.commit("decrement");
  }
};

const app = new Vue({
  el: "#app",
  store,
  components: {
    offer: Offer
  },
  data() {
    return {
      offers: [],
      offerCount: 0
    };
  },
  computed: {
    offerCountFromStore() {
      return this.$store.state.count;
    }
  },
  methods: {
    offerCreated() {
      this.offerCount++;
    },
    offerDestroyed() {
      this.offerCount--;
    },
    addOffer() {
      this.offers.push({
        name: `Item: ${this.offers.length}`
      });
    },
    removeOffer() {
      this.offers.pop();
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<div id="app">
  <div>Offer instances: {{offerCount}}</div>
  <div>Offer instances (from store): {{offerCountFromStore}}</div>
  <div>
    <div v-if="offers.length > 3">
      <a href="#">View all offers here</a>
    </div>
    <div v-else-if="offers.length > 1">
      <offer @offer-created="offerCreated" @offer-destroyed="offerDestroyed" v-for="offer in offers" :data="offer"></offer>
    </div>
    <div v-else-if="offers.length == 1">
      <offer @offer-created="offerCreated" @offer-destroyed="offerDestroyed" :data="offers[0]"></offer>
    </div>
  </div>
  <div>
    <button @click.prevent="addOffer">Add</button>
    <button @click.prevent="removeOffer">Remove</button>
  </div>
</div>

Проблема с попыткой использования $children заключается в том, что он по своей сути не реактивен:

Прямые дочерние компоненты текущего экземпляра. Обратите внимание, что нет Заказать гарантию на $children, и она не реагирует . Если ты найдешь пытаясь использовать $children для привязки данных, рассмотрите возможность использования Array и v-for для генерации дочерних компонентов, и используйте Array как источник истины.

...