我看到很多使用这种结构的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
想要更新Vuex中的inCart
数据。为此,购物车导入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.js
移动到api
目录,因为这打破了将所有添加数据的文件放入store-directory中的存储的逻辑。除此之外,逻辑应放在Messages.vue
内。例如,当api返回错误时,应设置本地error
- 常量。所以它不能由单独的文件处理。
建议api调用并将其存储在vuex或本地data()
中的应用程序结构是什么?放置动作文件,api文件等的位置?在查看Jackblog示例时,它仅支持Vuex数据。如何重组这个以支持两者?
答案 0 :(得分:6)
我使用axios作为HTTP客户端进行API调用,我在gateways
文件夹中创建了一个src
文件夹,每个后端都有文件,创建{{3} },如下面的
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
})
}
.....
如果您使用专用axios instances维护产品相关数据, 你可以从组件中的方法调度一个动作,它将在内部调用后端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
}
答案 1 :(得分:2)
简短回答:考虑到Jackblog示例 - 您只需要从组件中导入“api”,然后直接使用API。不要导入操作。在Messages.vue中,忘记商店。您不需要与商店绑定的actions层。你只需要API。
答案很长:在一个项目中,我们有以下内容
Ajax库包装器,提供名为 remote
的函数,该函数接受两个参数:字符串和对象。字符串告诉我们要实现的目标(例如,“saveProductComment”),对象是有效负载(参数的名称和值,将被发送到服务器)。
每个应用模块都可能包含一个“ routes.js ”文件,该文件使用路由配置映射上面的“字符串”。例如:saveProductComment: 'POST api/v1/products/{product_id}/comment'
注意:我不使用术语“app module”表示单个
.js
或.vue
文件,该文件被NodeJS或Webpack视为“模块”。我称“app module”为包含与特定域相关的应用代码的完整文件夹(例如:“购物车”模块,“帐户”模块,“评论”模块,等等)。
我们可以在任何地方致电remote('saveProductComment', { product_id: 108, comment: 'Interesting!' })
,然后返回Promise
。包装器使用路由配置来构建正确的请求,它还解析响应并处理错误。在任何情况下,remote
函数始终返回Promise
。
每个app模块还可以提供自己的商店模块,我们在其中定义与模块相关的初始状态,突变,操作和getter。我们使用术语“经理”作为州管理代码。例如,我们可以有一个“ commentsManager.js ”文件,为商店模块提供“评论”。
在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
})
}
}
}
在应用程序结构方面,对我们来说真正重要的是:
将应用程序正确划分为不同的问题;我们称之为“app modules”;每个特定事物的一个模块
我们有一个“modules”文件夹,其中包含每个“app module”的文件夹
在特定的“app module文件夹”中,我们在routes.js
处有 routes config,将远程函数first参数映射到路由配置;我们的自定义代码选择HTTP方法,插入URL,做各种花哨的东西,适合我们的需要;但是在剩余的应用代码中的任何地方,我们只是以这种简单的方式使用:remote('stuffNeededToBeAccomplished', { dataToAccomplishTheNeed })
换句话说,繁重的工作是在映射和Ajax库包装器中(您可以使用任何Ajax库来实际请求);请注意,这完全独立于使用Vue / Vuex
我们将Vuex商店分成模块;通常,在app模块中,我们使用相应的商店模块
在主入口点,我们导入app模块;每个模块的index.js负责注册Ajax包装器中的路由和Vuex中的商店模块(因此,我们只需要导入,不采取进一步操作,为Ajax和商店模块提供可用的路由在Vuex)