Не удается получить вычисленное свойство (массив)

#vue.js

#vue.js

Вопрос:

Пытаюсь получить « displayImages массив как вычисляемое свойство. Использование значения по умолчанию « selected property = 0 . this.selected изменяется соответствующим образом при наведении курсора мыши и событиях щелчка.

При попытке получить вычисленное « displayImages он говорит:

 "this.variations[this.selected] is undefined."
  

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

 <template>
  <div id="product-page">
    <v-card width="100%" class="product-card">
      <div class="image-carousel">
        <v-carousel height="100%" continuos hide-delimiters>
          <v-carousel-item
            v-for="(image, i) in displayImages"
            :key="i"
            :src="image"
          >
          </v-carousel-item>
        </v-carousel>
      </div>
      <div class="details">
        <h2>{{ this.title }}<br />Price: ${{ this.price }}</h2>
        <p>{{ this.details }}</p>
        <ul style="list-style: none; padding: 0">
          <li
            style="border: 1px solid red; width: auto"
            v-for="(color, index) in variations"
            :key="index"
            @mouseover="updateProduct(index)"
            @click="updateProduct(index)"
          >
            {{ color.color }}
          </li>
        </ul>
        <div class="buttons">
          <v-btn outlined rounded
            >ADD TO CART<v-icon right>mdi-cart-plus</v-icon></v-btn
          >
          <router-link to="/shop">
            <v-btn text outlined rounded> BACK TO SHOP</v-btn>
          </router-link>
        </div>
      </div>
    </v-card>
  </div>
</template>

<script>
export default {
  name: "Product",
  props: ["APIurl"],
  data: () => ({
    title: "",
    details: "",
    price: "",
    variations: [],
    selected: 0,
  }),
  created() {
    fetch(this.APIurl   "/products/"   this.$route.params.id)
      .then((response) => response.json())
      .then((data) => {
        //console.log(data);
        this.title = data.title;
        this.details = data.details.toLowerCase();
        this.price = data.price;
        data.variations.forEach((element) => {
          let imagesArray = element.photos.map(
            (image) => this.APIurl   image.url
          );
          this.variations.push({
            color: element.title,
            images: imagesArray,
            qty: element.qty,
            productId: element.productId,
          });
        });
      });
  },
  computed: {
    displayImages() {
      return this.variations[this.selected].images;
    },
  },
  methods: {
    updateProduct: function (index) {
      this.selected = index;
      console.log(index);
    }
  },
};
</script>
  

Комментарии:

1. Это потому, что при первом отображении вашего DOM this.variations массив пуст и поэтому this.variations[this.selected] возвращает значение undefined . Попытки доступа .images к undefined объекту выдадут ошибку. Вы должны добавить защитное предложение, где, если оно не определено, просто верните пустой массив.

2. @Terry спасибо!… любой другой способ предотвратить это, возможно, с помощью надлежащих перехватов жизненного цикла? или это способ сделать это .. еще раз спасибо

3. Насколько я знаю, нет, поскольку массив заполняется асинхронно, поэтому он всегда пуст в начале.

4. @Terry спасибо .. если вы хотите, чтобы я принял ваш ответ, вам нужно «ответить на вопрос» ниже

5. Считайте, что это сделано 🙂

Ответ №1:

Чтобы должным образом расширить мой комментарий, причина, по которой вы сталкиваетесь с ошибкой, заключается в том, что при обращении к вычисляемому в шаблоне this.variations это пустой массив. Оно заполняется только асинхронно, поэтому, скорее всего, оно пустое, когда VueJS пытается использовать его при рендеринге виртуального DOM.

По этой причине будет возвращен доступ к элементу внутри него по индексу (заданному как this.selected ) undefined . Поэтому попытка получить доступ к свойству, вызываемому images в undefined объекте, вернет ошибку.

Чтобы устранить эту проблему, все, что вам нужно, это ввести защитное предложение в ваш вычисляемый как таковой:

 computed: {
  displayImages() {
    const variation = this.variations[this.selected];

    // GUARD: If variation is falsy, return empty array
    if (!variation) {
      return [];
    }

    return variation.images;
  },
}
  

Бонусный совет: если вы однажды захотите использовать TypeScript, вы можете даже упростить его как таковой… но это обсуждение для другого дня 😉 на данный момент необязательная цепочка и оператор объединения с нулевым значением поддерживаются только новейшими версиями браузеров evergreen.

 computed: {
  displayImages() {
    return this.variations[this.selected]?.images ?? [];
  },
}
  

Ответ №2:

Чтобы избежать такого рода ошибок, вы должны использовать свойство безопасной навигации.

Помните, что это полезно только при загрузке приложения.

Попробуйте что-то подобное:

 <script>
export default {
  name: 'Product',
  computed: {
    displayImages() {
      if (this.variations[this.selected]) {
        return this.variations[this.selected].images;
      }
      return [];
    },
  },
};
</script>