3

我看到很多 Vue.js 项目使用这种结构:

├── main.js
├── api
│   └── index.js
│   └── services           #containing files with api-calls
│       ├── global.js
│       ├── cart.js
│       └── messages.js
├── components
│   ├── Home.vue
│   ├── Cart.vue
│   ├── Messages.vue
│   └── ...
└── store
    ├── store.js
    ├── actions.js  #actions to update vuex stores
    ├── types.js
    └── modules
        ├── global.js
        ├── cart.js
        └── ...

(这种结构的一个例子是“ Jackblog ”。)

因此,例如,Cart.vue想要更新inCartVuex 中的数据。为此,购物车导入actions.js

import { inCart } from '../../store/actions'

actions.js导入 api以便它index.js可以连接到 api。然后它会更新 Vuex 存储中的值。

好的,这对我来说很清楚。但现在,我想在Messages.vue模块上工作。该模块也应该连接到 api 以获取所有消息,但不必将结果存储在 Vuex 中。唯一需要数据的组件是 Messages.vue 本身,因此它应该只存储在组件中data()

问题:我无法actions.js在里面导入,Messages.vue因为该操作不应该更新 Vuex。但我无法将 移动actions.jsapi目录,因为这破坏了将所有向商店添加数据的文件放在商店目录中的逻辑。除此之外,逻辑应该放在里面Messages.vue。例如,当 api 返回错误时,error应设置本地 -constant。所以它不能由单独的文件处理。

进行 api 调用并将它们存储在 vuex 或 local 中的推荐应用程序结构是什么data()?将操作文件、api 文件等放在哪里?查看 Jackblog 示例时,它仅支持 Vuex 数据。如何重组它以支持两者?

4

2 回答 2

7

我使用axios作为 HTTP 客户端进行 API 调用,我gateways在我的文件夹中创建了一个文件src夹,并且我为每个后端创建了文件,创建axios 实例,如下所示

myApi.js

import axios from 'axios'
export default axios.create({
  baseURL: 'http://localhost:3000/api/v1',
  timeout: 5000,
  headers: {
    'X-Auth-Token': 'f2b6637ddf355a476918940289c0be016a4fe99e3b69c83d',
    'Content-Type': 'application/json'
  }
})

这些相同的实例用于组件和 vuex 操作以获取数据,以下是两种方式的详细信息。

填充组件数据

如果数据仅在组件中使用,例如您的情况Messages.vue,您可以使用一种方法从 api 获取数据,如下所示:

export default {
  name: 'myComponent',
  data: () => ({
    contents: '',
    product: []
  }),
  props: ['abc'],
  methods: {
    getProducts (prodId) {
       myApi.get('products?id=' + prodId).then(response => this.product = response.data)
       },
       error => {
          console.log('Inside error, fetching products failed')
          //set error variable here
       })
    }
    ..... 

填充 Vuex 数据

如果您在专用vuex 模块中维护产品相关数据,您可以从组件中的方法调度一个操作,该操作将在内部调用后端 API 并在存储中填充数据,代码如下所示:

组件中的代码:

methods: {
 getProducts (prodId) {
     this.$store.dispatch('FETCH_PRODUCTS', prodId)
  }
}

Vuex商店中的代码:

import myApi from '../../gateways/my-api'
const state = {
  products: []
}

const actions = {
  FETCH_PRODUCTS: (state, prodId) => {
    myApi.get('products?id=' + prodId).then(response => state.commit('SET_PRODUCTS', response))
  }
} 

// mutations
const mutations = {
  SET_PRODUCTS: (state, data) => {
    state.products = Object.assign({}, response.data)
  }
}

const getters = {
}

export default {
  state,
  mutations,
  actions,
  getters
}
于 2016-11-27T15:31:31.460 回答
2

简短回答:考虑 Jackblog 示例 - 您只需要从组件中导入“api”,然后直接使用 API。不要导入操作。在 Messages.vue 中,忘记存储。您不需要绑定到商店的操作层。您只需要 API。


长答案:在一个项目中,我们有以下内容

  1. Ajax 库包装器提供一个名为的函数,该函数remote接受两个参数:一个字符串和一个对象。字符串告诉我们要实现什么(例如,“saveProductComment”),对象是有效负载(参数的名称和值,要发送到服务器)。

  2. 每个应用程序模块可能包含一个“ routes.js ”文件,该文件将上面的“字符串”映射到一个路由配置。例如:saveProductComment: 'POST api/v1/products/{product_id}/comment'

注意:我没有使用术语“应用程序模块”来表示被 NodeJS 或 Webpack 视为“模块”的单个文件.js或文件。.vue我将“应用程序模块”称为包含与特定域相关的应用程序代码的完整文件夹(例如:“购物车”模块、“帐户”模块、“评论”模块)。

  1. 从任何地方,我们都可以调用remote('saveProductComment', { product_id: 108, comment: 'Interesting!' }),它返回一个Promise。包装器使用路由配置来构建正确的请求,它还解析响应并处理错误。在任何情况下,该remote函数总是返回一个Promise.

  2. 每个 app 模块还可以提供自己的store 模块,我们在其中定义与模块相关的初始状态、突变、动作和 getter。我们使用术语“Manager”来表示状态管理代码。例如,我们可以有一个“ commentsManager.js ”文件,提供存储模块来处理“评论”。

  3. 在 Manager 中,我们使用该remote函数在 Vuex操作中进行 API 调用。我们从远程返回 Promise,但我们也将处理结果的回调附加到它。在回调中,我们调用变异函数来提交结果:


newProductComment ({ commit }, { product, contents }) {
    return remote('saveProductComment', {
        product_id: product.id,
        comment: contents
    })
    .then(result => {
        commit('SOME_MUTATION', result.someProperty)
    })
}

现在,如果我们想在 Vuex 上下文之外直接在组件内部使用相同的 API 调用,我们只需要在 Vue 组件方法中使用类似的代码。例如:

export default {
    name: 'myComponent',
    data: () => ({
        contents: '',
        someData: null
    }),
    props: ['product'],
    methods: {
        saveComment () {
            remote('saveProductComment', {
                product_id: this.product.id,
                comment: this.contents
            })
            .then(result => {
                this.someData = result.someProperty
            })
        }
    }
}

在应用程序结构方面,对我们来说真正重要的是:

  • 将应用程序正确划分为不同的关注点;我们称之为“应用程序模块”;每个特定事物的一个模块

  • 我们有一个“模块”文件夹,其中包含每个“应用程序模块”的文件夹

  • 在特定的“应用程序模块文件夹”中,我们有路由配置routes.js,将远程函数的第一个参数映射到路由配置;我们的自定义代码选择 HTTP 方法,插入 URL,做各种花哨的东西,完全适合我们的需求;但在应用程序代码的其余部分,我们只是以这种简单的方式使用它:remote('stuffNeededToBeAccomplished', { dataToAccomplishTheNeed })

  • 换句话说,繁重的工作是在映射和 Ajax 库包装器中(您可以使用任何 Ajax 库来处理实际请求);请注意,这完全独立于使用 Vue / Vuex

  • 我们的 Vuex 商店也分为模块;通常,在一个应用程序模块中,我们有相应的商店模块,使用那里定义的路由

  • 在主入口点,我们导入应用程序模块;每个模块的 index.js 负责在 Ajax 包装器中注册路由和在 Vuex 中注册存储模块(因此,我们只需要导入,无需采取进一步行动,即可获得可用于 Ajax 的路由和可用的存储模块在 Vuex 中)

于 2016-11-28T13:50:40.603 回答