# 综合应用
# 介绍
- 使用 jQuery 做一个模拟购物车的示例
- 包括:显示购物列表、加入购物车、从购物车删除
# 用到的设计模式
- 工程模式:$('xxx'), 创建商品
// 1
constructor(id) {
// 工厂模式
this.$el = $('#' + id)
}
// 2
// 工厂函数
export default function(list, itemData) {
if(itemData.discount) {
itemData = createDiscount(itemData)
}
return new Item(list, itemData)
}
- 单例模式:购物车
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
- 装饰器模式:打点统计
// 添加到购物车
@log('add')
addToCartHandle() {
this.cart.add(this.data)
}
// 从购物车删除
@log('del')
deleteFromCartHandle() {
this.cart.del(this.data.id)
}
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
}
}
- 观察者模式:网页事件,Promise
- 状态模式:添加到购物车 & 从购物车删除
initBtn() {
let $el = this.$el
let $btn = $('<button>')
const _this = this
let fsm = new StateMachine({
init: '加入购物车',
transitions: [
{
name: 'addToCart',
form: '加入购物车',
to: '从购物车删除'
},
{
name: 'deleteFromCart',
form: '从购物车删除',
to: '加入购物车'
}
],
methods: {
// 加入购物车
onAddToCart() {
_this.addToCartHandle()
updateText()
},
// 从购物车移除
onDeleteFromCart() {
_this.deleteFromCartHandle()
updateText()
}
}
})
function updateText() {
$btn.text(fsm.state)
}
$btn.click(() => {
if(fsm.is('加入购物车')) {
fsm.addToCart()
} else {
fsm.deleteFromCart()
}
})
updateText()
$el.append($btn)
}
- 模板方法模式:渲染有统一的方法,内部包含了各模块渲染
- 代理模式:打折商品信息处理
function createDiscount(itemData) {
// 用代理做折扣显示
return new Proxy(itemData, {
get: function(target, key, receiver) {
if(key === 'name') {
return `${target[key]}【折扣】`
}
if(key === 'price') {
return target[key] * 0.8
}
return target[key]
}
})
}
# UML 类图
# 代码
- index.js
import App from './demo/App'
let app = new App('app')
app.init()
- App.js
import $ from 'jquery'
import ShoppingCart from './ShoppingCart/ShoppingCart'
import List from './List/List'
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()
}
}
- ./List/List.js
import $ from 'jquery'
import { GET_LIST } from '../config/config'
import createItem from '../Item/CreateItem'
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 => {
// 创建一个 Item 然后 init
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()
})
}
}
- ./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/ShoppingCart.js
import $ from 'jquery'
import getCart from './GetCart'
export default class ShoppingCart {
constructor(app) {
this.app = app
this.$el = $('<div>').css({
'padding-bottom': '10px',
'border-bottom': '1px solid #ccc'
})
this.cart = getCart()
}
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)
}
init() {
this.initBtn()
this.render()
}
}
- ./Item/Item.js
import $ from 'jquery'
import StateMachine from 'javascript-state-machine'
import getCart from '../ShoppingCart/GetCart'
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>')
const _this = this
let fsm = new StateMachine({
init: '加入购物车',
transitions: [
{
name: 'addToCart',
form: '加入购物车',
to: '从购物车删除'
},
{
name: 'deleteFromCart',
form: '从购物车删除',
to: '加入购物车'
}
],
methods: {
// 加入购物车
onAddToCart() {
_this.addToCartHandle()
updateText()
},
// 从购物车移除
onDeleteFromCart() {
_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()
}
}
- ./Item/CreateItem.js
import Item from './Item'
function createDiscount(itemData) {
// 用代理做折扣显示
return new Proxy(itemData, {
get: function(target, key, receiver) {
if(key === 'name') {
return `${target[key]}【折扣】`
}
if(key === 'price') {
return target[key] * 0.8
}
return target[key]
}
})
}
// 工厂函数
export default function(list, itemData) {
if(itemData.discount) {
itemData = createDiscount(itemData)
}
return new Item(list, itemData)
}
- ./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
}
}
- ./config/config.js
export const GET_LIST = '/api/list.json'
- ./api/list.json
[
{
"id": 1,
"name": "《JS 基础面试题》",
"price": 149,
"discount": 1
},
{
"id": 2,
"name": "《JS 高级面试题》",
"price": 366,
"discount": 1
},
{
"id": 3,
"name": "《React 模拟大众点评 webapp》",
"price": 248,
"discount": 0
},
{
"id": 4,
"name": "《zepto 设计与源码解读》",
"price": 0,
"discount": 0
}
]
阅读量:
评 论:
← 其他设计模式