![68630014b941ecaf181719306420a3d4.png](https://img-blog.csdnimg.cn/img_convert/68630014b941ecaf181719306420a3d4.png)
本文由图雀社区成员 Holy[1] 使用 Tuture[2] 实战教程写作工具 写作而成,欢迎加入图雀社区,一起创作精彩的免费技术实战教程,予力编程行业发展。
前面五篇教程我们已经基本实现了迷你全栈电商应用的界面展示以及功能逻辑,相信大家在这个过程中都收获颇丰,并且迈向了全栈工程师的第一步。但是我们却并不满足于此,我们还需要对我们的项目代码进行优化,使得我们的代码可读性更高,也更好维护。相信细心的你们已经感觉到了项目中的store实例实在是过于臃肿,因此,本篇教程就是带大家一起学习如何抽出 Getters 、 Mutations 和Actions 逻辑实现store的“减重”以及如何干掉 mutation-types 硬编码。
欢迎阅读《从零到部署:用 Vue 和 Express 实现迷你全栈电商应用》系列:
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(一)[3]
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(二)[4]
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(三)[5]
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(四)[6]
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(五)[7]
- 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(六)(也就是这篇)
如果你希望直接从这一步开始,请运行以下命令:
git clone -b section-six https://github.com/tuture-dev/vue-online-shop-frontend.git
cd vue-online-shop-frontend
本文所涉及的源代码都放在了 Github[8] 上,如果您觉得我们写得还不错,希望您能给❤️这篇文章点赞+Github仓库加星❤️哦~
抽出 Getters 和 Mutations 逻辑
这一节我们来学习如何抽出在store
实例中定义的复杂getters
和mutation
逻辑。
我们发现之前我们直接把所有的getter
属性和方法都定义在了store
实例中的getters
属性中,所有的mutation
属性也都定义在了store
实例中的mutations
属性中,这样显得store
实例特别的累赘,因此我们可以通过对象展开运算符将这些复杂的逻辑抽取到对应的 Getters
和 Mutations
文件中。
重构 Admin 入口文件
首先我们做一点本土化,把之前的 src/pages/admin/Index.vue
中的英文导航改成中文版,方便查看;并且我们增加了查看生产商导航。
<template>
<div>
<div class="admin-new">
<div class="container">
<div class="col-lg-3 col-md-3 col-sm-12 col-xs-12">
<ul class="admin-menu">
<li>
<router-link to="/admin">查看商品router-link>
li>
<li>
<router-link to="/admin/new">添加商品router-link>
li>
<li>
<router-link to="/admin/manufacturers">查看生产商router-link>
li>
ul>
div>
<router-view>router-view>
div>
div>
div>
template>
这里我们将有关商品的导航栏修改为中文版,让用户能够秒懂;除此之外我们又添加了有关制造商的导航,这里增加的是查看生产商导航,并添加了对应的导航跳转路径,该路径需要与对应路由参数一致。
创建 Manufacturers 组件
我们创建的src/pages/admin/Manufacturers.vue
文件是本地制造商组件,用于展示制造商的信息。
<template>
<div>
<table class="table">
<thead>
<tr>
<th>制造商th>
<th>th>
<th>th>
tr>
thead>
<tbody>
<tr v-for="manufacturer in manufacturers" :key="manufacturer._id">
<td>{
{manufacturer.name}}td>
<td class="modify"><router-link :to="'/admin/manufacturers/edit/' + manufacturer._id">修改router-link>td>
<td class="remove"><a @click="removeManufacturer(manufacturer._id)" href="#">删除a>td>
tr>
tbody>
table>
div>
template>
<style>table {
margin: 0 auto;
}.modify {
color: blue;
}.remove a {
color: red;
}style>
<script>export default {
created() {
if (this.manufacturers.length === 0) {
this.$store.dispatch('allManufacturers');
}
},computed: {
manufacturers() {
return this.$store.getters.allManufacturers
}
},methods: {
removeManufacturer(manufacturerId) {
// 使用 JavaScript BOM 的 confirm 方法来询问用户是否删除此制造商const res = confirm('是否删除此制造商?');// 如果用户同意,那么就删除此制造商if (res) {
this.$store.dispatch('removeManufacturer', {
manufacturerId,
})
}
}
}
}script>
这里首先定义了一个计算属性manufacturers
,通过this.$store.getters.allManufacturers
属性访问的形式调用对应的getter
属性allManufacturers
从本地获取manufacturers
,并返回给计算属性manufacturers
。
然后在该组件刚被创建时判断本地中是否存在manufacturers
,如果没有则通过this.$store.dispatch
分发到类型为allManufacturers
的action
中进行异步操作获取所有制造商,并将获取的制造商提交到对应的mutation
中,在mutation
中修改本地状态,将获取的所有制造商保存到本地。
最后利用v-for
在表格中遍历manufacturers
,每个制造商的信息在一行展示,除了信息之外还有两个功能(修改和删除制造商),点击修改则会根据'/admin/manufacturers/edit/' + manufacturer._id
路由到指定页面;点击删除则会触发removeManufacturer
事件,首先询问用户是否同意删除,若用户同意则将选中制造商的id作为载荷分发到类型为removeManufacturer
的action
中,在action
中进行异步操作删除后端对应商品,并将对应商品id提交到对应的mutation
中,在mutation
中进行本地状态修改,删除本地对应的商品。
重构 Products 组件
根据Manufacturers
组件的设计原则,我们需要再次进入src/pages/admin/Products.vue
文件。按照Manufacturers
组件的UI展示以及数据处理,将Products
组件进行一下重构。
<template>
<div>
<table class="table">
<thead>
<tr>
<th>名称th>
<th>价格th>
<th>制造商th>
<th>th>
<th>th>
tr>
thead>
<tbody>
<tr v-for="product in products" :key="product._id">
<td>{
{product.name}}td>
<td>{
{product.price}}td>
<td>{
{product.manufacturer.name}}td>
<td class="modify"><router-link :to="'/admin/edit/' + product._id">修改router-link>td>
<td class="remove"><a @click="removeProduct(product._id)" href="#">删除a>td>
tr>
tbody>
table>
div>
template>
<style>table {
margin: 0 auto;
}.modify {
color: blue;
}.remove a {
color: red;
}style>
<script>export default {
created() {
if (this.products.length === 0) {
this.$store.dispatch('allProducts');
}
},computed: {
products() {
return this.$store.getters.allProducts
}
},methods: {
removeProduct(productId) {
// 使用 JavaScript BOM 的 confirm 方法来询问用户是否删除此商品const res = confirm('是否删除此商品?');// 如果用户同意,那么就删除此商品if (res) {
this.$store.dispatch('removeProduct', {
productId,
})
}
}
}
}// ...
这部分代码逻辑与src/pages/admin/Manufacturers.vue
文件中的代码逻辑相似,如果您理解了上面的代码逻辑,那么我们相信您对这里的代码也能融会贯通,所以这里就不再赘述了。
添加路由信息
我们已经创建了有关制造商的导航以及查看制造商组件,还需对其配置相应的路由参数才能实现跳转。因此再次进入src/router/index.js
文件,这里我们导入了制造商组件并增加了制造商相关路由参数。
// ...
import New from '@/pages/admin/New';
import Products from '@/pages/admin/Products';
import Edit from '@/pages/admin/Edit';
import Manufacturers from '@/pages/admin/Manufacturers';
Vue.use(Router);
// ...
name: 'Edit',
component: Edit,
},
{
path: 'manufacturers',
name: 'Manufacturers',
component: Manufacturers,
},
]
},
{
// ...
把项目跑起来,点击Admin
然后再点击查看生产商,我们可以看到从后端获取的所有生产商: 下面展示的就是从后端获取的制造商,并且我们可以对其进行修改和删除操作。
抽取 Getters 逻辑
我们首先创建了src/store/getters.js
文件,用于存放各种不同类型的getter
属性和方法。这里我们导出了两个对象分别为productGetters
和manufacturerGetters
,前者包含了有关商品的getter
属性与方法,后者包含了有关制造商的getter
属性与方法。
export const productGetters = {
allProducts(state) {
return state.products
},
productById: (state, getters) => id => {
if (getters.allProducts.length > 0) {
return getters.allProducts.filter(product => product._id === id)[0]
} else {
return state.product;
}
}
}
export const manufacturerGetters = {
allManufacturers(state) {
return state.manufacturers;
}
}
在productGetters
对象中定义的就是有关商品的getter
属性和方法,如allProducts
,productById
等等;在manufacturerGetters<