1. 程式人生 > 其它 >.NET經銷商實戰(十五)——購物車介面改造,全選功能實現與完善

.NET經銷商實戰(十五)——購物車介面改造,全選功能實現與完善

一.購物車數量前端資料渲染

1.ShoppingCart.vue程式碼如下:

點選檢視程式碼
<template>
  <div>
    <div class="cart-list">
      <ul>
        <li v-for="type in types" :key="type.typeNo">
          <p>
            <i></i>
            <span>{{ transTypeWhenNull(type.typeName) }}</span>
          </p>
          <template v-for="cart in carts" :key="cart.cartGuid">
            <div v-if="cart.productDto?.typeNo == type.typeNo">
              <i></i>
              <img src="" alt="" />
              <p class="p-name">{{ cart.productDto?.productName }}</p>
              <p class="p-price">&yen;{{}}</p>
              <p class="p-num">
                <span class="sub-num" @click="onSubNum(cart)">-</span>
                <input v-model="cart.productNum" @change="onChangeNum(cart)" />
                <span class="add0num" @click="onAddNum(cart)">+</span>
                <b>塊</b>
              </p>
            </div>
          </template>
        </li>
      </ul>
    </div>
    <div class="total-pad">
      <i></i>
      <span>全選</span>
      <span>
        合計:&yen; <b>{{ totalPrice | price }}</b>
      </span>
      <button>確定下單</button>
    </div>
  </div>
</template>

<script>
import { reactive, toRefs, onMounted } from 'vue'
import { getCarts } from '@/httpRequests/ShoppingCartRequest'
export default {
  // mounted() {
  //   this.$store.comm
  //   this.$store.dispatch('setFootMenuIndexAsync', 2)
  // },
  setup() {
    //資料發生改變時,這個方式不能及時獲取變化後的資料
    //const productNumRef = ref()
    const shoppingCartInfo = reactive({
      carts: [],
      types: [],
      // buyNum: 1,
      totalPrice: 6888,
      onAddNum(cart) {
        cart.productNum++
      },
      onSubNum(cart) {
        if (cart.productNum > 1) {
          cart.productNum--
        }
      },
      onChangeNum(cart) {
        var currNum = event.target.value
        if (!isNaN(currNum) && currNum > 0) {
          cart.productNum = currNum
        } else {
          event.target.value = cart.productNum
        }
      },
      onGetShoppingCarts: async () => {
        var customerNo = localStorage['customerNo']
        var res = await getCarts(customerNo)
        shoppingCartInfo.carts = res.carts
        shoppingCartInfo.types = res.types
        console.log(res)
      },
      transTypeWhenNull: (typeName) => typeName ?? '未分類產品',
    })
    onMounted(() => {
      shoppingCartInfo.onGetShoppingCarts()
    })
    return { ...toRefs(shoppingCartInfo) }
  },
}
</script>

<style lang="scss" scoped>
.cart-list {
  text-align: left;
  ul {
    margin-bottom: 108px;

    li {
      background-color: #fff;
      margin-bottom: 12px;

      > p {
        padding-left: 46px;
        position: relative;
        height: 46px;
        border-bottom: 1px solid #ddd;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 13px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        span {
          display: inline-block;
          border-left: 3px solid crimson;
          height: 28px;
          margin: 9px 0;
          padding-left: 8px;
          line-height: 30px;
        }
      }

      div {
        padding-left: 46px;
        position: relative;
        height: 98px;
        padding: 8px 14px 8px 148px;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 28px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        img {
          width: 68px;
          height: 68px;
          background-color: #ccc;
          position: absolute;
          left: 58px;
          top: 20px;
        }

        p.p-name {
          font-size: 13px;
          margin-top: 10px;
          height: 30px;
        }
        p.p-price {
          font-size: 13px;
          height: 20px;
          color: crimson;
        }
        p.p-num {
          text-align: right;
          padding-right: 20px;

          span {
            display: inline-block;
            width: 18px;
            height: 18px;
            border: 1px solid crimson;
            color: crimson;
            border-radius: 9px;
            text-align: center;
            line-height: 18px;
          }

          input {
            width: 28px;
            border: none 0px;
            outline: none;
            text-align: center;
          }

          b {
            font-weight: normal;
            margin-left: 10px;
            font-size: 13px;
          }
        }
      }
    }
  }
}

