jQuery 版本购物车(融入设计模式)

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'
      }
    }
  }
}

猜你喜欢

转载自blog.csdn.net/Cipuzp/article/details/83896068