Nuxt + Vuex - 如何将 Vuex 模块分解为单独的文件?

Posted

技术标签:

【中文标题】Nuxt + Vuex - 如何将 Vuex 模块分解为单独的文件?【英文标题】:Nuxt + Vuex - How do I break down a Vuex module into separate files? 【发布时间】:2019-04-26 01:44:07 【问题描述】:

在 Nuxt 文档 (here) 中,它说“您可以选择将模块文件分解为单独的文件:state.jsactions.jsmutations.jsgetters.js。”

我似乎找不到任何关于如何做到这一点的示例 - 大量将根级别的 Vuex 存储分解为 state.jsactions.jsmutations.jsgetters.js,并分解为单个模块文件,但没有关于分解模块本身的内容。

所以目前我有:

     ├── assets
     ├── components
     └── store
           ├── moduleOne.js
           ├── moduleTwo.js
           └── etc...

而我想要的是:

     ├── assets
     ├── components
     └── store
           └── moduleOne
                 └── state.js
                 └── getters.js
                 └── mutations.js
                 └── actions.js
           └── moduleTwo
                └── etc...

要试试这个,/store/moduleOne/state.js 我有:

export const state = () => 
    return 
        test: 'test'
    
;

/store/moduleOne/getters.js 我有:

export const getters = 
    getTest (state) 
        return state.test;
    

在我的组件中,我使用 $store.getters['moduleOne/getters/getTest'] 访问它

但是使用调试器和 Vue 开发工具时,似乎无法在 getters 文件中访问状态 - 它似乎正在本地文件中寻找状态,因此 state.test 未定义。

尝试将state 从我的state.js 文件导入我的getters.js 文件似乎也不起作用。

有没有人举个例子说明他们是如何在 Nuxt 像这样打破商店的?

【问题讨论】:

好问题。刚试了一下,它确实破坏了我的应用程序。也许在cmty.app/nuxt 上创建一个问题。似乎是错误或缺少文档。 示例在github.com/nuxt/nuxt.js/tree/dev/test/fixtures/basic/store/foo/… ;) @manniL 的上述回答并没有解决问题,因为模块目录的内容只是在商店根目录中的同名文件中重复 抱歉,我现在了解更多细节;) 【参考方案1】:

我正在使用 nuxt 2.1.0 如果你想拥有这样的东西:

在我的store/index.js

确保您有 namespaced: true

import Vuex from 'vuex';
import apiModule from './modules/api-logic';
import appModule from './modules/app-logic';

const createStore = () => 
  return new Vuex.Store(
    namespaced: true,
    modules: 
      appLogic: appModule,
      api: apiModule
    
  );
;

export default createStore

在moduleOne中

在我的store/api-logic/index.js

import actions from './actions';
import getters from './getters';
import mutations from './mutations';

const defaultState = 
  hello: 'salut I am module api'


const inBrowser = typeof window !== 'undefined';
// if in browser, use pre-fetched state injected by s-s-r
const state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;

export default 
  state,
  actions,
  mutations,
  getters

在我的store/api-logic/getters.js

export default 
  getHelloThere: state => state.hello

在模块二中

在我的store/app-logic/index.js

import actions from './actions';
import getters from './getters';
import mutations from './mutations';

const defaultState = 
  appLogicData: 'bonjours I am module Logic'


const inBrowser = typeof window !== 'undefined';
// if in browser, use pre-fetched state injected by s-s-r
const state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;

export default 
  state,
  actions,
  mutations,
  getters

在我的store/app-logic/getters.js

export default 
  getAppLogicData: state => state.appLogicData

应用中的任何位置

 computed: 
  ...mapGetters(
   logicData: 'getAppLogicData',
   coucou: 'getHelloThere'
 )
,
mounted () 
  console.log('coucou', this.coucou) --> salut I am module api
  console.log('logicData', this.logicData) --> bonjours I am module Logic

奖励积分

如果您想在模块之间进行通信,例如 app-logic 中的某个操作会触发 api-logic 中的某些内容。 所以 app-logic(模块一)到 api-logic(模块二)

当您指定root: true 时,它将开始查看存储的根目录。

store/app-logic/actions.js

  callPokemonFromAppLogic: ( dispatch , id) => 
    dispatch('callThePokemonFromApiLogic', id, root:true);
  ,

store/api-logic/actions.js

  callThePokemonFromApiLogic: ( commit , id) => 

    console.log('I make the call here')
    axios.get('http://pokeapi.salestock.net/api/v2/pokemon/' + id).then(response => commit('update_pokemon', response.data))
  ,

store/api-logic/index.js添加另一个条目

import actions from './actions';
import getters from './getters';
import mutations from './mutations';

