Răsfoiți Sursa

页面设计: 商品组

萤火科技 1 an în urmă
părinte
comite
4a12f05eb8
2 a modificat fișierele cu 293 adăugiri și 162 ștergeri
  1. 278 158
      components/page/diyComponents/goods/index.vue
  2. 15 4
      utils/utils.scss

+ 278 - 158
components/page/diyComponents/goods/index.vue

@@ -1,92 +1,129 @@
 <template>
   <!-- 商品组 -->
-  <view class="diy-goods" :style="{ background: itemStyle.background }">
-    <view class="goods-list" :class="[`display__${itemStyle.display}`, `column__${itemStyle.column}`]">
-      <scroll-view :scroll-x="itemStyle.display === 'slide'">
-        <view class="goods-item" v-for="(dataItem, index) in dataList" :key="index" @click="onTargetGoods(dataItem.goods_id)">
-
+  <scroll-view class="scroll-view" :scroll-x="itemStyle.display === 'slide'" :style="{ background: itemStyle.background }">
+    <view class="diy-goods">
+      <view class="goods-list" :class="[`display-${itemStyle.display}`, `column-${itemStyle.column}`]"
+        :style="{ padding: `${itemStyle.paddingY * 2}rpx ${itemStyle.paddingX * 2}rpx` }">
+        <view class="goods-item" v-for="(dataItm, index) in dataList" :key="index" :class="[`display-${itemStyle.cardType}`]"
+          :style="{ marginBottom: `${itemStyle.itemMargin * 2}rpx`, borderRadius: `${itemStyle.borderRadius * 2}rpx` }"
+          @click="handleGoodsItem(dataItm.goods_id)">
           <!-- 单列商品 -->
-          <block v-if="itemStyle.column === 1">
-            <view class="dis-flex">
-              <!-- 商品图片 -->
+          <template v-if="itemStyle.column === 1">
+            <view class="flex">
               <view class="goods-item-left">
-                <image class="image" :src="dataItem.goods_image"></image>
+                <image class="image" :src="dataItm.goods_image"></image>
               </view>
               <view class="goods-item-right">
-                <!-- 商品名称 -->
-                <view v-if="itemStyle.show.includes('goodsName')" class="goods-name">
-                  <text class="twoline-hide">{{ dataItem.goods_name }}</text>
-                </view>
-                <view class="goods-item-desc">
-                  <!-- 商品卖点 -->
-                  <view v-if="itemStyle.show.includes('sellingPoint')" class="desc-selling-point dis-flex">
-                    <text class="oneline-hide">{{ dataItem.selling_point }}</text>
+                <view class="goods-info">
+                  <view v-if="inArray('goodsName', itemStyle.show)" class="goods-name twoline-hide">{{ dataItm.goods_name }}</view>
+                  <view v-if="inArray('sellingPoint', itemStyle.show)" class="goods-selling">
+                    <text class="selling oneline-hide" :style="{ color: itemStyle.sellingColor }">{{ dataItm.selling_point }}</text>
                   </view>
-                  <!-- 商品销量 -->
-                  <view v-if="itemStyle.show.includes('goodsSales')" class="desc-goods-sales dis-flex">
-                    <text>已售{{ dataItem.goods_sales }}件</text>
+                  <view v-if="inArray('goodsSales', itemStyle.show)" class="goods-sales oneline-hide">
+                    <text class="sales">已售{{ dataItm.goods_sales }}</text>
+                    <!-- <text class="line">|</text>
+                                      <text>惊艳度100%</text>-->
                   </view>
-                  <!-- 商品价格 -->
-                  <view class="desc-footer">
-                    <text v-if="itemStyle.show.includes('goodsPrice')" class="price-x">¥{{ dataItem.goods_price_min }}</text>
-                    <text class="price-y col-9"
-                      v-if="itemStyle.show.includes('linePrice') && dataItem.line_price_min > 0">¥{{ dataItem.line_price_min }}</text>
+                  <view class="footer">
+                    <view class="goods-price oneline-hide" :style="{ color: itemStyle.priceColor }">
+                      <template v-if="inArray('goodsPrice', itemStyle.show)">
+                        <text class="unit">¥</text>
+                        <text class="value">{{ dataItm.goods_price_min }}</text>
+                        <!-- <text class="unit2">到手价</text> -->
+                      </template>
+                      <text v-if="inArray('linePrice', itemStyle.show)" class="line-price">
+                        <text class="unit">¥</text>
+                        <text class="value">{{ dataItm.line_price_min }}</text>
+                      </text>
+                    </view>
+                    <view v-show="inArray('cartBtn', itemStyle.show) && itemStyle.column < 3" class="action">
+                      <view class="btn-cart" :style="{ background: itemStyle.btnCartColor, color: itemStyle.btnFontColor }"
+                        @click.stop="handleAddCart(dataItm)">
+                        <text class="cart-icon iconfont icon-plus"></text>
+                      </view>
+                    </view>
                   </view>
                 </view>
               </view>
             </view>
-          </block>
-          <!-- 多列商品 -->
-          <block v-else>
-            <!-- 商品图片 -->
+          </template>
+          <!-- 两列/三列 -->
+          <template v-else>
             <view class="goods-image">
-              <image class="image" mode="aspectFill" :src="dataItem.goods_image"></image>
+              <image class="image" mode="aspectFill" :src="dataItm.goods_image"></image>
             </view>
-            <view class="detail">
-              <!-- 商品标题 -->
-              <view v-if="itemStyle.show.includes('goodsName')" class="goods-name twoline-hide">
-                <text class="twoline-hide">{{ dataItem.goods_name }}</text>
+            <view class="goods-info">
+              <view v-if="inArray('goodsName', itemStyle.show)" class="goods-name twoline-hide">{{ dataItm.goods_name }}</view>
+              <view v-if="inArray('sellingPoint', itemStyle.show)" class="goods-selling">
+                <text class="selling oneline-hide" :style="{ color: itemStyle.sellingColor }">{{ dataItm.selling_point }}</text>
               </view>
-              <!-- 商品价格 -->
-              <view class="detail-price oneline-hide">
-                <text v-if="itemStyle.show.includes('goodsPrice')" class="goods-price f-30 col-m">¥{{ dataItem.goods_price_min }}</text>
-                <text v-if="itemStyle.show.includes('linePrice') && dataItem.line_price_min > 0"
-                  class="line-price col-9 f-24">¥{{ dataItem.line_price_min }}</text>
+              <view v-if="inArray('goodsSales', itemStyle.show)" class="goods-sales oneline-hide">
+                <text class="sales">已售{{ dataItm.goods_sales }}</text>
+                <!-- <text class="line">|</text>
+                            <text>惊艳度100%</text>-->
+              </view>
+              <view class="footer">
+                <view v-if="inArray('goodsPrice', itemStyle.show)" class="goods-price oneline-hide"
+                  :style="{ color: itemStyle.priceColor }">
+                  <text class="unit">¥</text>
+                  <text class="value">{{ dataItm.goods_price_min }}</text>
+                  <!-- <text class="unit2">到手价</text> -->
+                  <text v-if="inArray('linePrice', itemStyle.show)" class="line-price">
+                    <text class="unit">¥</text>
+                    <text class="value">{{ dataItm.line_price_min }}</text>
+                  </text>
+                </view>
+                <view v-show="inArray('cartBtn', itemStyle.show) && itemStyle.column < 3" class="action">
+                  <view class="btn-cart" :style="{ background: itemStyle.btnCartColor, color: itemStyle.btnFontColor }"
+                    @click.stop="handleAddCart(dataItm)">
+                    <text class="cart-icon iconfont icon-plus"></text>
+                  </view>
+                </view>
               </view>
             </view>
-          </block>
-
+          </template>
         </view>
-      </scroll-view>
+      </view>
     </view>
-  </view>
+    <!-- 加入购物车组件 -->
+    <AddCartPopup ref="AddCartPopup" @addCart="onAddCart" />
+  </scroll-view>
 </template>
 
 <script>
