Vue计算属性尚未更新,尽管它所依赖的数组已被明确地重新分配

时间:2020-09-02 02:41:45

标签: typescript vue.js

从问题answerWhat is affecting on will Vue computed property re-computed or no?开始,我知道

Vue无法检测到对数组的以下更改:

直接用索引设置项目时,例如 vm.items [indexOfItem] = newValue当您修改 阵列,例如vm.items.length = newLength

肯定是其他情况,因为我明确分配新值到数组。

目标

  1. 图像滑块必须显示当前选择的照片
  2. keyPath数组为空时,滑块应改为显示虚拟图像(如“无图像”)。
  3. "sublayers.moe.position"更新后,滑块必须显示更新后的照片(如果已删除所有照片,则为空白)。

实施

下面的实现达到第一个和第二个目标。

标记(pug)

photosURLs

逻辑(TypeScript)

图像滑块指向product.photosURLs

  • 当用户切换到编辑模式时,.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" ) 将被复制到product.photosURLs,这是更新但尚未提交的照片URL的数组。
  • 提交product.photosURLs时,uploadedProductPhotosURLs将被复制到uploadedProductPhotosURLs;
uploadedProductPhotosURLs

问题

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) {

      // ....
    }
  }
}

从算法的角度来看,尚未重新计算所有正确但已计算的属性this.product.photosURLs(以TypeScript OOP语法获取的属性)! 这意味着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" ] 仍在显示。

activeProductPhotoURL_ForImagesViewer

与删除图像相同:调试输出与预期的匹配,但是仍显示已删除的缓存图像!

PRODUCT_DUMMY_PHOTO_URL

与替换图像相同。

1 个答案:

答案 0 :(得分:2)

扩展@Estradiaz的评论,并在Vue自己的文档中提到:Reactivity in Depth

Vue无法检测到属性的添加或删除。

您可能需要使用空数组初始化product.photosURLs,或者需要使用Vue.set()来在this.product.photosURLs函数中为onClickSaveProductButton赋值,像这样:

Vue.set(this.product, 'photosURLs', this.uploadedProductPhotosURLs);