.total-pad {
  height: 58px;
  width: 100%;
  background-color: #383838;
  position: fixed;
  left: 0;
  bottom: 40px;

  i {
    display: inline-block;
    border: 1px solid #a9a9a9;
    width: 18px;
    height: 18px;
    line-height: 18px;
    border-radius: 18px;
    background-color: #fff;
    margin-left: 13px;
    margin-top: 20px;
    vertical-align: bottom;
    height: 18px;
    text-align: center;
    font-size: 12px;
    color: #fff;
    font-style: italic;
  }

  i.cart-select {
    background-color: crimson;
    border: 1px solid crimson;
  }

  span {
    color: #fff;
    margin-left: 6px;
    font-size: 13px;

    b {
      font-size: 15px;
    }
  }

  button {
    float: right;
    height: 58px;
    width: 120px;
    border: 0 none;
    background-color: #ddd;
    color: #aaa;
    font-size: 15px;
    font-weight: bold;
  }
}
</style>

2.後端ShoppingCartController控制器中修改GetShoppingCartDtos方法

增加一個返回值TypeSeleted,預設賦值為false,這裡我只是為了偷懶,所有用了dynamic,公司開發中最好不要用dynamic,否則會被人噴死

3.shoppingCart前端全選功能實現

點選檢視程式碼
<template>
  <div>
    <div class="cart-list">
      <ul>
        <li v-for="type in types" :key="type.typeNo">
          <p>
            <i :class="{ 'cart-select': type.typeSelected }">√</i>
            <span>{{ transTypeWhenNull(type.typeName) }}</span>
          </p>
          <template v-for="cart in carts" :key="cart.cartGuid">
            <div v-if="cart.productDto?.typeNo == type.typeNo">
              <i
                :class="{ 'cart-select': cart.cartSelected }"
                @click="onSelectCart(cart)"
                >√</i
              >
              <img src="" alt="" />
              <p class="p-name">{{ cart.productDto?.productName }}</p>
              <p class="p-price">&yen;{{}}</p>
              <p class="p-num">
                <span class="sub-num" @click="onSubNum(cart)">-</span>
                <input v-model="cart.productNum" @change="onChangeNum(cart)" />
                <span class="add0num" @click="onAddNum(cart)">+</span>
                <b>塊</b>
              </p>
            </div>
          </template>
        </li>
      </ul>
    </div>
    <div class="total-pad">
      <i></i>
      <span>全選</span>
      <span>
        合計:&yen; <b>{{ totalPrice | price }}</b>
      </span>
      <button>確定下單</button>
    </div>
  </div>
</template>

<script>
import { reactive, toRefs, onMounted } from 'vue'
import { getCarts } from '@/httpRequests/ShoppingCartRequest'
export default {
  // mounted() {
  //   this.$store.comm
  //   this.$store.dispatch('setFootMenuIndexAsync', 2)
  // },
  setup() {
    //資料發生改變時,這個方式不能及時獲取變化後的資料
    //const productNumRef = ref()
    const shoppingCartInfo = reactive({
      carts: [],
      types: [],
      // buyNum: 1,
      totalPrice: 6888,
      onAddNum(cart) {
        cart.productNum++
      },
      onSubNum(cart) {
        if (cart.productNum > 1) {
          cart.productNum--
        }
      },
      onChangeNum(cart) {
        var currNum = event.target.value
        if (!isNaN(currNum) && currNum > 0) {
          cart.productNum = currNum
        } else {
          event.target.value = cart.productNum
        }
      },
      onGetShoppingCarts: async () => {
        var customerNo = localStorage['customerNo']
        var res = await getCarts(customerNo)
        shoppingCartInfo.carts = res.carts
        shoppingCartInfo.types = res.types
        // console.log(res)
      },
      onSelectCart: (cart) => {
        cart.cartSelected = !cart.cartSelected
        //找到型別中對應設定物品的型別
        var type = shoppingCartInfo.types.filter(
          (m) => m.typeNo == cart.productDto?.typeNo
        )[0]
        var cartsOfType = shoppingCartInfo.carts.filter(
          (s) => s.productDto?.typeNo == type?.typeNo
        )
        if (cartsOfType.every((m) => m.cartSelected)) {
          type.typeSelected = true
        } else {
          type.typeSelected = false
        }
      },
      transTypeWhenNull: (typeName) => typeName ?? '未分類產品',
    })
    onMounted(() => {
      shoppingCartInfo.onGetShoppingCarts()
    })
    return { ...toRefs(shoppingCartInfo) }
  },
}
</script>

