preface

Last semester, I learned vue. js and Node.js in my spare time. I always wanted to do a complete project for practice, but I didn’t have enough time in school before. Now that I have the time, I want to do a project to reinforce what I’ve learned.

I finally decided to imitate Mi Mall to do an e-commerce project, which is almost finished now. This paper summarizes the realization of shopping cart module.

instructions

Complete project repository: github.com/hai-27/vue-… .

The project is deployed on my server, preview link: http://106.15.179.105 (not compatible with mobile terminal, please use PC to access).

This article only summarizes the front-end part, the back-end uses Node.js(Koa)+Mysql implementation, detailed code please go to github.com/hai-27/stor… .

New post, if there is something wrong, please advise more

The effect

No more words, see the effect first

Implementation steps

1. Prepare static pages

The page uses the element-UI Icon, el-checkbox, el-Input-number, el-popover, el-button, all of which need to be introduced in main.js.

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Copy the code

The page code is as follows:

Note: For convenience, put the final code directly here.

<template>
  <div class="shoppingCart">
    <! -- Shopping cart header -->
    <div class="cart-header">
      <div class="cart-header-content">
        <p>
          <i class="el-icon-shopping-cart-full" style="color:#ff6700; font-weight: 600;">
          </i>My shopping cart</p>
        <span>Tips: Whether the product is purchased successfully depends on the final order. Please settle as soon as possible</span>
      </div>
    </div>
    <! END -->

    <! -- Shopping cart main content area -->
    <div class="content" v-if="getShoppingCart.length>0">
      <ul>
        <! -- Shopping cart header -->
        <li class="header">
          <div class="pro-check">
            <el-checkbox v-model="isAllCheck">select all</el-checkbox>
          </div>
          <div class="pro-img"></div>
          <div class="pro-name">Name of commodity</div>
          <div class="pro-price">The unit price</div>
          <div class="pro-num">The number of</div>
          <div class="pro-total">subtotal</div>
          <div class="pro-action">operation</div>
        </li>
        <! END -->

        <! -- Shopping cart list -->
        <li class="product-list" v-for="(item,index) in getShoppingCart" :key="item.id">
          <div class="pro-check">
            <el-checkbox :value="item.check" @change="checkChange($event,index)">
            </el-checkbox>
          </div>
          <div class="pro-img">
            <router-link :to="{ path: '/goods/details', query: {productID:item.productID} }">
              <img :src="$target + item.productImg" />
            </router-link>
          </div>
          <div class="pro-name">
            <router-link
              :to="{ path: '/goods/details', query: {productID:item.productID} }"
            >{{item.productName}}</router-link>
          </div>
          <div class="pro-price">{{item. Price}}</div>
          <div class="pro-num">
            <el-input-number
              size="small"
              :value="item.num"
              @change="handleChange($event,index,item.productID)"
              :min="1"
              :max="item.maxNum"
            ></el-input-number>
          </div>
          <div class="pro-total pro-total-in">{{item. The item price *. Num}}</div>
          <div class="pro-action">
            <el-popover placement="right">
              <p>Are you sure?</p>
              <div style="text-align: right; margin: 10px 0 0">
                <el-button
                  type="primary"
                  size="mini"
                  @click="deleteItem($event,item.id,item.productID)"
                >determine</el-button>
              </div>
              <i class="el-icon-error" slot="reference" style="font-size: 18px;"></i>
            </el-popover>
          </div>
        </li>
        <! END -->
      </ul>
      <div style="height:20px; background-color: #f5f5f5"></div>
      <! -- Shopping cart bottom navigation bar -->
      <div class="cart-bar">
        <div class="cart-bar-left">
          <span>
            <router-link to="/goods">To continue shopping</router-link>
          </span>
          <span class="sep">|</span>
          <span class="cart-total"><span class="cart-total-num">{{getNum}}</span>Item, selected<span class="cart-total-num">{{getCheckNum}}</span></span>
        </div>
        <div class="cart-bar-right">
          <span>
            <span class="total-price-title">Total:</span>
            <span class="total-price">{{getTotalPrice}}</span>
          </span>
          <router-link :to="getCheckNum > 0 ? '/confirmOrder' : ''">
            <div :class="getCheckNum > 0 ? 'btn-primary' : 'btn-primary-disabled'">To settle accounts</div>
          </router-link>
        </div>
      </div>
      <! -- Shopping cart navigation bar END -->
    </div>
    <! -- Shopping cart main contents END -->

    <! -- What to display when shopping cart is empty -->
    <div v-else class="cart-empty">
      <div class="empty">
        <h2>Your shopping cart is still empty!</h2>
        <p>Go shopping!</p>
      </div>
    </div>
    <! -- What to display when shopping cart is empty
  </div>
