Vue JS 观察深度嵌套对象

52

免责声明:这是我第一次尝试构建一个MVVM应用程序,我之前也没有使用过vue.js,因此我的问题可能是由于更基本的问题导致的。


在我看来,我有两种带有复选框的块:

  • 类型1:块/复选框
  • 类型2:块/标题/复选框

底层对象的结构如下:

{
  "someTopLevelSetting": "someValue",
  "blocks": [
    {
      "name": "someBlockName",
      "categryLevel": "false",
      "variables": [
        {
          "name": "someVarName",
          "value": "someVarValue",
          "selected": false,
          "disabled": false
        }
      ]
    },
    {
      "name": "someOtherBlockName",
      "categryLevel": "true",
      "variables": [
        {
          "name": "someVarName",
          "value": "someVarValue",
          "categories": [
            {
              "name": "SomeCatName",
              "value": "someCatValue",
              "selected": false,
              "disabled": false
            }
          ]
        }
      ]
    }
  ]
}

我的目标

选择复选框:

  1. 用户点击复选框,复选框被选中(selected=true)。
  2. 触发一个方法来检查是否需要禁用其他复选框(disabled=true)。 (如果此方法确实禁用了任何内容,则它还会再次调用自身,因为其他项目可能依次依赖于禁用的项目)
  3. 另一个方法更新一些其他内容,例如图标等。

清除复选框

用户可以单击“清除”按钮,以取消列表中所有复选框的选中状态(selected=false)。此操作还应触发可选禁用复选框和更新图标等的方法。

我当前的方法(似乎不太正确)

  • 使用v-model指令将数据模型的selected属性绑定到复选框元素的选中状态上。
  • 从模型中绑定disabled属性到元素的class和disabled属性。此状态由上述方法设置。
  • 为初始化禁用复选框和更改某些图标的方法,我正在使用v-on="change: checkboxChange(this)"指令。我认为我需要以不同的方式执行此部分。
  • 通过v-on="click: clearList(this)"调用clearList方法。

我的当前设置存在的问题是,当以编程方式清除复选框时(即非用户交互),更改事件不会触发。

我希望的替代方案
对我来说,最合适的做法应该是使用this.$watch并跟踪模型中的更改,而不是侦听DOM事件。

一旦有更改,我就需要确定哪个项目确切地发生了更改,并采取行动。我已尝试创建一个观察blocks数组的$watch函数。这似乎很好地检测到了更改,但它返回完整对象,而不是已更改的单个属性。此外,此对象缺少一些方便的辅助属性,例如$parent。

我可以想到一些笨拙的方法使应用程序正常工作(例如在我的clearList方法中手动触发更改事件等),但我的用例似乎非常标准,因此我预计可能有更优雅的处理方式。

4个回答

87

您可以使用“watch”方法..例如,如果您的数据为:

data: {
    block: {
        checkbox: {
            active:false
        },
        someotherprop: {
            changeme: 0
        }
    }
}
您可以这样做:

您可以像这样做:

data: {...},
watch: {
   'block.checkbox.active': function() {
        // checkbox active state has changed
        this.block.someotherprop.changeme = 5;
    } 
}

1
".selected"和".disabled"是匿名变量对象的属性,它们属于变量数组。你的例子能够工作是因为它只是一个单一的对象,而不是一个数组。 - Hendrik
我做了类似 block.checkbox.active 的东西,但是直到我像你上面提到的那样添加了双引号,它才能运行。谢谢。现在它可以工作了。 - Apit John Ismail

38
如果您想查看对象的所有属性,而不仅仅是一个属性,可以使用以下方法:
 data() {
    return {
       object: {
          prop1: "a",
          prop2: "b",
       }    
    }
 },
 watch: {
    object: {
        handler(newVal, oldVal) {
            // do something with the object
        },
        deep: true,
    },
},

请注意handlerdeep: true

如果您只想观察prop1,您可以执行以下操作:

watch: { 
    'object.prop1' : function(newVal, oldVal) { 
        // do something here 
     }
}

谢谢您。然而,由于我的问题已经两年以上了,而且我自那以后就没有使用过Vue,所以无法验证它是否有效。 - Hendrik
3
没问题,我希望这能帮助到遇到同样问题的人。 - peerbolte
1
你知道如果我只想观看 prop1,我应该怎么做吗? - Sylvain Attoumani
28
@SylvainAttoumani 是的:以我的示例为例: watch: { 'object.prop1' : function(newVal, oldVal) { // 在此处执行某些操作 }} - peerbolte
1
@peerbolte 我认为那个评论应该成为答案的一部分。这样你会得到更多的赞同。 - TKharaishvili

12

这里没有提到的其他解决方案是: 使用 deep 选项。

watch:{
  block: {
    handler: function () {console.log("changed") },
    deep: true
  }
}

7

由于没有人回复,而且我现在已经解决/解决了这个问题,所以我认为发布我的解决方案可能会有用。请注意,我不确定我的解决方案是否应该如何处理这些类型的问题,但它确实有效。

不再使用此事件侦听器v-on ="change:checkboxChange(this)",而是使用自定义指令,该指令侦听所选和禁用的模型属性,如下所示:v-on-filter-change="selected,disabled"

指令如下所示:

directives: {
    'on-filter-change': function(newVal, oldVal) {
        // When the input elements are first rendered, the on-filter-change directive is called as well, 
        // but I only want stuff to happen when a user does someting, so I return when there is no valid old value
        if (typeof oldVal === 'undefined') {
            return false;
        }
        // Do stuff here
        // this.vm is a handy attribute that contains some vue instance information as well as the current object
        // this.expression is another useful attribute with which you can assess which event has taken place
    }
},

if语句看起来有点笨拙,但我找不到其他方法。至少现在它能够正常工作。

或许将来会有人觉得这很有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接