Dari jawaban pada pertanyaan Apa yang mempengaruhi apakah properti yang dihitung Vue akan dihitung ulang atau tidak? Saya tahu itu

Vue tidak dapat mendeteksi perubahan berikut pada array:

Saat Anda langsung mengatur item dengan indeks, mis. vm.items[indexOfItem] = newValue Saat Anda mengubah panjang array, mis. vm.items.length = newLength

Ini jelas kasus lain karena saya secara eksplisit menetapkan nilai baru ke array.

Target

  1. Slider gambar harus menampilkan foto yang dipilih saat ini
  2. Ketika array photosURLs kosong, penggeser seharusnya menampilkan gambar dummy (seperti "tidak ada gambar").
  3. Saat product.photosURLs diperbarui, penggeser harus menampilkan foto yang diperbarui (atau dummy, jika semua foto telah dihapus).

Penerapan

Implementasi di bawah ini mencapai target pertama dan kedua.

Markup (pesek)

.ImageSliderForNarrowScreens
  .ImageSliderForNarrowScreens-ActiveImage-DefaultBackgroundUnderlay

    .ImageSliderForNarrowScreens-ActiveImage-ImageLayer(
      v-if="product.photosURLs.length < 2"
      :style="`background-image: url(${activeProductPhotoURL_ForImagesViewer});`"
    )

    template(v-else)
      .ImageSliderForNarrowScreens-ActiveImage-ImageLayer(
        :key="'IMAGE_SLIDER-IMAGE-'+activeProductPhotoArrayIndexForImagesViewer"
        :style="`background-image: url(${activeProductPhotoURL_ForImagesViewer});`"
        v-touch:swipe.left="switchImagesSliderToPreviousPhoto"
        v-touch:swipe.right="switchImagesSliderToNextPhoto"
      )

Logika (TypeScript)

Slider gambar mengacu pada product.photosURLs.

  • Saat pengguna beralih ke mode pengeditan, product.photosURLs akan disalin ke uploadedProductPhotosURLs, larik URL foto yang diperbarui tetapi belum dikirimkan.
  • Ketika uploadedProductPhotosURLs akan dikirimkan, uploadedProductPhotosURLs akan disalin ke product.photosURLs;
import { Vue, Component, Watch } from "vue-property-decorator";


@Component
export default class MyComponent extends Vue {

  private product!: Product;
  private uploadedProductPhotosURLs: Array<string> = [];

  /* --- Product photos viewing ------------------------------------------------------------------------------------ */
  private activeProductPhotoArrayIndexForImagesViewer: number = 0;

  private get activeProductPhotoURL_ForImagesViewer(): string {
    if (this.product.photosURLs.length === 0) {
      return PRODUCT_DUMMY_PHOTO_URL;
    }
    return this.product.photosURLs[this.activeProductPhotoArrayIndexForImagesViewer];
  }

  // --- Well, it does not matter, I just mentioned it in template
  private switchImagesViewersToNextProductPhoto(): void {
    this.activeProductPhotoArrayIndexForImagesViewer =
      this.activeProductPhotoArrayIndexForImagesViewer !== this.product.photosURLs.length - 1 ?
        this.activeProductPhotoArrayIndexForImagesViewer + 1 : 0;
  }

  private switchImagesViewersToPreviousProductPhoto(): void {
    this.activeProductPhotoArrayIndexForImagesViewer =
      this.activeProductPhotoArrayIndexForImagesViewer !== 0 ?
        this.activeProductPhotoArrayIndexForImagesViewer - 1 : this.product.photosURLs.length - 1;
  }
  // ------------------------------------------------------------


  /* --- Submitting of changes ------------------------------------------------------------------------------------ */
  private async onClickSaveProductButton(): Promise<void> {

    try {

      await ProductsUpdatingAPI.submit({
        // ...
        productPhotosURLs: this.uploadedProductPhotosURLs
      });


      console.log("checkpoint");
      console.log("uploadedProductPhotosURLs:");
      console.log(this.uploadedProductPhotosURLs);

      console.log("'product.photosURLs' before updating:");
      console.log(JSON.stringify(this.product.photosURLs, null, 2));

      this.product.photosURLs = this.uploadedProductPhotosURLs;
      // normally, I must set it to 0, but for now it does not affect
      // this.activeProductPhotoArrayIndexForImagesViewer = 0;
      console.log("'product.photosURLs' after updating:");
      console.log(JSON.stringify(this.product.photosURLs, null, 2));

    } catch (error) {

      // ....
    }
  }
}

Masalah

Saat this.product.photosURLs kosong, mari coba tambahkan dan kirimkan foto baru. Output debug akan menjadi:

checkpoint
uploadedProductPhotosURLs:
[
  "https://XXX/c732d006-1261-403a-a32f-f73c0f205aa8.jpeg", 
  "https://XXX/2b7ae2e2-4424-4038-acee-9624d5b937bc.jpeg", 
   __ob__: Observer
]
'product.photosURLs' before updating:
[]
'product.photosURLs' after updating:
[
  "https://XXX/c732d006-1261-403a-a32f-f73c0f205aa8.jpeg",
  "https://XXX/2b7ae2e2-4424-4038-acee-9624d5b937bc.jpeg"
]

Dari sudut pandang algoritme, semuanya benar, tetapi properti yang dihitung activeProductPhotoURL_ForImagesViewer (pengambil dalam sintaks OOP TypeScript) belum dihitung ulang! Artinya, PRODUCT_DUMMY_PHOTO_URL masih ditampilkan.

private get activeProductPhotoURL_ForImagesViewer(): string {
  if (this.product.photosURLs.length === 0) {
    return PRODUCT_DUMMY_PHOTO_URL;
  }
  return this.product.photosURLs[this.activeProductPhotoArrayIndexForImagesViewer];
}

Sama jika untuk menghapus gambar: keluaran debug cocok dengan yang diharapkan, tetapi gambar cache yang telah dihapus masih ditampilkan!

checkpoint
uploadedProductPhotosURLs:
[__ob__: Observer]
'product.photosURLs' before updating:
[
  "https://XXX/c732d006-1261-403a-a32f-f73c0f205aa8.jpeg",
  "https://XXX/2b7ae2e2-4424-4038-acee-9624d5b937bc.jpeg"
]
'product.photosURLs' after updating:
[]

Sama jika untuk mengganti gambar.

0
Takeshi Tokugawa YD 2 September 2020, 05:41

1 menjawab

Jawaban Terbaik

Memperluas komentar @Estradiaz, dan seperti yang disebutkan dalam dokumentasi Vue sendiri: Reaktivitas dalam Kedalaman,

Vue tidak dapat mendeteksi penambahan atau penghapusan properti.

Anda juga perlu menginisialisasi product.photosURLs mungkin dengan array kosong, atau Anda perlu menggunakan Vue.set() untuk menetapkan nilai ke this.product.photosURLs dalam fungsi onClickSaveProductButton Anda, seperti ini:

Vue.set(this.product, 'photosURLs', this.uploadedProductPhotosURLs);
2
waleed ali 4 September 2020, 07:40