const defaultState = 
  appLogicData: 'bonjours I am module Logic',
  pokemon: 


const inBrowser = typeof window !== 'undefined';
// if in browser, use pre-fetched state injected by s-s-r
const state = (inBrowser && window.__INITIAL_STATE__) ? window.__INITIAL_STATE__.page : defaultState;

export default 
  state,
  actions,
  mutations,
  getters

store/api-logic/mutations.js 中添加口袋妖怪突变:p

  update_pokemon: (state, pokemon) => 
    state.pokemon = pokemon
  

应用中的任何位置:

computed: 
  ...mapGetters(
    bidule: 'bidule',
    pokemon: 'getPokemon'
  )
,
mounted() 
  console.log('bidule', this.bidule)
  this.callPokemonFromAppLogic('1') --> the call 
  console.log('the pokemon', this.pokemon.name) --> 'bulbasaur'
,
methods: 
  ...mapActions(
    callPokemonFromAppLogic: 'callPokemonFromAppLogic'
  ),

最后你的 Vue devTool 应该是这样的 :)

瞧,我希望它很清楚。 代码示例:

https://github.com/CMarzin/nuxt-vuex-modules

【讨论】:

【参考方案2】:

在 nuxt 版本 2.14^ 中,您不必在商店根 index.js 文件中创建它。

import Vuex from 'vuex';
import apiModule from './modules/api-logic';
import appModule from './modules/app-logic';

const createStore = () => 
  return new Vuex.Store(
    namespaced: true,
    modules: 
      appLogic: appModule,
      api: apiModule
    
  );
;

export default createStore

但是,您可以将根 index.js 文件保留为默认文件或执行您需要的操作。无需导入。

store/index.js

export const state = () => (
  counter: 0
)

export const mutations = 
  increment(state) 
    state.counter++
  


export const actions = 
   async nuxtServerInit( state, commit ,  req ) 
   const cookies = this.$cookies.getAll() 
   ...

它看起来像这样,非常简单。

文件夹结构

?store
 ┣ ?auth
 ┣ ?utils
 ┣ ?posts
 ┃ ┗ ?actions.js
 ┃ ┗ ?mutations.js
 ┃ ┗ ?getters.js
 ┃ ┗ ?index.js
 ┣ index.js

例子

store/posts/index.js你可以只放状态函数。您无需导入操作、getter 和突变。

export const state = () => ( 
   comments: []
)

store/posts/actions.js

const actions = 
  async getPosts( commit, state , obj) 
    return new Promise((resolve, reject) =>  
       ...
    
  


export default actions

store/posts/mutations.js

 const mutations = 
    CLEAR_POST_IMAGE_CONTENT: (state) => 
       state.post_image_content = []
    
 
 
 export default mutations

store/posts/getters.js

const getters = 
    datatest: (state) => state.datatest,
    headlineFeatures: (state) => state.headlineFeatures,


export default getters

效果与@CMarzin 答案相同,但更干净

【讨论】:

【参考方案3】:

您的问题

在您的文件中使用default 导出以达到预期的效果(除了index.js 之外,没有命名导出)

示例

可以直接在 Nuxt.js 测试套件中找到一个示例(https://github.com/nuxt/nuxt.js/tree/dev/test/fixtures/basic/store/foo)。

如果您运行 basic 夹具并访问 /store 页面,您将看到以下结果

模块本身中的“重复”内容只是表明拆分值优先(否则getVal 不会返回 10 而是 99,state.val 不会返回 4 而是 2)。

store.vue 代码:

<template>
  <div>
    <h1> baz </h1>
    <br>
    <p> $store.state.counter </p>
    <br>
    <h2> getVal </h2>
    <br>
    <h3> getBabVal </h3>
  </div>
</template>

<script>
import  mapGetters  from 'vuex'

export default 
  computed: 
    ...mapGetters('foo/bar', ['baz']),
    ...mapGetters('foo/blarg', ['getVal']),
    ...mapGetters('bab', ['getBabVal'])
  

</script>

【讨论】:

以上是关于Nuxt + Vuex - 如何将 Vuex 模块分解为单独的文件?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Nuxt.js 时动态 Vuex 模块初始化的最佳方法是啥?

使用 Jest 测试 NUXT.js 和 Vue.js 应用程序。获取“在 mapState() 中找不到 [vuex] 模块命名空间”和“[vuex] 未知操作类型”

NuxtServerInit 在 Vuex 模块模式下不起作用 - Nuxt.js

Vue/Nuxt:如何在 vuex 商店中访问 Nuxt 实例?

在 Vuex/Nuxt 中绑定选择表单

如何将 Firebase Firestore 数据添加到 s-s-r Nuxt Apps Vuex Store