</template>
Copy the code

2. Create Vuex

/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

import shoppingCart from './modules/shoppingCart'

Vue.use(Vuex)

export default new Vuex.Store({
  strict: true.modules: {
    shoppingCart
  }
})
Copy the code

/store/modules/shoppingCart.js

export default {
  state: {
    shoppingCart: []
    / / shoppingCart structure
    /* shoppingCart = {id: "", // shoppingCart = {id: "", // shoppingCart = {id: "", // shoppingCart = {id: "", // shoppingCart = {id: "", // "Num: / / commodity prices", "", / / quantity maxNum:" ", / / commodity purchase quantity check: check whether false / /} * /}}Copy the code

3. Synchronize shopping cart status

Ideas:

  • Monitor user login status in the root component app.vue;
  • If the user is logged in, retrieve the user’s shopping cart data from the database and update the obtained data to VUEX;
  • The user is not logged in. Set the status of the shopping cart in VUEX to empty.

The code is as follows:

import { mapActions } from "vuex";
import { mapGetters } from "vuex"; computed: { ... mapGetters(["getUser"."getNum"])},methods: {
  ...mapActions(["setShoppingCart"]),
}
watch: {
  // Obtain the vuEX login status
  getUser: function(val) {
    if (val === "") {
      // The user is not logged in
      this.setShoppingCart([]);
    } else {
      // The user has logged in to get the shopping cart information for the user
      this.$axios
        .post("/api/user/shoppingCart/getShoppingCart", {
          user_id: val.user_id
        })
        .then(res= > {
          if (res.data.code === "001") {
            // 001 To succeed, update vuex shopping cart status
            this.setShoppingCart(res.data.shoppingCartData);
          } else {
            // A failure message is displayed
            this.notifyError(res.data.msg);
          }
        })
        .catch(err= > {
          return Promise.reject(err); }); }}}Copy the code

Vuex mutations:

setShoppingCart (state, data) {
	// Set the shopping cart state
	state.shoppingCart = data;
},
Copy the code

The actions of vuex

setShoppingCart({ commit }, data) {
  commit('setShoppingCart', data);
}
Copy the code

4. Dynamically generate shopping cart pages

Ideas:

  • Getters. GetShoppingCart in VUEX to get the status of shopping cart;
  • Use V-if to determine whether the shopping cart has items;
  • If present, use V-for to generate a shopping cart list;
  • If it does not exist, display what was displayed when the shopping cart was empty;

Shopping cart HTML pseudocode:

<div class="shoppingCart">
  <div class="content" v-if="getShoppingCart.length>0">
    <ul>
      <li class="header">
        <! -- Shopping cart header, omit detail code -->
      </li>
      <li class="product-list" v-for="(item,index) in getShoppingCart" :key="item.id">
        <! -- Shopping cart list section, omit detailed code -->
      </li>
    </ul>
  </div>
  <! -- What to display when shopping cart is empty -->
  <div v-else class="cart-empty">
    <div class="empty">
      <h2>Your shopping cart is still empty!</h2>
      <p>Go shopping!</p>
    </div>
    
  </div>
</div>
Copy the code

Vuex getters:

getShoppingCart(state) {
  // Get the cart status
  return state.shoppingCart;
}
Copy the code

5. Add items to cart

Ideas:

  • The user in the product details page, by clicking the add cart button, call click event addShoppingCart;
  • First initiate a request to add shopping cart to the back end, and operate VUEX according to the returned information;
  • The first time the item is added to the cart, the cart information returned by the back end is inserted into vuex through vuex’s Actions (unshiftShoppingCart);
  • The item is already in the shopping cart, add the item quantity +1 by vuex’s Actions (addShoppingCartNum);
  • Do not click add to cart button when the quantity of goods reaches the limit.

HTML:

<el-button class="shop-cart" :disabled="dis" @click="addShoppingCart">Add to shopping cart</el-button>
Copy the code

The logical code is as follows:

methods: { ... mapActions(["unshiftShoppingCart"."addShoppingCartNum"]),
  // Add to cart
  addShoppingCart() {
    // Check whether you are logged in. If you are not logged in, the login component is displayed
    if (!this.$store.getters.getUser) {
      this.$store.dispatch("setShowLogin".true);
      return;
    }
    // The back end makes a request to insert the item information into the shopping cart table of the database
    this.$axios
      .post("/api/user/shoppingCart/addShoppingCart", {
        user_id: this.$store.getters.getUser.user_id,
        product_id: this.productID
      })
      .then(res= > {
        switch (res.data.code) {
          case "001":
            // Added to shopping cart successfully
            this.unshiftShoppingCart(res.data.shoppingCartData[0]);
            this.notifySucceed(res.data.msg);
            break;
          case "002":
            // The item is already in the cart, quantity +1
            this.addShoppingCartNum(this.productID);
            this.notifySucceed(res.data.msg);
            break;
          case "003":
            // The quantity reaches the limit
            this.dis = true;
            this.notifyError(res.data.msg);
            break;
          case "401":
            // No login
            this.$store.dispatch("setShowLogin".true);
            this.notifyError(res.data.msg);
            break;
          default:
            this.notifyError(res.data.msg);
        }
      })
      .catch(err= > {
        return Promise.reject(err); }); }}Copy the code

Vuex mutations:

unshiftShoppingCart(state, data) {
  // Add items to cart
  // It is used to click Add shopping cart on the product details page, and update vuEX status after the background is added successfully
  state.shoppingCart.unshift(data);
},
addShoppingCartNum(state, productID) {
  // Add items to cart
  // It is used to click add shopping cart on the product details page, and the background returns 002, "The product has been in the shopping cart, quantity +1" to update the quantity of vuex goods
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    if (temp.productID == productID) {
      if(temp.num < temp.maxNum) { temp.num++; }}}}Copy the code

Vuex actions:

unshiftShoppingCart({ commit }, data) {
  commit('unshiftShoppingCart', data);
},
addShoppingCartNum({ commit }, productID) {
  commit('addShoppingCartNum', productID);
}
Copy the code

6. Delete items from your cart

Ideas:

  • Each item in the shopping cart has a delete button. If the user clicks the delete button, the confirmation dialog box will pop up first.
  • When the user selects confirm delete, call the click event called deleteItem ($event, the item id, item. The productID);
  • Click the event to get the shopping cart ID and commodity ID;
  • First, initiate a request to delete the shopping cart from the back end, and operate VUEX according to the returned information;
  • Delete the item from the cart by vuex’s Actions (deleteShoppingCart).
  • If the deletion fails, a message is displayed.

HTML:

<div class="pro-action">
  <el-popover placement="right">
    <p>Are you sure?</p>
    <div style="text-align: right; margin: 10px 0 0">
      <el-button type="primary" size="mini" 
      @click="deleteItem($event,item.id,item.productID)">determine</el-button>
    </div>
    <i class="el-icon-error" slot="reference" style="font-size: 18px;"></i>
  </el-popover>
</div>
Copy the code

The logical code is as follows:

methods: {
  // The backend initiates a database information request to delete the shopping cart
  deleteItem(e, id, productID) {
    this.$axios
      .post("/api/user/shoppingCart/deleteShoppingCart", {
        user_id: this.$store.getters.getUser.user_id,
        product_id: productID
      })
      .then(res= > {
        switch (res.data.code) {
          case "001":
            // The deletion succeeded
            // Update the vuEX status
            this.deleteShoppingCart(id);
            // The deletion success message is displayed
            this.notifySucceed(res.data.msg);
            break;
          default:
            // A deletion failure message is displayed
            this.notifyError(res.data.msg);
        }
      })
      .catch(err= > {
        return Promise.reject(err); }); }}Copy the code

Vuex mutations:

deleteShoppingCart(state, id) {
  // Delete the cart item according to the cart ID
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    if (temp.id == id) {
      state.shoppingCart.splice(i, 1); }}}Copy the code

Vuex actions:

deleteShoppingCart({ commit }, id) {
  commit('deleteShoppingCart', id);
}
Copy the code

7. Modify the number of items in your cart

Ideas:

  • Each item in the cart has a counter, which can be modified by clicking the plus or minus button, or by directly entering the number of items in the input box. The counter is usedelement-ui 的el-input-numberThe implementation.
  • The change event of the counter gets the new quantity, the index of the shopping cart item (that is, the index of the array), and the item ID.
  • First, initiate a request to modify the number of items in the shopping cart at the back end, and operate vuEX according to the returned information;
  • Vuex Actions (updateShoppingCart) to change the number of items in the shopping cart.
  • Failure message is displayed. Among them: the quantity is less than 1, whether the quantity reaches the purchase limit (in these two cases, there is a front set check, generally will not appear).

HTML:

<div class="pro-num">
  <el-input-number 
  size="small" 
  :value="item.num" 
  @change="handleChange($event,index,item.productID)" 
  :min="1"
  :max="item.maxNum"
  >
</el-input-number>
Copy the code

The logical code is as follows:

// This function is called when the number of items is changed
handleChange(currentValue, key, productID) {
  // This parameter is selected by default when changing the number
  this.updateShoppingCart({ key: key, prop: "check".val: true });
  // The back end initiates a request to modify the number of items in the cart
  this.$axios
    .post("/api/user/shoppingCart/updateShoppingCart", {
      user_id: this.$store.getters.getUser.user_id,
      product_id: productID,
      num: currentValue
    })
    .then(res= > {
      switch (res.data.code) {
        case "001":
          // 001 indicates that the modification is successful
          // Update the vuEX status
          this.updateShoppingCart({
            key: key,
            prop: "num".val: currentValue
          });
          // A message is displayed indicating that the modification is successful
          this.notifySucceed(res.data.msg);
          break;
        default:
          // Failure message is displayed
          this.notifyError(res.data.msg);
      }
    })
    .catch(err= > {
      return Promise.reject(err);
    });
}
Copy the code

Vuex mutations:

updateShoppingCart(state, payload) {
  // Update the shopping cart
  // The number of items can be updated and whether to check
  // For shopping cart click tick and add or subtract item quantity
  if (payload.prop == "num") {
    // Determine whether the number of goods is greater than the limit or less than 1
    if (state.shoppingCart[payload.key].maxNum < payload.val) {
      return;
    }
    if (payload.val < 1) {
      return; }}// Changes based on the index and properties of the items in the shopping cart array
  state.shoppingCart[payload.key][payload.prop] = payload.val;
}
Copy the code

Vuex actions:

updateShoppingCart({ commit }, payload) {
  commit('updateShoppingCart', payload);
}
Copy the code

8. Check whether to select goods

Ideas:

  • Shopping cart each item has a check box, useelement-ui 的el-checkboxImplementation, the settlement of all ticked goods submitted.
  • Get the check box state (true or false) and the index of the shopping cart items (that is, the index of the array) through the change event.
  • Vuex Actions (updateShoppingCart) to change the checkbox status of shopping cart items.

html:

<div class="pro-check">
  <el-checkbox :value="item.check" @change="checkChange($event,index)"></el-checkbox>
</div>
Copy the code

The logical code is as follows:

checkChange(val, key) {
  // Update the status of whether shopping cart items are checked in vuex
  this.updateShoppingCart({ key: key, prop: "check".val: val });
}
Copy the code

Note: The vuex mutationSvuex and Actions used here are the same as those for modifying the quantity of goods. They are distinguished by different parameters passed. {key: key, prop: “num”, val: val} are the parameters for changing the number of goods. Whether to select {key: key, prop: “check”, val: val} are the parameters for changing the number of goods.

9. Whether to select all products

Ideas:

  • The shopping cart is set up with a full checkbox, bound to isAllCheck via v-Model.
  • The isAllCheck value is getters. GetIsAllCheck in vuex by calculating the getter of the property.
  • Getters. GetIsAllCheck in vuex judges the checked status of each item by traversing the shopping cart array. As long as one item is not checked, getIsAllCheck is false, otherwise it is true.
  • When clicking on the checkAll box, vuex’s Actions (checkAll) are called through the setter of the calculated property to change the checkAll status of each item, thus changing the checkAll status of the checkAll box.

HTML:

<div class="pro-check">
  <el-checkbox v-model="isAllCheck">select all</el-checkbox>
</div>
Copy the code

The logical code is as follows:

computed: { 
  isAllCheck: {
    get() {
      return this.$store.getters.getIsAllCheck;
    },
    set(val) {
      this.checkAll(val); }}}Copy the code

Vuex getters:

getIsAllCheck(state) {
  // Check whether all are selected
  let isAllCheck = true;
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    // Return immediately if one item is not checked false;
    if(! temp.check) { isAllCheck =false;
      returnisAllCheck; }}return isAllCheck;
}
Copy the code

Vuex mutations:

checkAll(state, data) {
  // Click the all button to change the check status of each item
  for (let i = 0; i < state.shoppingCart.length; i++) { state.shoppingCart[i].check = data; }}Copy the code

The actions of vuex

checkAll({ commit }, data) {
  commit('checkAll', data);
}
Copy the code

10. Count the total number of items in your cart

Used in the shopping cart page and the top navigation bar of the root component.

Vuex getters:

getNum(state) {
  // Total number of items in cart
  let totalNum = 0;
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    totalNum += temp.num;
  }
  return totalNum;
}
Copy the code

11. Count the total number of items checked in your shopping cart

Used on the shopping cart page and billing page.

Vuex getters:

getCheckNum(state) {
  // Get the total number of items checked in the shopping cart
  let totalNum = 0;
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    if(temp.check) { totalNum += temp.num; }}return totalNum;
}
Copy the code

12. Calculate the total price of items checked in the shopping cart

Used on the shopping cart page and billing page.

Vuex getters:

getTotalPrice(state) {
  // Total price of items checked by shopping cart
  let totalPrice = 0;
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    if(temp.check) { totalPrice += temp.price * temp.num; }}return totalPrice;
}
Copy the code

13. Generate the details of items checked in the shopping cart

Used on the settlement page.

Vuex getters:

getCheckGoods(state) {
  // Get the checked item information
  // To confirm the order page
  let checkGoods = [];
  for (let i = 0; i < state.shoppingCart.length; i++) {
    const temp = state.shoppingCart[i];
    if(temp.check) { checkGoods.push(temp); }}return checkGoods;
}
Copy the code

conclusion

At this point, the front end of the shopping cart is fully implemented: Synchronous shopping cart data from a database, according to the shopping cart data dynamically generated a shopping cart page, add items to shopping cart, remove the items in the cart, modify the number of shopping cart of goods, whether to check the shopping cart of goods, whether all shopping cart items, calculate the total amount of goods in the shopping cart, and calculate the total number of items in the shopping cart checked, Calculate the total price of the items checked in the shopping cart and generate the details of the items checked in the shopping cart.

Afterword.

The end, the first post of the new person, if there is something wrong, please advise more ^_^

This article is based on the complete project, the implementation of the shopping cart module is summarized.

Complete project repository: github.com/hai-27/vue-… .

Project preview link: http://106.15.179.105 (not compatible with mobile terminals, please use PC access).

If you like this article, please give it a “like”, if you can add a Star to the complete project repository, thank you ^_^

There will be more summaries of this project, and those who are interested can click on it.

Thanks for reading!

The author hai – 27

8 March 2020