为动态创建的组件分隔vuex存储

时间:2017-06-03 15:41:29

标签: javascript module store vuex on-the-fly

这个问题让我陷入了一点困境。不幸的是,我在这里找不到答案(要求也没有帮助)。所以经过一些研究并在这里和那里询问后,似乎我得到了这个问题的解决方案。

  

如果您有一个问题,您已经知道答案,而且您   我想在公开场合记录这些知识,以便其他人   (包括你自己)可以在以后找到它。

当然,我的答案可能不是理想的答案,而且我知道不是,这是我发帖的关键点 - 改进它。

注意,我没有在示例中使用操作。这个想法是一样的。

让我们从陈述问题开始:

想象一下,我们App.vue动态生成名为Hello的本地组件。

<template>
  <div id="app">
    <div>
      <hello v-for="i in jobs" :key="i" :id="i"></hello>
      <button @click="addJob">New</button>
    </div>
  </div>
</template>   

<script>
import Hello from './components/Hello'

export default {
  components: {
    Hello
  }...

store.js

export const store = new Vuex.Store({
  state: {
    jobs: []
  }
})

我们正在使用v-for指令通过迭代数组jobs来生成组件。到目前为止,我们的store仅包含state个空数组。 按钮New应该做两件事:

1)创建新组件Hello,换句话说,将元素添加到jobs(让它成为数字),这些元素将被指定为{{1}和key的{​​{1}},并以id的形式传递给本地组件。

2)生成本地商店 - 模块 - 保持任何数据作用于新创建的组件。

<hello>

props

简单组件 - 使用添加1的按钮输入。

我们的目标是设计这样的东西: Vuex local stores

2 个答案:

答案 0 :(得分:20)

对于NEW按钮 - 生成组件的第一次操作,我们将mutation添加到store.js

 mutations: {
    addJob (state) {
      state.jobs.push(state.jobs.length + 1)
...
}

其次,创建本地模块。在这里,我们将使用reusableModule生成模块的多个实例。该模块我们保存在单独的文件中以方便。另外,注意使用函数来声明模块状态

const state = () => {
  return {
    count: 0
  }
}

const getters = {
  count: (state) => state.count
}

const mutations = {
  updateCountPlus (state) {
    state.count++
  }
}

export default {
  state,
  getters,
  mutations
}

要使用reusableModule我们导入它并应用动态模块注册。

<强> store.js

import module from './reusableModule'

const {state: stateModule, getters, mutations} = module

export const store = new Vuex.Store({
  state: {
    jobs: []
  },
  mutations: {
    addJob (state) {
      state.jobs.push(state.jobs.length + 1)
      store.registerModule(`module${state.jobs.length}`, {
        state: stateModule,
        getters,
        mutations,
        namespaced: true // making our module reusable
      })
    }
  }
})

之后,我们要将Hello.vue与其存储空间相关联。我们可能需要state中的gettersmutationsactionsvuex。要访问存储空间,我们需要创建getters。与mutations相同。

<强> Home.vue

<script>

export default {
  props: ['id'],
  computed: {
     count () {
        return this.$store.getters[`module${this.id}/count`]
     }
  },
  methods: {
    updateCountPlus () {
        this.$store.commit(`module${this.id}/updateCountPlus`)
     } 
  }
}
</script>

想象一下,我们有很多gettersmutationsactions。为什么不使用{mapGetters}{mapMutations}?当我们有几个模块并且我们知道所需模块的路径时,我们就可以做到。不幸的是,我们无法访问模块名称。

  

代码在执行组件模块时运行(当您的应用程序运行时)   正在启动),而不是在创建组件时。所以这些助手可以   只有在提前知道模块名称时才能使用。

这里几乎没有帮助。我们可以将gettersmutations分开,然后将它们作为对象导入并保持清洁。

<script>
import computed from '../store/moduleGetters'
import methods from '../store/moduleMutations'

export default {
  props: ['id'],
  computed,
  methods
}
</script>

返回App组件。我们必须提交mutation,并为getter创建一些App。为了说明我们如何访问位于模块中的数据。

<强> store.js

export const store = new Vuex.Store({
  state: {
    jobs: []
  },
  getters: {
    jobs: state => state.jobs,
    sumAll (state, getters) {
      let s = 0
      for (let i = 1; i <= state.jobs.length; i++) {
        s += getters[`module${i}/count`]
      }
      return s
    }
  } 
...

完成App组件

中的代码
<script>
import Hello from './components/Hello'
import {mapMutations, mapGetters} from 'vuex'

    export default {
      components: {
        Hello
      },
      computed: {
        ...mapGetters([
          'jobs',
          'sumAll'
        ])
      },
      methods: {
        ...mapMutations([
          'addJob'
        ])
      }
    }
    </script>

答案 1 :(得分:1)

您好,感谢您发布问题和解决方案。

几天前,我开始学习Vuex,遇到了类似的问题。我已经检查了您的解决方案,并提出了我的方法,该方法不需要注册新模块。我发现这太过分了,说实话,我不明白您为什么这么做。我总是有可能误解了这个问题。

为了清晰和演示起见,我创建了带有一些差异的标记副本。

我有:

  1. JobList.vue-主要自定义组件
  2. Job.vue-作业列表子自定义组件
  3. jobs.js-vuex存储模块文件

JobList.vue(负责包装作业列表项)

<template>
    <div>
        <job v-for="(job, index) in jobs" :data="job" :key="job.id"></job>

        <h3>Create New Job</h3>
        <form @submit.prevent="addJob">
            <input type="text" v-model="newJobName" required>
            <button type="submit">Add Job</button>
        </form>
    </div>
</template>

<script>
    import store from '../store/index'
    import job from './job';

    export default {
        components: { job },
        data() {
            return {
                newJobName: ''
            };
        },
        computed: {
            jobs() {
                return store.state.jobs.jobs;
            }
        },
        methods: {
            addJob() {
                store.dispatch('newJob', this.newJobName);
            }
        }
    }
</script>

工作

<template>
    <div>
        <h5>Id: {{ data.id }}</h5>
        <h4>{{ data.name }}</h4>
        <p>{{ data.active}}</p>
        <button type="button" @click="toggleJobState">Toggle</button>
        <hr>
    </div>
</template>

<script>

    import store from '../store/index'

    export default {
        props: ['data'],
        methods: {
            toggleJobState() {
                store.dispatch('toggleJobState', this.data.id);
            }
        }
    }

</script>

最后是jobs.js Vuex模块文件:

export default {
    state: {
        jobs: [
            {
                id: 1,
                name: 'light',
                active: false
            },
            {
                id: 2,
                name: 'medium',
                active: false
            },
            {
                id: 3,
                name: 'heavy',
                active: false
            }
        ]
    },

    actions: { //methods
        newJob(context, jobName) {
            context.state.jobs.push({
                id: context.getters.newJobId,
                name: jobName,
                active: false
            });
        },
        toggleJobState(context, id) {
            context.state.jobs.forEach((job) => {
                if(job.id === id) { job.active = !job.active; }
            })
        }
    },

    getters: { //computed properties
        newJobId(state) { return state.jobs.length + 1; }
    }
}

可以在商店中添加新作业,并且正如“活动”属性所建议的那样,您可以控制每个单独的作业,而无需新的自定义vuex模块。