【问题标题】:Vue.js computed on nested arraysVue.js 在嵌套数组上计算
【发布时间】:2018-04-15 17:56:11
【问题描述】:

我来自 Knockout.js 背景,我一直在考虑为我未来的项目尝试 Vue.js。让我感到困惑的一件事是在嵌套数据数组上使用计算函数。

假设我们从 ajax 调用“/api/getProject/”中获取此数据结构。

{
    projectID: 23,
    phases: [
        {
            phaseID: 23,
            activities: [
                {activityID : 23, start: "date", end : "date"},
                {activityID : 23, start: "date", end : "date"}
            ]
        },
        {
            phaseID: 24,
            activities: [
                {activityID : 23, start: "date", end : "date"},
                {activityID : 23, start: "date", end : "date"}
            ]
        },
    ]
}

为此,我需要一些计算变量。首先,将是每个活动的持续时间。然后,我想要计算每个阶段的总持续时间。最后是项目总工期的计算结果。

使用 KO.js,我这样做的方式是为每个数据点创建类并将计算函数放入每个类中。例如。

    var Project = function(obj){
    var self = this;

    self.projectID = ko.observable(obj.projectID);

    var mapped = mapArray(obj.phases, i => new Phase(i));
    self.phases = ko.observableArray(mapped);

    self.computed = {
        total : ko.computed(() => {
            var total = 0;
            for(var phase of self.phases())
                total += phase.computed.total();
            return total;
        }),
    }
}

var Phase = function(obj){
    var self = this;

    self.phaseID = ko.observable(obj.phaseID);

    var mapped = mapArray(obj.activities, i => new Activity(i));
    self.activities = ko.observableArray(mapped);

    self.computed = {
        total : ko.computed(() => {
            var total = 0;
            for(var act of self.activities())
                total += act.computed.duration();
            return total;
        }),
    }
}

var Activity = function(obj){
    var self = this;

    self.activityID = ko.observable(obj.activityID);
    self.start = ko.observable(obj.start);
    self.end = ko.observable(obj.end);

    self.computed= {
        duration: ko.computed(() => {
        return end - start;
        }),
    }
}

然后做。

 $.getJSON("/api/getProject", function (data, status, xhr) {
        VM.project = new Project(data);
    }),

以下是我阅读和考虑的一些内容,以及为什么我无法让它们发挥作用。

“使用组件项目、阶段、活动,每个组件都有自己的计算属性”-据我了解,组件无法从其他组件读取数据,而且我的数据都是一次调用,所以我将如何设置数据每个组件?大多数答案只是用硬编码值填充数据,而大多数情况下并非如此。

感谢任何帮助。我知道我可能以错误的方式看待这个问题,所以如果我可以改变我的数据传递方式或我对 Vue.js 的看法;我愿意这样做。

【问题讨论】:

  • Knockout 没有 Vue 所拥有的——通过 Vuex 进行状态管理。这就是您以集中方式保存数据的地方,以便您的各种组件可以访问它。 vuex.vuejs.org/en/intro.html

标签: knockout.js vue.js


【解决方案1】:

你要求全局状态管理,所以你需要使用Vuex。

https://vuex.vuejs.org/en/intro.html

安装 Vuex 后,您将创建一个 store(代表应用程序的当前状态),然后创建一个 action 发送异步 API 请求(ajax 请求)并相应地更新 store .依赖于此 API 调用中接收到的数据的每个组件都会对此更新做出反应。您可以选择使用 Vuex getter,它的行为与常规组件 getter 完全相同,但在您的所有组件中都可用。


这个想法是每个活动的日期都是可编辑的。

编辑嵌套属性已不是什么秘密。您只需要更新整个对象以保持反应性。

这是一个完整的例子:

const store = new Vuex.Store({
  state: {
    phases: [
      {
        phaseId: 1,
        activities: [
          { activityId: 1, start: 1, end: 6 },
          { activityId: 2, start: 5, end: 9 },
        ],
      },
      {
        phaseId: 2,
        activities: [
          { activityId: 3, start: 10, end: 16 },
          { activityId: 4, start: 14, end: 19 },
        ],
      },
    ],
  },
  mutations: {
    setDuration (state, {phaseId, activityId, start, end}) {
      const phase = state.phases.find(x => x.phaseId === phaseId);
      state.phases = [
        ...state.phases.filter(x => x !== phase),
        {
          ...phase,
          activities: [
            ...phase.activities.filter(x => x.activityId !== activityId),
            { activityId, start, end }
          ],
        },
      ];
    },
  },
});

const example = {
  data() {
    return {
      phaseId: null,
      activityId: null,
      start: null,
      end: null
    };
  },
  computed: {
    ...Vuex.mapState(['phases']),
    phasesFormated() {
      return JSON.stringify([...this.phases].sort((a, b) => a.phaseId - b.phaseId), null, 2);
    },
  },
  methods: {
    ...Vuex.mapMutations(['setDuration']),
    updatePhase() {
      this.setDuration({
        phaseId: parseInt(this.phaseId),
        activityId: parseInt(this.activityId),
        start: parseInt(this.start),
        end: parseInt(this.end),
      });
    },
  },
  template: `
    <div>
      <div>
        Phase ID:
        <input type="text" v-model="phaseId">
        <br />
        Activity ID:
        <input type="text" v-model="activityId">
        <br />
        Start:
        <input type="text" v-model="start">
        <br />
        End:
        <input type="text" v-model="end">
      </div>
      <button type="button" v-on:click="updatePhase">update</button>
      <pre style="margin-right: 1rem">{{ phasesFormated }}</pre>    
    </div>
  `,
};

const app = new Vue({
  store,
  el: '#app',
  components: { example },
  template: `
    <div v-cloak>
      <h1>app</h1>
      <example></example>
    </div>
  `
});

重建整个对象可能会有点混乱。这就是为什么使用状态管理库(Vuex、Redux 等)的人经常对数据进行规范化。

Redux 库的文档有a nice example of what data normalization is,Vue 的创建者也有an interesting post on the subject

【讨论】:

  • 我查看了 vuex 商店,它并没有真正解决我的问题。这个想法是每个活动的日期都是可编辑的。这意味着持续时间(这是一个计算属性将改变),这将影响阶段的持续时间,这将影响项目的持续时间。我的问题确实与嵌套计算属性有关。我做了很多挖掘工作,但没有人真正解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
  • 2017-09-28
  • 2015-11-22
  • 2022-01-05
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多