用 Vue 提供的 methods 来处理业务是我们从一开始学 Vue 的习惯做法,但是,这会产生一个弊端,就是当业务十分复杂时,methods 中的代码就会变得十分冗长,使得代码阅读性下降,调试和维护的难度也跟着加大。因此,我个人比较强烈推荐将业务从 Vue 的 methods 中分离出来集中管理的。接下来,我们用购物车为例来说明用 class 封装业务逻辑,去掉 methods 的具体做法。
我们在 data 中创建购物车对象 cart 时,不是用 cart: { } 来初始化购物车,而是通过 cart : new ShoppingCar() 。在这里我们无需写任何 methods,但是对于一些计算属性,我们仍然要明确写出来,不过可以通过调用 cart 对象的方法来完成。
import Vue from 'https://dev.jspm.io/vue/dist/vue';
import {ShoppingCart} from './shoppingCart.j'
//some fake products
let products = [
{ id: "170001", name: "masks" , "price": 10},
{ id: "170002", name: "pears" , "price": 6},
{ id: "170003", name: "cakes" , "price": 40},
{ id: "170004", name: "bikes" , "price": 200},
]
/*
Important Here!!!
1. We create an empty shopping cart by using class ShoppingCart instead of passing a {}.
2. We still need to add the computed attrs, but that's bearable because we can compute them by calling methods from ShoppingCart
*/
new Vue({
el: "#app",
data() {
return {
cart: new ShoppingCart(), //==>1
products
};
},
/*No methods are needed, as we are able to define them in ShoppingCart class*/
computed: {
count() {
return this.cart.count(); //==>2
},
totalPrice() {
return this.cart.totalPrice();
}
}
});
这里我们封装 cart 对象的所有业务逻辑(添加,删除,计算数量和总额等),本来写在 methods 中的代码,被我们搬到 ShoppingCart 集中管理,使得 script.js 中原本的 Vue 实例代码更加精简,也使得购物车的业务代码更加集中,容易维护。
import Vue from 'https://dev.jspm.io/vue/dist/vue';
export class ShoppingCart {
list = {};//shopping cart content
constructor() {
//this.list = {}
}
//Add an item to the shopping cart
add(item) {
let exist = Object.keys(this.list).includes((item.id));
if(exist) {
this.list[item.id].count++;
}else{
Vue.set(this.list, item.id, {"id": item.id, "name": item.name, count: 1, price: item.price });
}
}
//Remove an item from the shopping cart
remove(item) {
if(!this.list[item.id]) return;
this.list[item.id].count--;
if(this.list[item.id].count == 0) {
delete this.list[item.id];
}
}
//Count the total number of all items
count() {
let items = Object.values(this.list)
let total = items.reduce((total, item )=> {
return total += item.count;
}, 0);
return total;
}
//Count the total price of all items
totalPrice() {
let items = Object.values(this.list)
let total = items.reduce((total, item )=> {
return total += item.price * item.count;
}, 0);
return total;
}
}
在 html 或 template 中,我们的 click 事件调用的不是 methods 中的方法,而是 cart 对象的方法。
<html>
<head>
<link rel="stylesheet" href="lib/style.css">
head>
<body>
<h1>My Shopping Carth1>
<div id="app">
<div v-for="(item, i) in products">
<button @click="cart.add(item)">add {{item.name}}button>
<button @click="cart.remove(item)">remove {{item.name}}button>
div>
Shopping Cart: {{count}} items, total price is {{totalPrice}}
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<th>idth><th>nameth><th>unit priceth>
<th>countth><th>priceth>
tr>
<tr v-for="(item, i) in cart.list">
<td>{{item.id}}td>
<td>{{item.name}}td>
<td>{{item.price}}td>
<td>{{item.count}}td>
<td>{{item.price * item.count}}td>
tr>
ul>
div>
body>
<script type="module" src="lib/script.js">script>
html>