<!-- 装修商品组件:商品卡片 --> <template> <!-- 商品卡片 --> <view> <!-- 布局1. 单列大图(上图,下内容)--> <view v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.goodsList.length" class="goods-sl-box"> <view class="goods-box" v-for="item in state.goodsList" :key="item.id" :style="[{ marginBottom: data.space * 2 + 'rpx' }]" > <s-goods-column class="" size="sl" :goodsFields="data.fields" :tagStyle="data.badge" :data="item" :titleColor="data.fields.name?.color" :subTitleColor="data.fields.introduction.color" :topRadius="data.borderRadiusTop" :bottomRadius="data.borderRadiusBottom" @click="sheep.$router.go('/pages/goods/index', { id: item.id })" > <!-- 购买按钮 --> <template v-slot:cart> <button class="ss-reset-button cart-btn" :style="[buyStyle]"> {{ btnBuy.type === 'text' ? btnBuy.text : '' }} </button> </template> </s-goods-column> </view> </view> <!-- 布局2. 双列(每一列:上图,下内容)--> <view v-if="layoutType === LayoutTypeEnum.TWO_COL && state.goodsList.length" class="goods-md-wrap ss-flex ss-flex-wrap ss-col-top" > <view class="goods-list-box"> <view class="left-list" :style="[{ paddingRight: data.space + 'rpx', marginBottom: data.space + 'px' }]" v-for="item in state.leftGoodsList" :key="item.id" > <s-goods-column class="goods-md-box" size="md" :goodsFields="data.fields" :tagStyle="data.badge" :data="item" :titleColor="data.fields.name?.color" :subTitleColor="data.fields.introduction.color" :topRadius="data.borderRadiusTop" :bottomRadius="data.borderRadiusBottom" :titleWidth="330 - marginLeft - marginRight" @click="sheep.$router.go('/pages/goods/index', { id: item.id })" @getHeight="calculateGoodsColumn($event, 'left')" > <!-- 购买按钮 --> <template v-slot:cart> <button class="ss-reset-button cart-btn" :style="[buyStyle]"> {{ btnBuy.type === 'text' ? btnBuy.text : '' }} </button> </template> </s-goods-column> </view> </view> <view class="goods-list-box"> <view class="right-list" :style="[{ paddingLeft: data.space + 'rpx', marginBottom: data.space + 'px' }]" v-for="item in state.rightGoodsList" :key="item.id" > <s-goods-column class="goods-md-box" size="md" :goodsFields="data.fields" :tagStyle="data.badge" :data="item" :titleColor="data.fields.name?.color" :subTitleColor="data.fields.introduction.color" :topRadius="data.borderRadiusTop" :bottomRadius="data.borderRadiusBottom" :titleWidth="330 - marginLeft - marginRight" @click="sheep.$router.go('/pages/goods/index', { id: item.id })" @getHeight="calculateGoodsColumn($event, 'right')" > <!-- 购买按钮 --> <template v-slot:cart> <button class="ss-reset-button cart-btn" :style="[buyStyle]"> {{ btnBuy.type === 'text' ? btnBuy.text : '' }} </button> </template> </s-goods-column> </view> </view> </view> <!-- 布局3. 单列小图(左图,右内容) --> <view v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.goodsList.length" class="goods-lg-box"> <view class="goods-box" :style="[{ marginBottom: data.space + 'px' }]" v-for="item in state.goodsList" :key="item.id" > <s-goods-column class="goods-card" size="lg" :goodsFields="data.fields" :data="item" :tagStyle="data.badge" :titleColor="data.fields.name?.color" :subTitleColor="data.fields.introduction.color" :topRadius="data.borderRadiusTop" :bottomRadius="data.borderRadiusBottom" @tap="sheep.$router.go('/pages/goods/index', { id: item.id })" > <!-- 购买按钮 --> <template v-slot:cart> <button class="ss-reset-button cart-btn" :style="[buyStyle]"> {{ btnBuy.type === 'text' ? btnBuy.text : '' }} </button> </template> </s-goods-column> </view> </view> </view> </template> <script setup> /** * 商品卡片 */ import { computed, reactive, onMounted } from 'vue'; import sheep from '@/sheep'; import SpuApi from '@/sheep/api/product/spu'; // 布局类型 const LayoutTypeEnum = { // 单列大图 ONE_COL_BIG_IMG: 'oneColBigImg', // 双列 TWO_COL: 'twoCol', // 单列小图 ONE_COL_SMALL_IMG: 'oneColSmallImg', } const state = reactive({ goodsList: [], leftGoodsList: [], rightGoodsList: [], }); const props = defineProps({ data: { type: Object, default() {}, }, styles: { type: Object, default() {}, }, }); const { layoutType, btnBuy, spuIds } = props.data ?? {}; const { marginLeft, marginRight } = props.styles ?? {}; // 购买按钮样式 const buyStyle = computed(() => { if (btnBuy.type === 'text') { // 文字按钮:线性渐变背景颜色 return { background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`, }; } if (btnBuy.type === 'img') { // 图片按钮 return { width: '54rpx', height: '54rpx', background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`, backgroundSize: '100% 100%', }; } }); //region 商品瀑布流布局 // 下一个要处理的商品索引 let count = 0; // 左列的高度 let leftHeight = 0; // 右列的高度 let rightHeight = 0; /** * 计算商品在左列还是右列 * @param height 商品的高度 * @param where 添加到哪一列 */ function calculateGoodsColumn(height = 0, where = 'left') { // 处理完 if (!state.goodsList[count]) return; // 增加列的高度 if (where === 'left') leftHeight += height; if (where === 'right') rightHeight += height; // 添加到矮的一列 if (leftHeight <= rightHeight) { state.leftGoodsList.push(state.goodsList[count]); } else { state.rightGoodsList.push(state.goodsList[count]); } // 计数 count++; } //endregion /** * 根据商品编号列表,获取商品列表 * @param ids 商品编号列表 * @return {Promise<undefined>} 商品列表 */ async function getGoodsListByIds(ids) { const { data } = await SpuApi.getSpuListByIds(ids); return data; } // 初始化 onMounted(async () => { // 加载商品列表 state.goodsList = await getGoodsListByIds(spuIds.join(',')); // 只有双列布局时需要 if (layoutType === LayoutTypeEnum.TWO_COL){ // 分列 calculateGoodsColumn(); } }); </script> <style lang="scss" scoped> .goods-md-wrap { width: 100%; } .goods-list-box { width: 50%; box-sizing: border-box; .left-list { &:nth-last-child(1) { margin-bottom: 0 !important; } } .right-list { &:nth-last-child(1) { margin-bottom: 0 !important; } } } .goods-box { &:nth-last-of-type(1) { margin-bottom: 0 !important; } } .goods-md-box, .goods-sl-box, .goods-lg-box { position: relative; .cart-btn { position: absolute; bottom: 18rpx; right: 20rpx; z-index: 11; height: 50rpx; line-height: 50rpx; padding: 0 20rpx; border-radius: 25rpx; font-size: 24rpx; color: #fff; } } </style>