简体   繁体   English

Vue JS 观看深层嵌套对象

[英]Vue JS Watching deep nested object

Disclaimer: This is my first attempt at building an MVVM app I have also not worked with vue.js before, so it could well be that my issue is a result of a more fundamental problem.免责声明:这是我第一次尝试构建一个 MVVM 应用程序,我之前也没有使用过 vue.js,所以很可能我的问题是一个更基本的问题的结果。


In my view I have two types of blocks with checkboxes:在我看来,我有两种带有复选框的块:

  • Type 1: block/checkboxes类型 1:块/复选框
  • Type 2: block/headers/checkboxes类型 2:块/标题/复选框

The underlying object is structured like this:底层对象的结构如下:

{
  "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
            }
          ]
        }
      ]
    }
  ]
}

My objectives我的目标

Selecting checkboxes:选择复选框:

  1. User clicks on checkbox, checkbox is selected (selected=true)用户点击复选框,复选框被选中(selected=true)
  2. A method is fired to check if any other checkboxes need to be disabled (disabled=true).会触发一个方法来检查是否需要禁用任何其他复选框(禁用 = 真)。 (If this method has indeed disabled anything, it also calls itself again, because other items could be in turn dependent on the disabled item) (如果这个方法确实禁用了任何东西,它也会再次调用自己,因为其他项目可能反过来依赖于禁用的项目)
  3. Another method updates some other things, like icons etc另一种方法更新其他一些东西,比如图标等

Clearing checkboxes清除复选框

A user can click on a "clear" button, which unchecks all checkboxes in a list (selected=false).用户可以单击“清除”按钮,取消选中列表中的所有复选框(selected=false)。 This action should also trigger the methods that optionally disables checkboxes and updates icons etc.此操作还应触发可选地禁用复选框和更新图标等的方法。

My current method (which doesn't seem quite right)我目前的方法(似乎不太正确)

  • The selected attribute of the data-model is bound to the checked state of the checkbox element via the v-model directive.数据模型的 selected 属性通过v-model指令绑定到复选框元素的选中状态。
  • The disabled attribute (from the model) is bound to the element's class and disabled attribute. disabled 属性(来自模型)绑定到元素的 class 和 disabled 属性。 This state is set by the aforementioned method.该状态通过上述方法设置。
  • To initialize the methods that disable checkboxes and change some icons, I am using a v-on="change: checkboxChange(this)" directive.为了初始化禁用复选框和更改某些图标的方法,我使用了v-on="change: checkboxChange(this)"指令。 I think I need to do this part differently我想我需要以不同的方式做这部分
  • The clearList method is called via v-on="click: clearList(this)" clearList 方法通过v-on="click: clearList(this)"

The problems with my current setup is that the change event is not firing when the checkboxes are cleared programatically (ie not by user interaction).我当前设置的问题是当以编程方式清除复选框时(即不是通过用户交互),更改事件不会触发。

What I would like instead我想要的是什么
To me the most logical thing to do would be to use this.$watch and keep track of changes in the model, instead of listening for DOM events.对我来说,最合乎逻辑的做法是使用this.$watch并跟踪模型中的变化,而不是监听 DOM 事件。

Once there is a change I would then need to identify which exact item changed, and act on that.一旦发生变化,我就需要确定哪个确切的项目发生了变化,然后采取行动。 I have tried to create a $watch function that observes the blocks array.我试图创建一个观察blocks数组的$watch函数。 This seems to pick up on the changes fine, but it is returning the full object, as opposed to the individual attribute that has changed.这似乎很好地接受了更改,但它返回了完整的对象,而不是已更改的单个属性。 Also this object lacks some convenient helper attributes, like $parent .这个对象也缺少一些方便的辅助属性,比如$parent

I can think of some hacky ways to make the app work (like manually firing change events in my clearList method, etc.) but my use case seems pretty standard, so I expect there is probably a much more elegant way to handle this.我可以想到一些让应用程序工作的hacky方法(例如在我的 clearList 方法中手动触发更改事件等),但我的用例似乎非常标准,所以我希望可能有一种更优雅的方法来处理这个问题。

You could use the 'watch' method.. for example if your data is:您可以使用 'watch' 方法.. 例如,如果您的数据是:

data: {
    block: {
        checkbox: {
            active:false
        },
        someotherprop: {
            changeme: 0
        }
    }
}

You could do something like this:你可以这样做:

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

If you want to watch the object as a whole with all its properties, and not only just one property, you can do this instead:如果您想查看整个对象及其所有属性,而不仅仅是一个属性,您可以这样做:

 data() {
    return {
       object: {
          prop1: "a",
          prop2: "b",
       }    
    }
 },
 watch: {
    object: {
        handler(newVal, oldVal) {
            // do something with the object
        },
        deep: true,
    },
},

notice handler and deep: true通知handlerdeep: true

If you only want to watch prop1 you can do:如果您只想观看prop1您可以执行以下操作:

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

Other solution not mentioned here: Use the deep option.此处未提及的其他解决方案:使用deep选项。

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

Since nobody replied and I have solved/ worked around the issue by now, I thought it migth be useful to post my solution.由于没有人回复并且我现在已经解决/解决了这个问题,我认为发布我的解决方案可能很有用。 Please note that I am not sure my solution is how these types of things should be tackled, it works though.请注意,我不确定我的解决方案是如何处理这些类型的事情,但它确实有效。

Instead of using this event listener v-on="change: checkboxChange(this)" I am now using a custom directive which listens to both the selected and disabled model attribute, like this: v-on-filter-change="selected, disabled" .而不是使用这个事件监听器v-on="change: checkboxChange(this)"我现在使用一个自定义指令来监听 selected 和 disabled 模型属性,像这样: v-on-filter-change="selected, disabled"

The directive looks like this:该指令如下所示:

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
    }
},

The if clause seems a bit hacky, but I couldn't find another way. if 子句似乎有点 hacky,但我找不到其他方法。 At least it all works.至少这一切都有效。

Perhaps this will be useful to someone in the future.也许这对将来的某人有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM