通过微信开发者工具 商城模板 创建新小程序
This commit is contained in:
264
mini-program/pages/order/components/goods-card/index.js
Normal file
264
mini-program/pages/order/components/goods-card/index.js
Normal file
@@ -0,0 +1,264 @@
|
||||
Component({
|
||||
options: {
|
||||
multipleSlots: true, // 在组件定义时的选项中启用多slot支持
|
||||
addGlobalClass: true,
|
||||
},
|
||||
intersectionObserverContext: null,
|
||||
|
||||
externalClasses: [
|
||||
'card-class',
|
||||
'title-class',
|
||||
'desc-class',
|
||||
'num-class',
|
||||
'thumb-class',
|
||||
'specs-class',
|
||||
'price-class',
|
||||
'origin-price-class',
|
||||
'price-prefix-class',
|
||||
],
|
||||
|
||||
relations: {
|
||||
'../order-card/index': {
|
||||
type: 'ancestor',
|
||||
linked(target) {
|
||||
this.parent = target;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
properties: {
|
||||
hidden: {
|
||||
// 设置为null代表不做类型转换
|
||||
type: null,
|
||||
value: false,
|
||||
observer(hidden) {
|
||||
// null就是代表没有设置,没有设置的话不setData,防止祖先组件触发的setHidden操作被覆盖
|
||||
if (hidden !== null) {
|
||||
this.setHidden(!!hidden);
|
||||
}
|
||||
},
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
// `goods-card-88888888`
|
||||
// 不能在这里写生成逻辑,如果在这里写,那么假设有多个goods-list时,他们将共享这个值
|
||||
value: '',
|
||||
observer: (id) => {
|
||||
this.genIndependentID(id);
|
||||
if (this.properties.thresholds?.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
}
|
||||
},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
observer(goods) {
|
||||
// 有ID的商品才渲染
|
||||
if (!goods) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** 划线价是否有效 */
|
||||
let isValidityLinePrice = true;
|
||||
// 判断一次划线价格是否合理
|
||||
if (
|
||||
goods.originPrice &&
|
||||
goods.price &&
|
||||
goods.originPrice < goods.price
|
||||
) {
|
||||
isValidityLinePrice = false;
|
||||
}
|
||||
|
||||
// 敲定换行数量默认值
|
||||
if (goods.lineClamp === undefined || goods.lineClamp <= 0) {
|
||||
// tag数组长度 大于0 且 可见
|
||||
// 指定换行为1行
|
||||
if ((goods.tags?.length || 0) > 0 && !goods.hideKey?.tags) {
|
||||
goods.lineClamp = 1;
|
||||
} else {
|
||||
goods.lineClamp = 2;
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({ goods, isValidityLinePrice });
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
value: 'horizontal',
|
||||
},
|
||||
thumbMode: {
|
||||
type: String,
|
||||
value: 'aspectFill',
|
||||
},
|
||||
thumbWidth: Number,
|
||||
thumbHeight: Number,
|
||||
priceFill: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
value: '¥',
|
||||
},
|
||||
lazyLoad: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
centered: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showCart: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
pricePrefix: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
cartSize: {
|
||||
type: Number,
|
||||
value: 48,
|
||||
},
|
||||
cartColor: {
|
||||
type: String,
|
||||
value: '#FA550F',
|
||||
},
|
||||
/** 元素可见监控阈值, 数组长度大于0就创建 */
|
||||
thresholds: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer(current) {
|
||||
if (current && current.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
} else {
|
||||
this.clearIntersectionObserverHandle();
|
||||
}
|
||||
},
|
||||
},
|
||||
specsIconClassPrefix: {
|
||||
type: String,
|
||||
value: 'wr',
|
||||
},
|
||||
specsIcon: {
|
||||
type: String,
|
||||
value: 'expand_more',
|
||||
},
|
||||
addCartIconClassPrefix: {
|
||||
type: String,
|
||||
value: 'wr',
|
||||
},
|
||||
addCartIcon: {
|
||||
type: String,
|
||||
value: 'cart',
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
hiddenInData: false,
|
||||
independentID: '',
|
||||
goods: { id: '' },
|
||||
/** 保证划线价格不小于原价,否则不渲染划线价 */
|
||||
isValidityLinePrice: false,
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
ready() {
|
||||
this.init();
|
||||
},
|
||||
detached() {
|
||||
this.clear();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
clickHandle() {
|
||||
this.triggerEvent('click', { goods: this.data.goods });
|
||||
},
|
||||
clickThumbHandle() {
|
||||
this.triggerEvent('thumb', { goods: this.data.goods });
|
||||
},
|
||||
clickTagHandle(evt) {
|
||||
const { index } = evt.currentTarget.dataset;
|
||||
this.triggerEvent('tag', { goods: this.data.goods, index });
|
||||
},
|
||||
// 加入购物车
|
||||
addCartHandle(e) {
|
||||
const { id } = e.currentTarget;
|
||||
const { id: cardID } = e.currentTarget.dataset;
|
||||
this.triggerEvent('add-cart', {
|
||||
...e.detail,
|
||||
id,
|
||||
cardID,
|
||||
goods: this.data.goods,
|
||||
});
|
||||
},
|
||||
genIndependentID(id, cb) {
|
||||
let independentID;
|
||||
if (id) {
|
||||
independentID = id;
|
||||
} else {
|
||||
// `goods-card-88888888`
|
||||
independentID = `goods-card-${~~(Math.random() * 10 ** 8)}`;
|
||||
}
|
||||
this.setData({ independentID }, cb);
|
||||
},
|
||||
|
||||
init() {
|
||||
const { thresholds, id, hidden } = this.properties;
|
||||
if (hidden !== null) {
|
||||
this.setHidden(!!hidden);
|
||||
}
|
||||
|
||||
this.genIndependentID(id || '', () => {
|
||||
if (thresholds && thresholds.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.clearIntersectionObserverHandle();
|
||||
},
|
||||
|
||||
setHidden(hidden) {
|
||||
this.setData({ hiddenInData: !!hidden });
|
||||
},
|
||||
|
||||
createIntersectionObserverHandle() {
|
||||
if (this.intersectionObserverContext || !this.data.independentID) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.intersectionObserverContext = wx
|
||||
.createIntersectionObserver(this, {
|
||||
thresholds: this.properties.thresholds,
|
||||
})
|
||||
.relativeToViewport();
|
||||
|
||||
this.intersectionObserverContext.observe(
|
||||
`#${this.data.independentID}`,
|
||||
(res) => {
|
||||
this.intersectionObserverCB(res);
|
||||
},
|
||||
);
|
||||
},
|
||||
intersectionObserverCB(ob) {
|
||||
this.triggerEvent('ob', {
|
||||
goods: this.data.goods,
|
||||
context: this.intersectionObserverContext,
|
||||
ob,
|
||||
});
|
||||
},
|
||||
clearIntersectionObserverHandle() {
|
||||
if (this.intersectionObserverContext) {
|
||||
try {
|
||||
this.intersectionObserverContext.disconnect();
|
||||
} catch (e) {}
|
||||
|
||||
this.intersectionObserverContext = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"price": "/components/price/index",
|
||||
"t-image": "/components/webp-image/index",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon"
|
||||
}
|
||||
}
|
77
mini-program/pages/order/components/goods-card/index.wxml
Normal file
77
mini-program/pages/order/components/goods-card/index.wxml
Normal file
@@ -0,0 +1,77 @@
|
||||
<view
|
||||
id="{{independentID}}"
|
||||
class="wr-goods-card card-class {{ layout }} {{ centered ? 'center' : ''}}"
|
||||
bind:tap="clickHandle"
|
||||
data-goods="{{ goods }}"
|
||||
hidden="{{hiddenInData}}"
|
||||
>
|
||||
<view class="wr-goods-card__main">
|
||||
<view class="wr-goods-card__thumb thumb-class" bind:tap="clickThumbHandle">
|
||||
<!-- data-src 是方便加购动画读取图片用的 -->
|
||||
<t-image
|
||||
t-class="wr-goods-card__thumb-com"
|
||||
wx:if="{{ !!goods.thumb && !goods.hideKey.thumb }}"
|
||||
src="{{ goods.thumb }}"
|
||||
mode="{{ thumbMode }}"
|
||||
lazy-load="{{ lazyLoad }}"
|
||||
/>
|
||||
<slot name="thumb-cover" />
|
||||
</view>
|
||||
|
||||
<view class="wr-goods-card__body">
|
||||
<view class="wr-goods-card__long_content">
|
||||
<view wx:if="{{ goods.title && !goods.hideKey.title }}" class="wr-goods-card__title title-class" style="-webkit-line-clamp: {{ goods.lineClamp }};">
|
||||
<slot name="before-title" />
|
||||
{{ goods.title }}
|
||||
</view>
|
||||
<slot name="after-title" />
|
||||
<view wx:if="{{ goods.desc && !goods.hideKey.desc }}" class="wr-goods-card__desc desc-class">{{ goods.desc }}</view>
|
||||
<slot name="after-desc" />
|
||||
<view wx:if="{{ goods.specs && goods.specs.length > 0 && !goods.hideKey.specs }}" class="wr-goods-card__specs__desc specs-class" bind:tap="clickSpecsHandle">
|
||||
<view class="wr-goods-card__specs__desc-text">{{ goods.specs }}</view>
|
||||
</view>
|
||||
<view class="goods_tips" wx:if="{{goods.stockQuantity !== 0 && goods.quantity >= goods.stockQuantity}}">库存不足</view>
|
||||
</view>
|
||||
|
||||
<view class="wr-goods-card__short_content">
|
||||
<block wx:if="{{goods.stockQuantity !== 0}}">
|
||||
<view wx:if="{{ pricePrefix }}" class="wr-goods-card__price__prefix price-prefix-class">{{ pricePrefix }}</view>
|
||||
<slot name="price-prefix" />
|
||||
<view wx:if="{{ goods.price && !goods.hideKey.price }}" class="wr-goods-card__price">
|
||||
<price
|
||||
wr-class="price-class"
|
||||
symbol="{{currency}}"
|
||||
price="{{goods.price}}"
|
||||
fill="{{priceFill}}"
|
||||
decimalSmaller
|
||||
/>
|
||||
</view>
|
||||
<view wx:if="{{ goods.originPrice && !goods.hideKey.originPrice && isValidityLinePrice }}" class="wr-goods-card__origin-price">
|
||||
<price
|
||||
wr-class="origin-price-class"
|
||||
symbol="{{currency}}"
|
||||
price="{{goods.originPrice}}"
|
||||
fill="{{priceFill}}"
|
||||
/>
|
||||
</view>
|
||||
<slot name="origin-price" />
|
||||
<view wx:if="{{goods.num && !goods.hideKey.num}}" class="wr-goods-card__num num-class">
|
||||
<text class="wr-goods-card__num__prefix">x </text>
|
||||
{{ goods.num }}
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="no_storage">
|
||||
<view>请重新选择商品规格</view>
|
||||
<view class="no_storage__right">重选</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
<slot name="append-body" />
|
||||
</view>
|
||||
<slot name="footer" />
|
||||
</view>
|
||||
<slot name="append-card" />
|
||||
</view>
|
||||
|
254
mini-program/pages/order/components/goods-card/index.wxss
Normal file
254
mini-program/pages/order/components/goods-card/index.wxss
Normal file
@@ -0,0 +1,254 @@
|
||||
.wr-goods-card {
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.wr-goods-card__main {
|
||||
position: relative;
|
||||
display: flex;
|
||||
line-height: 1;
|
||||
flex-direction: row;
|
||||
background: transparent;
|
||||
padding: 16rpx 0rpx;
|
||||
}
|
||||
.wr-goods-card.center .wr-goods-card__main {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.wr-goods-card__thumb {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
}
|
||||
.wr-goods-card__thumb-com {
|
||||
width: 176rpx;
|
||||
height: 176rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wr-goods-card__thumb:empty {
|
||||
display: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wr-goods-card__body {
|
||||
display: flex;
|
||||
margin: 0 0 0 16rpx;
|
||||
flex-direction: row;
|
||||
flex: 1 1 auto;
|
||||
min-height: 176rpx;
|
||||
}
|
||||
.wr-goods-card__long_content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.wr-goods-card__long_content .goods_tips {
|
||||
width: 100%;
|
||||
margin-top: 16rpx;
|
||||
text-align: right;
|
||||
color: #fa4126;
|
||||
font-size: 24rpx;
|
||||
line-height: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.wr-goods-card__title {
|
||||
flex-shrink: 0;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
font-weight: 400;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
.wr-goods-card__title__prefix-tags {
|
||||
display: inline-flex;
|
||||
}
|
||||
.wr-goods-card__title__prefix-tags .prefix-tag {
|
||||
margin: 0 8rpx 0 0;
|
||||
}
|
||||
.wr-goods-card__desc {
|
||||
font-size: 24rpx;
|
||||
color: #f5f5f5;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wr-goods-card__specs__desc,
|
||||
.wr-goods-card__specs__text {
|
||||
font-size: 24rpx;
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
color: #999999;
|
||||
margin: 8rpx 0;
|
||||
}
|
||||
.wr-goods-card__specs__desc {
|
||||
display: flex;
|
||||
align-self: flex-start;
|
||||
flex-direction: row;
|
||||
}
|
||||
.wr-goods-card__specs__desc-text {
|
||||
height: 100%;
|
||||
max-width: 380rpx;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
.wr-goods-card__specs__desc-icon {
|
||||
line-height: inherit;
|
||||
margin-left: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
.wr-goods-card__specs__text {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
}
|
||||
.wr-goods-card__tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 16rpx 0 0 0;
|
||||
}
|
||||
.wr-goods-card__tag {
|
||||
color: #fa550f;
|
||||
background: transparent;
|
||||
font-size: 20rpx;
|
||||
border: 1rpx solid #fa550f;
|
||||
padding: 0 8rpx;
|
||||
height: 30rpx;
|
||||
line-height: 30rpx;
|
||||
margin: 0 8rpx 8rpx 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.wr-goods-card__short_content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
margin: 0 0 0 46rpx;
|
||||
}
|
||||
.wr-goods-card__price__prefix {
|
||||
order: 0;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
.wr-goods-card__price {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
order: 1;
|
||||
color: #fa4126;
|
||||
font-size: 36rpx;
|
||||
margin: 0;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
.wr-goods-card__origin-price {
|
||||
white-space: nowrap;
|
||||
font-weight: normal;
|
||||
order: 2;
|
||||
color: #aaaaaa;
|
||||
font-size: 24rpx;
|
||||
margin: 0;
|
||||
}
|
||||
.wr-goods-card__num {
|
||||
white-space: nowrap;
|
||||
order: 4;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin: 20rpx 0 0 auto;
|
||||
}
|
||||
.wr-goods-card__num__prefix {
|
||||
color: inherit;
|
||||
}
|
||||
.wr-goods-card__add-cart {
|
||||
order: 3;
|
||||
margin: auto 0 0 auto;
|
||||
}
|
||||
.wr-goods-card.horizontal-wrap .wr-goods-card__thumb {
|
||||
width: 192rpx;
|
||||
height: 192rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wr-goods-card.horizontal-wrap .wr-goods-card__body {
|
||||
flex-direction: column;
|
||||
}
|
||||
.wr-goods-card.horizontal-wrap .wr-goods-card__short_content {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 16rpx 0 0 0;
|
||||
}
|
||||
|
||||
.wr-goods-card.horizontal-wrap .wr-goods-card__num {
|
||||
margin: 0 0 0 auto;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__main {
|
||||
padding: 0 0 22rpx 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__thumb {
|
||||
width: 340rpx;
|
||||
height: 340rpx;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__body {
|
||||
margin: 20rpx 20rpx 0 20rpx;
|
||||
flex-direction: column;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__long_content {
|
||||
overflow: hidden;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__title {
|
||||
line-height: 36rpx;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__short_content {
|
||||
margin: 20rpx 0 0 0;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__price {
|
||||
order: 2;
|
||||
color: #fa4126;
|
||||
margin: 20rpx 0 0 0;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__origin-price {
|
||||
order: 1;
|
||||
}
|
||||
.wr-goods-card.vertical .wr-goods-card__add-cart {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
right: 20rpx;
|
||||
}
|
||||
|
||||
.wr-goods-card__short_content .no_storage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40rpx;
|
||||
color: #333;
|
||||
font-size: 24rpx;
|
||||
line-height: 32rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.no_storage .no_storage__right {
|
||||
width: 80rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 20rpx;
|
||||
border: 2rpx solid #fa4126;
|
||||
line-height: 40rpx;
|
||||
text-align: center;
|
||||
color: #fa4126;
|
||||
}
|
Reference in New Issue
Block a user