Build a simple shopping platform from scratch (16) Front-end mall part

From scratch, build a simple shopping platform (15) Front-end mall part:
https://blog.csdn.net/time_____/article/details/108680599
Project source code (continuous update): https://gitee.com/ DieHunter/myCode/tree/master/shopping

In the previous articles, we implemented the homepage, category list, public components, and tools. This article will introduce the realization of the product detail page. Here we will refine the product detail page into multiple components and use the component communication method Perform monitoring delivery methods to achieve data delivery and effect logic.
Let’s take a look at the effect first.

This interface we can break down the page into several components, namely Top at the top, product information display, product selection box and add to cart button, and finally a tab switching effect at the bottom

Product option box:

First, perform a simple secondary package on the official Picker and Navbar of mint-ui, and then trigger the picker component in the product option box and the add-in shopping cart button component. When adding to the shopping cart, there is an added animation that requires the animate animation, and Global shopping cart list update

  • shopPicker.vue, package official components, display the list by the maximum number of products
    <template>
      <div class="shopPicker">
        <mt-popup v-model="popupVisible" position="bottom">
          <mt-picker class="pickerItem" :slots="count" :showToolbar="true" @change="onValuesChange">
            <div>{
         
         {pickerTitle}}</div>
          </mt-picker>
        </mt-popup>
      </div>
    </template>
    <script>
    import { Picker, Popup } from "mint-ui";
    import Config from "../../config/config";
    const { EventName } = Config;
    export default {
      name: "shopPicker",
      props: ["ShopMaxCount","pickerTitle"],//最大购买数,picker的标题
      data() {
        return {
          popupVisible: false,//是否显示组件
          count: [{ flex: 1, values: [] }]//组件默认模板
        };
      },
      mounted() {
        this.createShopCount();//初始化组件
        this.$events.onEvent(EventName.ShowPicker, this.showPicker);//监听显示picker事件
      },
      destroyed() {
        this.$events.offEvent(EventName.ShowPicker);//注销显示picker事件
      },
      methods: {
        onValuesChange(comp, count) {//数据变化时触发counter中的显示商品数量
          this.$events.emitEvent(EventName.ChangeCount, count[0]);
        },
        showPicker() {
          this.popupVisible = true;
        },
        createShopCount() {//根据传进来的最大数量显示商品数量列表
          this.count[0].values = this.ShopMaxCount;
          for (let i = 0; i < this.ShopMaxCount; i++) {
            this.count[0].values.push(i + 1);
          }
        }
      }
    };
    </script>
    
    <style lang="less" scoped>
    @import "../../style/init.less";
    
    </style>
  •  Modify the navbar style and apply it to your own components
    <template>
      <div class="info">
        <mt-navbar v-model="selected">
          <mt-tab-item v-for="(item,index) in navTitle" :key="index" :id="item.val">{
         
         {item.name}}</mt-tab-item>
        </mt-navbar>
        <mt-tab-container v-model="selected">
          <mt-tab-container-item class="doc" id="0">
            <div>名称:{
         
         {shopName}}</div>
            <div>类型:{
         
         {Type[shopType].name}}</div>
            <div>数量:{
         
         {shopNum}}个</div>
            <div>¥{
         
         {shopPrice}}元</div>
          </mt-tab-container-item>
          <mt-tab-container-item class="doc" id="1">
            <div>净含量/克(g):{
         
         {shopScale}}</div>
            <div>口味:{
         
         {taste}}</div>
            <div>产地:{
         
         {address}}</div>
            <div>保质期:{
         
         {expiryDate}}</div>
            <div>上架时间:{
         
         {time}}</div>
          </mt-tab-container-item>
          <mt-tab-container-item id="2">
            <h3>7天包退</h3>
            <h3>15天包换</h3>
            <h3>一年保修</h3>
          </mt-tab-container-item>
        </mt-tab-container>
      </div>
    </template>
    
    <script>
    import { Navbar, TabItem } from "mint-ui";
    import NavConfig from "../../config/navConfig";
    import ShopType from "../../config/shopType";
    
    export default {
      name: "infoNav",
      data() {
        return {
          selected: "0",//默认选中第一项
          navTitle: NavConfig.NavTitle,
          Type: ShopType.shopType,
          ...this.$route.query//路由传参,将商品信息传递到data中
        };
      }
    };
    </script>
    
    <style lang="less" scoped>
    @import "../../style/init.less";
    @fontcolor: #bababa;
    .info {
      .mg(20px auto);
      .navBar();
      h3 {
        text-align: center;
        color: @mainColor;
      }
      .doc div {
        text-align: center;
        padding: 0.625rem 0;
      }
    }
    </style>

     

  •  One of the difficulties here is to add the animation of the shopping cart. I thought of many methods.
    Finally, I used one label to hide and the other label to perform animation to make the animation effect better.
    The showAnimate variable is used to control the label v-show that executes the animation.

    Use the zoomOutUp effect in animate.css in the animation tag

    <transition enter-active-class="animated zoomOutUp slow">
            <span v-show="showAnimate" class="icon-jiarugouwuche iconfont addIcon"></span>
    </transition>

     Event is triggered when click to add to cart

    addShopCar() {
          this.showAnimate = true;//显示元素
          setTimeout(() => {//延时的目的是等待动画完成
            this.shopCar.countShopItem({//缓存添加购物车数据
              ...this.$route.query,
              shopCount: this.shopCount
            });
            this.showAnimate = false;//隐藏元素
          }, 1000);
        }

    Complete counter component

    <template>
      <ul class="counter">
        <li @click="showPicker">
          数量
          <span>{
         
         {shopCount}}</span>
        </li>
        <li @click="addShopCar">
          加入购物车
          <span class="icon-jiarugouwuche iconfont"></span>
          <transition enter-active-class="animated zoomOutUp slow">
            <span v-show="showAnimate" class="icon-jiarugouwuche iconfont addIcon"></span>
          </transition>
        </li>
      </ul>
    </template>
    
    <script>
    import Config from "../../config/config";
    const { EventName } = Config;
    export default {
      name: "Counter",
      data() {
        return {
          shopCount: 1,//默认购买商品数量
          showAnimate: false//动画标签隐藏
        };
      },
      created() {
        this.$events.onEvent(EventName.ChangeCount, _count => {//添加事件监听,监听商品数量变化
          this.shopCount = _count;
        });
        this.shopCar = new this.$store.ShopCar();
      },
      destroyed() {
        this.$events.offEvent(EventName.ChangeCount);
      },
      methods: {
        showPicker() {
          this.$events.emitEvent(EventName.ShowPicker);
        },
        addShopCar() {
          this.showAnimate = true;//显示元素
          setTimeout(() => {//延时的目的是等待动画完成
            this.shopCar.countShopItem({//缓存添加购物车数据
              ...this.$route.query,
              shopCount: this.shopCount
            });
            this.showAnimate = false;//隐藏元素
          }, 1000);
        }
      }
    };
    </script>
    <style lang="less" scoped>
    @import "../../style/init.less";
    .counter {
      .h(120);
      .w(850);
      background: @mainColor;
      border-radius: 4rem;
      margin: 0 auto;
      .l_h(120);
      li {
        width: 49%;
        display: inline-block;
        .h(46);
        .l_h(46);
        .titleFont();
        .f_s(32);
        text-align: center;
      }
      li:nth-child(2) {
        margin-left: -2px;
        border-left: 1px dashed #dacda3;
        .addIcon {
          position: fixed;
          .f_s(75);
          z-index: -1;
          color: black;
        }
      }
    }
    </style>

    Finally , add a shopping cart variable processing method in the global store

     countShopItem(_data) {
        if (!_data._id) {//阻塞商品id为空现象
          return
        }
        let _shopCar = this.state//获取原购物车列表
        let list = _shopCar.filter(function (item) {
          return item._id === _data._id;//通过id查找购物车中传递项
        });
        if (list.length == 0) {//未找到时新建购物车商品
          _data.sum = _data.shopCount * _data.shopPrice;//商品总价
          _data.isSelect = false//是否选中商品,购物车界面默认值
          _shopCar.push(_data);
        } else if ((_data.shopNum > list[0].shopCount + _data.shopCount) && (list[0].shopCount + _data.shopCount <= 9) && list[0].shopCount + _data.shopCount > 0) {//找到时更新商品
          list[0].shopCount += _data.shopCount;
          list[0].sum = list[0].shopCount * list[0].shopPrice;
        } else if (list[0].shopCount + _data.shopCount <= 0) {//购物车允许最小值
          this.$events.emitEvent(EventName.CountShop, 'min');
          return;
        } else {//购物车允许最大值
          this.$events.emitEvent(EventName.CountShop, 'max');
          return;
        }
        this.state = _shopCar
        this.$events.emitEvent(EventName.CountShop);
      }

    In this way, a simple product detail page is complete

The next article will introduce the implementation of other functions of the shopping cart, including deleting items, selecting all, adding order interfaces, etc.

Guess you like

Origin blog.csdn.net/time_____/article/details/108769229