<style lang="scss" scoped>
.cart-list {
  text-align: left;
  ul {
    margin-bottom: 108px;

    li {
      background-color: #fff;
      margin-bottom: 12px;

      > p {
        padding-left: 46px;
        position: relative;
        height: 46px;
        border-bottom: 1px solid #ddd;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 13px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        span {
          display: inline-block;
          border-left: 3px solid crimson;
          height: 28px;
          margin: 9px 0;
          padding-left: 8px;
          line-height: 30px;
        }
      }

      div {
        padding-left: 46px;
        position: relative;
        height: 98px;
        padding: 8px 14px 8px 148px;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 28px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        img {
          width: 68px;
          height: 68px;
          background-color: #ccc;
          position: absolute;
          left: 58px;
          top: 20px;
        }

        p.p-name {
          font-size: 13px;
          margin-top: 10px;
          height: 30px;
        }
        p.p-price {
          font-size: 13px;
          height: 20px;
          color: crimson;
        }
        p.p-num {
          text-align: right;
          padding-right: 20px;

          span {
            display: inline-block;
            width: 18px;
            height: 18px;
            border: 1px solid crimson;
            color: crimson;
            border-radius: 9px;
            text-align: center;
            line-height: 18px;
          }

          input {
            width: 28px;
            border: none 0px;
            outline: none;
            text-align: center;
          }

          b {
            font-weight: normal;
            margin-left: 10px;
            font-size: 13px;
          }
        }
      }
    }
  }
}

.total-pad {
  height: 58px;
  width: 100%;
  background-color: #383838;
  position: fixed;
  left: 0;
  bottom: 40px;

  i {
    display: inline-block;
    border: 1px solid #a9a9a9;
    width: 18px;
    height: 18px;
    line-height: 18px;
    border-radius: 18px;
    background-color: #fff;
    margin-left: 13px;
    margin-top: 20px;
    vertical-align: bottom;
    height: 18px;
    text-align: center;
    font-size: 12px;
    color: #fff;
    font-style: italic;
  }

  i.cart-select {
    background-color: crimson;
    border: 1px solid crimson;
  }

  span {
    color: #fff;
    margin-left: 6px;
    font-size: 13px;

    b {
      font-size: 15px;
    }
  }

  button {
    float: right;
    height: 58px;
    width: 120px;
    border: 0 none;
    background-color: #ddd;
    color: #aaa;
    font-size: 15px;
    font-weight: bold;
  }
}
</style>

4.全選功能完善

購物車介面

點選檢視程式碼
<template>
  <div>
    <div class="cart-list">
      <ul>
        <li v-for="type in types" :key="type.typeNo">
          <p>
            <i
              :class="{ 'cart-select': type.typeSelected }"
              @click="onSelectType(type)"
              >√</i
            >
            <span>{{ transTypeWhenNull(type.typeName) }}</span>
          </p>
          <template v-for="cart in carts" :key="cart.cartGuid">
            <div v-if="cart.productDto?.typeNo == type.typeNo">
              <i
                :class="{ 'cart-select': cart.cartSelected }"
                @click="onSelectCart(cart)"
                >√</i
              >
              <img src="" alt="" />
              <p class="p-name">{{ cart.productDto?.productName }}</p>
              <p class="p-price">&yen;{{}}</p>
              <p class="p-num">
                <span class="sub-num" @click="onSubNum(cart)">-</span>
                <input v-model="cart.productNum" @change="onChangeNum(cart)" />
                <span class="add0num" @click="onAddNum(cart)">+</span>
                <b>塊</b>
              </p>
            </div>
          </template>
        </li>
      </ul>
    </div>
    <div class="total-pad">
      <i :class="{ 'cart-select': isAllSelected }">√</i>
      <span>全選</span>
      <span>
        合計:&yen; <b>{{ totalPrice | price }}</b>
      </span>
      <button>確定下單</button>
    </div>
  </div>
</template>

