使用 Vuex 和特定于组件的数据进行 Vue 结构化
Posted
技术标签:
【中文标题】使用 Vuex 和特定于组件的数据进行 Vue 结构化【英文标题】:Vue structuring with Vuex and component-specific data 【发布时间】:2017-04-11 06:48:48 【问题描述】:我看到很多 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()
中。
问题:我无法在 Messages.vue
中导入 actions.js
,因为该操作不应更新 Vuex。但我无法将actions.js
移动到api
目录,因为这破坏了将所有向存储添加数据的文件放在存储目录中的逻辑。除此之外,逻辑应该放在Messages.vue
中。例如,当 api 返回错误时,应设置本地 error
-constant。所以不能用单独的文件来处理。
进行 api 调用并将它们存储在 vuex 或本地 data()
中的推荐应用程序结构是什么?将操作文件、api 文件等放在哪里?查看 Jackblog 示例时,它仅支持 Vuex 数据。如何重组它以支持两者?
【问题讨论】:
一个深思熟虑的问题。谢谢你的提问,乔迪。 【参考方案1】:我使用 axios 作为 HTTP 客户端进行 API 调用,我在我的 src
文件夹中创建了一个 gateways
文件夹,并且我为每个后端创建了文件 axios instances,如下所示
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 module 中维护产品相关数据, 您可以从组件中的方法调度一个操作,该操作将在内部调用后端 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
【讨论】:
【参考方案2】:简短回答:考虑 Jackblog 示例 - 您只需从组件中导入“api”,并直接使用 API。不要导入操作。在 Messages.vue 中,忘记存储。您不需要绑定到商店的操作层。您只需要 API。
长答案:在一个项目中,我们有以下内容
一个 Ajax 库包装器提供一个名为 remote
的函数,该函数接受两个参数:一个字符串和一个对象。字符串告诉我们要实现什么(例如,“saveProductComment”),对象是有效负载(参数的名称和值,要发送到服务器)。
每个应用模块可能包含一个“routes.js”文件,该文件将上面的“字符串”映射到一个路由配置。例如:saveProductComment: 'POST api/v1/products/product_id/comment'
注意:我不对单个
.js
或.vue
文件使用术语“应用程序模块”,NodeJS 或 Webpack 将其视为“模块”。我将“app 模块”称为包含与特定域相关的应用代码的完整文件夹(例如:“cart”模块、“account”模块、“cmets”模块、等等)。
我们可以从任何地方调用remote('saveProductComment', product_id: 108, comment: 'Interesting!' )
,它会返回一个Promise
。包装器使用路由配置来构建正确的请求,它还解析响应并处理错误。在任何情况下,remote
函数总是返回一个Promise
。
每个应用程序模块还可以提供自己的存储模块,我们在其中定义与模块相关的初始状态、突变、动作和获取器。我们使用术语“Manager”来表示状态管理代码。例如,我们可以有一个“cmetsManager.js”文件,提供存储模块来处理“cmets”。
在 Manager 中,我们使用 remote
函数在 Vuex actions 中进行 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 模块文件夹”中,我们在routes.js
有 routes 配置,将远程函数第一个参数映射到路由配置;我们的自定义代码选择 HTTP 方法,插入 URL,做各种花哨的东西,完全适合我们的需求;但在应用程序代码的其余部分,我们只是使用它以这种简单的方式:remote('stuffNeededToBeAccomplished', dataToAccomplishTheNeed )
换句话说,繁重的工作是在映射和 Ajax 库包装器中(您可以使用任何 Ajax 库来处理实际请求);请注意,这完全独立于使用 Vue / Vuex
我们将 Vuex 存储也划分为模块;通常,在一个应用模块中,我们有相应的商店模块使用那里定义的路由
在主入口点,我们导入应用模块;每个模块的 index.js 负责在 Ajax 包装器中注册路由和在 Vuex 中注册存储模块(因此,我们只需要导入,无需采取进一步行动,即可获得可用于 Ajax 的路由和可用的存储模块在 Vuex 中)
【讨论】:
谢谢。因此,如果我理解正确:如果您想使用 Vuex 全局存储数据,您只需从组件内部调用 Vuex 操作函数。如果你想在本地存储它,你运行远程功能?如果我想要他们两个怎么办?例如:获取用户 cmets 时,我想在本地存储 cmets,但在全局范围内执行“LAST_TIME_ONLINE”操作。以上是关于使用 Vuex 和特定于组件的数据进行 Vue 结构化的主要内容,如果未能解决你的问题,请参考以下文章