vue.js - 在 VueJs 的对象中添加新属性时如何触发更改?

标签 vue.js vuejs2 vue-component vuex watch

我有以下 vuex 状态的初始结构(在 VueJS 项目中):

state: {
    level1prop: null
}

然后我动态地更改它,并将其变异为以下结构:

state: {
    level1prop: {
        level2prop: {
            level3prop: {
                "customKey1": { /* this is some object 1 */ },
                "customKey2": { /* this is some object 2 */ },
                ...
            }
        }
    }
}

然后我将在 level3prop 下添加 "customKeyN": {/* this is some object N */} 对我来说重要的是每次更改触发观察者,它正在观察状态对 level1prop 的更改。

最初,在我的突变中,我通过以下方式进行更新:

if (!state.hasOwnProperty("level1prop"))
    state["level1prop"] = {};
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state["level1prop"] = {};

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"]["level2prop"] = {};
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"]["level2prop"] = {};

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"]["level3prop"] = {};
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"]["level3prop"] = {};

let payloadObj = {  "customKey1": { /* this is some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

这是按照我想要的方式创建结构,但未触发更改观察者。遵循 here 的建议我将我的代码重构为几种不同的方式,但没有一种方式会触发更改。这是我尝试过的最新选项的示例:

if (!state.hasOwnProperty("level1prop"))
    state = Object.assign(state, { "level1prop" : {} });
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state = Object.assign(state, { "level1prop" : {} });

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });

let payloadObj = {  "customKey 1": { /* this is some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);

同样,这正在创建我需要的结构,但仍未触发观察者。我尝试过但未触发更改的其他一些选项是:

...
state["level1prop"]["level2prop"]["level3prop"] = Object.assign({}, state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

...
Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

在具有如此多嵌套级别的如此复杂的对象状态中,是否有任何方法能够触发观察者进行更改?

最佳答案

如文档中所述 Object Change Detection Caveats部分,你最好使用专门设计的 Vue setter Vue.set稍后将子级别添加到您的状态。

然后确保您的观察者指定了 deep选项,以便在您的子级别更改时正确触发它。

const store = new Vuex.Store({
  state: {
    level1prop: null,
  },
});

const state = store.state;

if (!state["level1prop"])
  Vue.set(state, "level1prop", {})

if (!state["level1prop"]["level2prop"])
  Vue.set(state["level1prop"], "level2prop", {})

if (!state["level1prop"]["level2prop"]["level3prop"])
  Vue.set(state["level1prop"]["level2prop"], "level3prop", {})

let payloadObj = {
  "customKey1": {
    hello: "world",
  },
};
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

setTimeout(() => {
  // Change an already existing key.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
}, 1000);

setTimeout(() => {
  // To add or remove keys, make sure to use again Vue.set or Vue.delete.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
  Vue.set(state["level1prop"]["level2prop"], "level3propSibling", {
    hi: "again",
  });
}, 2000);


new Vue({
  store: store,
  watch: {
    "$store.state": {
      // Make sure you specify the `deep` option
      deep: true,
      handler() {
        console.log(store.state);
      },
    },
  },
});
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/vuex@3"></script>

关于vue.js - 在 VueJs 的对象中添加新属性时如何触发更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51411566/

相关文章:

javascript - Vue.js 2 自动转义 HTML

javascript - Chart.js 绘制自定义网格线

vue.js - 使用Vue CLI3.0创建多页应用程序,如何处理此错误?

javascript - 如何从vue路由器拦截器 ‘to’参数获取不带参数的路径?

javascript - 使用 vue 的多个路由器

javascript - vue组件外部的访问方法

javascript - Vue.js 在计算函数中过滤多维数组

javascript - 在使用 forEach 然后过滤查询后,通过 JavaScript 中的下拉列表进行过滤不会抛出任何结果

vue.js - 带有 v-for 的动态 v 模型

vue.js - Vue路由器中的确切路径匹配?