<script>
import { reactive, toRefs, onMounted } from 'vue'
import { getCarts } from '@/httpRequests/ShoppingCartRequest'
export default {
  // mounted() {
  //   this.$store.comm
  //   this.$store.dispatch('setFootMenuIndexAsync', 2)
  // },
  setup() {
    //資料發生改變時,這個方式不能及時獲取變化後的資料
    //const productNumRef = ref()
    const shoppingCartInfo = reactive({
      carts: [],
      types: [],
      isAllSelected: true,
      // buyNum: 1,
      totalPrice: 6888,
      onAddNum(cart) {
        cart.productNum++
      },
      onSubNum(cart) {
        if (cart.productNum > 1) {
          cart.productNum--
        }
      },
      onChangeNum(cart) {
        var currNum = event.target.value
        if (!isNaN(currNum) && currNum > 0) {
          cart.productNum = currNum
        } else {
          event.target.value = cart.productNum
        }
      },
      /**
       * 獲取購物車資訊
       */
      onGetShoppingCarts: async () => {
        var customerNo = localStorage['customerNo']
        var res = await getCarts(customerNo)
        shoppingCartInfo.carts = res.carts
        shoppingCartInfo.types = res.types
        // console.log(res)
      },
      /**
       * 點選選擇購物車時觸發
       */
      onSelectCart: (cart) => {
        cart.cartSelected = !cart.cartSelected
        //找到型別中對應設定物品的型別
        // var type = shoppingCartInfo.types.filter(
        //   (m) => m.typeNo == cart.productDto?.typeNo
        // )[0]
        // var cartsOfType = shoppingCartInfo.carts.filter(
        //   (s) => s.productDto?.typeNo == type?.typeNo
        // )
        shoppingCartInfo.checkTypeSelected()
      },
      /**
       * 選擇型別時觸發
       */
      onSelectType: (type) => {
        type.typeSelected = !type.typeSelected
        shoppingCartInfo.carts
          .filter((s) => s.productDto?.typeNo == type?.typeNo)
          .forEach((s) => {
            s.cartSelected = type.typeSelected
          })
        shoppingCartInfo.checkAllSelected()
      },
      checkTypeSelected: () => {
        shoppingCartInfo.types.forEach((type) => {
          var cartsOfType = shoppingCartInfo.carts.filter(
            (s) => s.productDto?.typeNo == type?.typeNo
          )
          //檢視當前型別下的物品是否都被選擇,是則將屬於型別選中
          //否則不選中
          if (cartsOfType.every((m) => m.cartSelected)) {
            type.typeSelected = true
          } else {
            type.typeSelected = false
          }
        })
        shoppingCartInfo.checkAllSelected()
      },
      //全選 合計
      checkAllSelected: () => {
        if (shoppingCartInfo.carts.every((m) => m.cartSelected)) {
          shoppingCartInfo.isAllSelected = true
        } else {
          shoppingCartInfo.isAllSelected = false
        }
      },
      transTypeWhenNull: (typeName) => typeName ?? '未分類產品',
    })
    onMounted(() => {
      shoppingCartInfo.onGetShoppingCarts()
      shoppingCartInfo.checkTypeSelected()
    })
    return { ...toRefs(shoppingCartInfo) }
  },
}
</script>

<style lang="scss" scoped>
.cart-list {
  text-align: left;
  ul {
    margin-bottom: 108px;

    li {
      background-color: #fff;
      margin-bottom: 12px;

      > p {
        padding-left: 46px;
        position: relative;
        height: 46px;
        border-bottom: 1px solid #ddd;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 13px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        span {
          display: inline-block;
          border-left: 3px solid crimson;
          height: 28px;
          margin: 9px 0;
          padding-left: 8px;
          line-height: 30px;
        }
      }

      div {
        padding-left: 46px;
        position: relative;
        height: 98px;
        padding: 8px 14px 8px 148px;

        i {
          border: 1px solid #a9a9a9;
          width: 18px;
          height: 18px;
          line-height: 18px;
          border-radius: 18px;
          position: absolute;
          left: 13px;
          top: 28px;
          text-align: center;
          font-size: 12px;
          color: #fff;
          font-style: normal;
        }

        i.cart-select {
          background-color: crimson;
          border: 1px solid crimson;
        }

        img {
          width: 68px;
          height: 68px;
          background-color: #ccc;
          position: absolute;
          left: 58px;
          top: 20px;
        }

        p.p-name {
          font-size: 13px;
          margin-top: 10px;
          height: 30px;
        }
        p.p-price {
          font-size: 13px;
          height: 20px;
          color: crimson;
        }
        p.p-num {
          text-align: right;
          padding-right: 20px;

          span {
            display: inline-block;
            width: 18px;
            height: 18px;
            border: 1px solid crimson;
            color: crimson;
            border-radius: 9px;
            text-align: center;
            line-height: 18px;
          }

          input {
            width: 28px;
            border: none 0px;
            outline: none;
            text-align: center;
          }

          b {
            font-weight: normal;
            margin-left: 10px;
            font-size: 13px;
          }
        }
      }
    }
  }
}

.total-pad {
  height: 58px;
  width: 100%;
  background-color: #383838;
  position: fixed;
  left: 0;
  bottom: 40px;

  i {
    display: inline-block;
    border: 1px solid #a9a9a9;
    width: 18px;
    height: 18px;
    line-height: 18px;
    border-radius: 18px;
    background-color: #fff;
    margin-left: 13px;
    margin-top: 20px;
    vertical-align: bottom;
    height: 18px;
    text-align: center;
    font-size: 12px;
    color: #fff;
    font-style: normal;
  }

  i.cart-select {
    background-color: crimson;
    border: 1px solid crimson;
  }

  span {
    color: #fff;
    margin-left: 6px;
    font-size: 13px;

    b {
      font-size: 15px;
    }
  }

  button {
    float: right;
    height: 58px;
    width: 120px;
    border: 0 none;
    background-color: #ddd;
    color: #aaa;
    font-size: 15px;
    font-weight: bold;
  }
}
</style>