jQuery 版本购物车(融入设计模式)
1. 介绍
1.1 功能
- 显示购物列表、加入购物车、从购物车删除
1.2 用到的设计模式
- 工厂模式
$('XXX')
,创建商品
- 单例模式
- 购物车
- 装饰器模式
- 打点统计
- 观察者模式
- 网页事件、Promise
- 状态模式
- 添加/删除购物车
- 模板方法模式
init()
,统一的方法渲染
- 代理模式
- 打折商品信息处理
1.3 UML 演示
2. 代码演示
2.1 代码目录
2.2 api
- list.json
[ { id: 1, name: '《JS高级程序设计》', price: 87, discount: 1 }, { id: 2, name: '《新零售》', price: 42, discount: 1 }, { id: 3, name: '《干法》', price: 56, discount: 0 }, { id: 4, name: '《剑指offer》', price: 32, discount: 0 } ]
2.3 config
- config.js
export const GET_LIST = '../api/list.json'
2.4 List
-
CreateItem.js
import Item from './Item.js' //优惠商品处理逻辑 function createDiscount(itemData) { //代理模式 return new Proxy(itemData, { get: function(target, key, receicer) { if (key === 'name') { return `${target[key]}【折扣】` } if (key === 'price') { return Math.floor(target[key] * 0.8 * 100) / 100 } return target[key] } }) } //工厂模式 export default function(list, itemData) { if (itemData.discount) { itemData = createDiscount(itemData) } return new Item(list, itemData) }
-
Item.js
import $ from 'jquery' import getCart from '../ShoppingCart/GetCart.js' import StateMachine from 'javascript-state-machine' import { log } from '../util/log' export default class Item { constructor(list, data) { this.list = list this.data = data this.$el = $('<div>') this.cart = getCart() } initContent() { let $el = this.$el let data = this.data $el.append($(`<p>名称:${data.name}</p>`)) $el.append($(`<p>价格:${data.price}</p>`)) } initBtn() { let $el = this.$el let $btn = $('<button>') //状态模式 let _this = this let fsm = new StateMachine({ init: '加入购物车', transitions: [ { name: 'addToCart', from: '加入购物车', to: '从购物车删除' }, { name: 'deleteFromCart', from: '从购物车删除', to: '加入购物车' } ], methods: { //加入购物车 onAddToCart: function() { _this.addToCartHandle() updateText() }, //从购物车删除 onDeleteFromCart: function() { _this.deleteFromCartHandle() updateText() } } }) function updateText() { $btn.text(fsm.state) } //观察者模式 $btn.click(() => { //增加到购物车 if (fsm.is('加入购物车')) { fsm.addToCart() } else { fsm.deleteFromCart() } //从购物车移除 }) updateText() $el.append($btn) } //装饰器模式 //添加到购物车 // @log('add') addToCartHandle() { this.cart.add(this.data) } //从购物车删除 // @log('del') deleteFromCartHandle() { this.cart.del(this.data.id) } render() { this.list.$el.append(this.$el) } //模板方法模式 init() { this.initContent() this.initBtn() this.render() } }
-
List.js
import $ from 'jquery' import { GET_LIST } from '../config/config.js' import createItem from './CreateItem.js' export default class List { constructor(app) { this.app = app this.$el = $('<div>') } //获取数据 loadData() { //观察者模式 //返回Promise实例 return fetch(GET_LIST).then(result => { return result.json() }) } //生成列表 initItemList(data) { data.forEach(itemData => { let item = createItem(this, itemData) item.init() }) } //渲染 render() { this.app.$el.append(this.$el) } init() { //观察者模式 this.loadData() .then(data => { this.initItemList(data) }) .then(() => { //渲染 this.render() }) } }
2.5 ShoppingCart
-
GetCart.js
//单例模式 class Cart { constructor() { this.list = [] } add(data) { this.list.push(data) } del(id) { this.list = this.list.filter(item => { if (item.id === id) { return false } return true }) } getList() { return this.list .map(item => { return item.name }) .join('\n') } } let getCart = (function() { let cart return function() { if (!cart) { cart = new Cart() } return cart } })() export default getCart
-
ShoppingCart.js
import $ from 'jquery' import getCart from './GetCart' export default class ShoppingCart { constructor(app) { this.$el = $('<div>').css({ 'padding-bottom': '10px', 'border-bottom': '1px solid #ccc' }) this.app = app this.cart = getCart() } init() { this.initBtn() this.render() } initBtn() { let $btn = $('<button>购物车</button>') $btn.click(() => { this.showCart() }) this.$el.append($btn) } showCart() { alert(this.cart.getList()) } render() { this.app.$el.append(this.$el) } }
2.6 util
- log.js
//装饰器模式 export function log(type) { return function(target, name, descriptor) { let oldValue = descriptor.value descriptor.value = function() { //打印日志 console.log('日志上报${type}') //执行原有的方法 return oldValue.apply(this, arguments) } return descriptor } }
2.7 app.js
import $ from 'jquery'
import ShoppingCart from './ShoppingCart/ShoppingCart.js'
import List from './List/List.js'
export default class App {
constructor(id) {
//工厂模式
this.$el = $('#' + id)
}
//初始化购物车
initShoppingCart() {
let shoppingCart = new ShoppingCart(this)
shoppingCart.init()
}
//初始化列表
initList() {
let list = new List(this)
list.init()
}
init() {
this.initShoppingCart()
this.initList()
}
}
2.8 index.js
import App from './demo/App.js'
let app = new App('app')
app.init()
2.9 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>购物车</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript"></script>
</body>
</html>
2.10 webpack.dev.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
path: __dirname,
filename: './release/bundle.js'
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules)/,
loader: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
],
devServer: {
contentBase: path.join(__dirname, './release'), //根目录
open: true, //自动打开浏览器
port: 9000,
proxy: {
'/api/*': {
target: 'http://localhost:8880'
}
}
}
}