反应性:更改数组中的 属性,应用于 window 事件

Reactivity: change property in array, applied on window event

简单用例: 特定元素应通过将 属性 "active" 设置为 true (v-bind:class) 来激活 class。 属性 "active" 在 foreach 循环中设置,在检查一些条件后,在方法 "handleScroll".

如果我在创建的生命周期中直接调用 "handleScroll",这会起作用。

<template>
  <div class="c-sidebar">
    <p
      v-for="(sidebarItem, index) in sidebarItems"
      v-bind:key="index"
      v-bind:class="{ 'active': sidebarItem.active }"
    >
      {{ sidebarItem.label }}
    </p>
  </div>
</template>

<script lang="ts">

import { Component, Vue, Prop } from "vue-property-decorator";
import {SidebarItem, SidebarNavItem} from "../../Interfaces";

@Component
export default class Sidebar extends Vue {
  sidebarItems: SidebarItem[];

  public created() {

    this.sidebarItems = [
      {
        label: "First item",
        active: true
      },
      {
        label: "Second item",
        active: false
      }
    ];

    this.handleScroll();
}

  public handleScroll() {
    this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
      if (index == 1) {
        sidebarItem.active = true;
      } else {
        sidebarItem.active = false;
      }
    });
  }
}
</script>

如果我从 window 事件中调用 "handleScroll",反应性就会丢失。

改变

public created() {
  ...
  this.handleScroll();
}

public created() {
  ...
  window.addEventListener("scroll", this.handleScroll);
}

不起作用。该方法已执行,但模板中的反应性丢失。

问题:如何在全局 window 事件中设置这些属性并将它们分配回视图?

可能是 Vue 反应问题。

请尝试使用 JSON.parse(JSON.stringify())

创建深层副本来更改对象引用
public handleScroll() {
  this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
    if (index == 1) {
      sidebarItem.active = true;
    } else {
      sidebarItem.active = false;
    }
  });
  this.sidebarItems = JSON.parse(JSON.stringify(this.sidebarItems))
}

仅根据此处显示的代码,没有明显充分的理由认为这行不通。 Vue 的反应性警告是关于 adding/removing 数组项,而不是更改属性。

我会三重确保该方法实际上是 运行,其中一些 console.log:

this.sidebarItems.forEach((sidebarItem: SidebarItem, index) => {
  if (index == 1) {
    sidebarItem.active = true;
    console.log('on: ' + sidebarItem)
  } else {
    sidebarItem.active = false;
    console.log('off: ' + sidebarItem)
  }
});

如果这没有给出您的答案,最好在 jsfiddle 中重现您的问题。这可能会告诉你你需要什么。如果没有,您可以在此处 post fiddle。

您必须使用计算 属性 或直接从 vue 调用的函数以反映更改。下面的代码应该可以工作 -

<template>
  <div class="c-sidebar">
    <p
      v-for="(sidebarItem, index) in sidebarItems"
      :key="index"
      :class="getActiveClass(index)"
    >
      {{ sidebarItem.label }}
    </p>
  </div>
</template>

<script lang="ts">

import { Component, Vue, Prop } from "vue-property-decorator";
import {SidebarItem, SidebarNavItem} from "../../Interfaces";

@Component
export default class Sidebar extends Vue {
  sidebarItems: SidebarItem[];

  public created() {

    this.sidebarItems = [
      {
        label: "First item",
        active: true
      },
      {
        label: "Second item",
        active: false
      }
    ];
}

  public getActiveClass(index: number) {
    return index === 1 ? 'active': '';
  }
}
</script>

尝试使用 Vue.set 设置值,如 caveats 部分所述,如下所示:

Vue.set(sidebarItems[index], 'active', true)

Vue.set(sidebarItems, index, { ...sidebarItems[index], { active: true})