【问题标题】:Reactivity: change property in array, applied on window event反应性:更改数组中的属性,应用于窗口事件
【发布时间】:2019-09-15 10:06:53
【问题描述】:

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

如果我在创建的生命周期中直接调用“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>

如果我在窗口事件中调用“handleScroll”,反应性就会丢失。

改变

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

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

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

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

【问题讨论】:

    标签: typescript vue.js vuejs2 vue-component vue-class-components


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      您必须使用计算属性或直接从 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>
      

      【讨论】:

      • 这可行,但不适合我的用例。我的例子被简化了,只是为了说明问题。我需要对数组对象的多个属性进行突变,以对模板中的多个元素做出反应。
      【解决方案3】:

      仅基于此处显示的代码,这没有明显的充分理由不起作用。 Vue 的反应性警告是关于添加/删除数组项,而不是更改属性。

      我会通过一些 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 中重新创建您的问题。这可能会告诉你你需要什么。如果没有,您可以在此处发布小提琴。

      【讨论】:

      • 谢谢。它运行。我的示例中的问题是,我忘记将变异数组重新分配给原始数组 --> this.sidebarItems = this.sidebarItems.
      【解决方案4】:

      可能是 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))
      }
      

      【讨论】:

      • 这行得通。但它也有效,如果我只是将未字符串化的数组分配回原来的 --> this.sidebarItems = this.sidebarItems
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-18
      • 2012-09-11
      • 2023-04-09
      • 1970-01-01
      • 2017-11-03
      • 2022-08-19
      • 2023-03-22
      相关资源
      最近更新 更多