+  import { inArray } from '@/utils/util'
+  import { setCartTabBadge } from '@/core/app'
+  import AddCartPopup from '@/components/add-cart-popup'
+
   export default {
-    name: "Goods",
-    /**
-     * 组件的属性列表
-     * 用于组件自定义设置
-     */
+    components: {
+      AddCartPopup
+    },
     props: {
       itemIndex: String,
       itemStyle: Object,
       params: Object,
       dataList: Array
     },
-
-    /**
-     * 组件的方法列表
-     * 更新属性和数据的方法与更新页面数据的方法类似
-     */
+    data() {
+      return { inArray }
+    },
     methods: {
 
-      /**
-       * 跳转商品详情页
-       */
-      onTargetGoods(goodsId) {
+      // 跳转商品详情页
+      handleGoodsItem(goodsId) {
         this.$navTo(`pages/goods/detail`, { goodsId })
+      },
+
+      // 点击加入购物车
+      handleAddCart(item) {
+        console.log('handleAddCart', this.$refs.AddCartPopup)
+        this.$refs.AddCartPopup.handle(item)
+      },
+
+      // 更新购物车角标
+      onAddCart(total) {
+        setCartTabBadge()
       }
 
     }
@@ -96,162 +133,245 @@
 
 <style lang="scss" scoped>
   .diy-goods {
+    // 目的是解决划线价横线位置不对
+    // display: flex;
+    // flex-direction: column;
+    overflow: hidden;
+
     .goods-list {
-      padding: 4rpx;
-      box-sizing: border-box;
+      margin-bottom: -10px;
 
-      .goods-item {
-        box-sizing: border-box;
-        padding: 6rpx;
+      // 横向滑动
+      &.display-slide {
+        display: flex;
+        width: max-content;
 
-        .goods-image {
-          position: relative;
-          width: 100%;
-          height: 0;
-          padding-bottom: 100%;
-          overflow: hidden;
-          background: #fff;
+        .goods-item {
+          flex-shrink: 1;
+          margin-right: 20rpx !important;
 
-          &:after {
-            content: '';
-            display: block;
-            margin-top: 100%;
+          &:last-child {
+            margin-right: 0 !important;
           }
+        }
 
-          .image {
-            position: absolute;
-            width: 100%;
-            height: 100%;
-            top: 0;
-            left: 0;
-            -o-object-fit: cover;
-            object-fit: cover;
+        // 双列
+        &.column-2 {
+          .goods-item {
+            width: 160px;
+          }
+        }
+
+        // 3列
+        &.column-3 {
+          .goods-item {
+            width: 220px;
           }
         }
+      }
+
+      // 列表平铺
+      &.display-list {
+        display: flex;
+        flex-wrap: wrap;
+      }
+
+      // 单列
+      &.column-1 {
+        margin-bottom: 0;
 
-        .detail {
-          padding: 8rpx;
+        .goods-item {
+          margin-bottom: 12rpx;
+          padding: 20rpx;
+          box-sizing: border-box;
           background: #fff;
+          flex-basis: 100%;
+          margin-right: 0;
 
-          .goods-name {
-            min-height: 68rpx;
-            line-height: 1.3;
-            white-space: normal;
-            color: #484848;
-            font-size: 26rpx;
-            margin-bottom: 4rpx;
+          &:last-child {
+            margin-bottom: 0 !important;
           }
 
-          .detail-price {
-            .goods-price {
-              margin-right: 8rpx;
-            }
+          .goods-info {
+            padding: 0;
 
-            .line-price {
-              text-decoration: line-through;
+            .goods-name {
+              font-size: 27rpx;
             }
           }
+
         }
-      }
 
-      &.display__slide {
-        white-space: nowrap;
-        font-size: 0;
+        // 商品图片
+        .goods-item-left {
+          background: #fff;
+          margin-right: 20rpx;
 
-        .goods-item {
-          display: inline-block;
+          .image {
+            display: block;
+            width: 240rpx;
+            height: 240rpx;
+          }
         }
-      }
 
-      &.display__list {
-        .goods-item {
-          float: left;
+        .goods-item-right {
+          position: relative;
+          flex: 1;
+          width: 0; // 解决文字超出无法隐藏
         }
+
       }
 
-      &.column__2 {
+      // 2列
+      &.column-2 {
         .goods-item {
-          width: 50%;
+          flex-basis: 48.6%;
+
+          &:nth-child(2n) {
+            margin-right: 0;
+          }
         }
+
       }
 
-      &.column__3 {
+      // 3列
+      &.column-3 {
         .goods-item {
-          width: 33.33333%;
+          flex-basis: 31.46666%;
+
+          &:nth-child(3n) {
+            margin-right: 0;
+          }
         }
       }
 
-      &.column__1 {
-        .goods-item {
+      // 商品内容
+      .goods-item {
+        flex-shrink: 0;
+        background-color: #fff;
+        flex: 0 1 48.6%;
+        margin-right: 2.8%;
+        border-radius: 16rpx;
+        overflow: hidden;
+        margin-bottom: 20rpx;
+
+        &.display-card {
+          box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.07);
+        }
+
+        .goods-image {
+          position: relative;
           width: 100%;
-          height: 280rpx;
-          margin-bottom: 12rpx;
-          padding: 20rpx;
-          box-sizing: border-box;
-          background: #fff;
-          line-height: 1.6;
+          height: 0;
+          padding-bottom: 100%;
+          overflow: hidden;
 
-          &:last-child {
-            margin-bottom: 0;
+          &:after {
+            content: '';
+            display: block;
+            margin-top: 100%;
           }
-        }
-
-        .goods-item-left {
-          display: flex;
-          width: 40%;
-          background: #fff;
-          align-items: center;
 
           .image {
+            position: absolute;
+            top: 0;
+            left: 0;
             display: block;
-            width: 240rpx;
-            height: 240rpx;
+            width: 100%;
+            height: 100%;
+            object-fit: cover;
           }
         }
 
-        .goods-item-right {
-          position: relative;
-          width: 60%;
+        .goods-info {
+          padding: 20rpx;
 
           .goods-name {
-            margin-top: 20rpx;
-            min-height: 68rpx;
-            line-height: 1.3;
-            white-space: normal;
-            color: #484848;
             font-size: 26rpx;
+            color: #000;
+            margin-bottom: 8rpx;
+            height: 68rpx;
           }
-        }
 
-        .goods-item-desc {
-          margin-top: 8rpx;
-        }
+          .goods-selling {
+            display: flex; // 解决文字超出无法隐藏
+            font-size: 24rpx;
+            margin-bottom: 8rpx;
+          }
 
-        .desc-selling-point {
-          width: 400rpx;
-          font-size: 24rpx;
-          color: #e49a3d;
-        }
+          .goods-sales {
+            font-size: 24rpx;
+            color: #959595;
+            margin-bottom: 8rpx;
+
+            .line {
+              margin: 0 8rpx;
+            }
+          }
 
-        .desc-goods-sales {
-          color: #999;
-          font-size: 24rpx;
         }
 
-        .desc-footer {
-          font-size: 24rpx;
+        .footer {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+
+          .goods-price {
+            position: relative;
+            color: #ff1051;
+
+            .unit {
+              font-size: 20rpx;
+            }
+
+            .value {
+              font-size: 30rpx;
+            }
+
+            .unit2 {
+              margin-left: 4rpx;
+              font-size: 22rpx;
+            }
+
+            .line-price {
+              margin-left: 6rpx;
+              color: #959595;
+
+              .unit {
+                text-decoration: line-through;
+                font-size: 22rpx;
+              }
+
+              .value {
+                text-decoration: line-through;
+                font-size: 22rpx;
+              }
+            }
 
-          .price-x {
-            margin-right: 16rpx;
-            color: $main-bg;
-            font-size: 30rpx;
           }
 
-          .price-y {
-            text-decoration: line-through;
+          .action {
+
+            .btn-cart {
+              width: 44rpx;
+              height: 44rpx;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              background-color: #27c29a;
+              color: #fff;
+              border-radius: 50%;
+
+              .cart-icon {
+                font-size: 20rpx;
+              }
+            }
+
           }
+
         }
+
       }
     }
   }
-</style>
+</style>

+ 15 - 4
utils/utils.scss

@@ -1,6 +1,12 @@
-.container,
-input {
-  font-family: PingFang-Medium, PingFangSC-Regular, Heiti, Heiti SC, DroidSans, DroidSansFallback, 'Microsoft YaHei', sans-serif;
+.container, input {
+  font-family: PingFang-Medium,
+                 PingFangSC-Regular,
+                 Heiti,
+                 Heiti SC,
+                 DroidSans,
+                 DroidSansFallback,
+                 "Microsoft YaHei",
+                 sans-serif;
   -webkit-font-smoothing: antialiased;
 }
 
@@ -20,6 +26,10 @@ input {
   display: block;
 }
 
+.flex {
+  display: flex;
+}
+
 .dis-flex {
   display: flex !important;
   /* flex-wrap: wrap; */
@@ -107,7 +117,7 @@ input {
 
 .clearfix::after {
   clear: both;
-  content: ' ';
+  content: " ";
   display: table;
 }
 
@@ -253,6 +263,7 @@ input {
 }
 
 .oneline-hide {
+  // 需设置一个固定宽度 width
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;