feat: sku to support large image mode

This commit is contained in:
水墨
2020-06-23 11:32:08 +08:00
committed by neverland
parent 489dde2114
commit 54fca31cc3
10 changed files with 412 additions and 66 deletions
+22 -6
View File
@@ -13,6 +13,7 @@ export type SkuHeaderProps = {
goods: SkuGoodsData;
skuEventBus: Vue;
selectedSku: SelectedSkuData;
supportBigPicture: boolean;
};
export type SkuHeaderSlots = DefaultSlots & {
@@ -49,20 +50,34 @@ function SkuHeader(
slots: SkuHeaderSlots,
ctx: RenderContext<SkuHeaderProps>
) {
const { sku, goods, skuEventBus, selectedSku } = props;
const {
sku,
goods,
skuEventBus,
selectedSku,
supportBigPicture = false,
} = props;
const goodsImg = getSkuImg(sku, selectedSku) || goods.picture;
const previewImage = () => {
skuEventBus.$emit('sku:previewImage', goodsImg);
};
return (
<div class={[bem(), BORDER_BOTTOM]} {...inherit(ctx)}>
<div class={bem('img-wrap')} onClick={previewImage}>
<img src={goodsImg} />
{slots['sku-header-image-extra']?.()}
{!supportBigPicture && (
<div class={bem('img-wrap')} onClick={previewImage}>
<img src={goodsImg} />
{slots['sku-header-image-extra']?.()}
</div>
)}
<div
class={[
bem('goods-info'),
supportBigPicture && bem('goods-info--no-padding'),
]}
>
{slots.default?.()}
</div>
<div class={bem('goods-info')}>{slots.default?.()}</div>
</div>
);
}
@@ -72,6 +87,7 @@ SkuHeader.props = {
goods: Object,
skuEventBus: Object,
selectedSku: Object,
supportBigPicture: Boolean,
};
export default createComponent<SkuHeaderProps>(SkuHeader);
+101
View File
@@ -0,0 +1,101 @@
// Utils
import { createNamespace } from '../../utils';
import { BORDER_BOTTOM } from '../../utils/constant';
import { BindEventMixin } from '../../mixins/bind-event';
import { getScroller } from '../../utils/dom/scroll';
const [createComponent, bem, t] = createNamespace('sku-row');
export default createComponent({
mixins: [
BindEventMixin(function (bind) {
if (!(this.isShowBigPicture && this.hasScrollTab)) {
return false;
}
if (!this.scrollCon) {
this.scrollCon = getScroller(this.$refs.skuContent);
}
bind(this.scrollCon, 'scroll', this.onScroll);
}),
],
props: {
skuRow: Object,
isShowBigPicture: {
type: Boolean,
default: false,
},
hasScrollTab: {
type: Boolean,
default: false,
},
},
data() {
return {
present: 0,
contentWidth: 0,
contentItemWidth: 0,
scrollLeft: 0,
};
},
computed: {
scrollStyle() {
if (!(this.isShowBigPicture && this.hasScrollTab)) {
return false;
}
this.tranX = this.present * 20;
return {
transform: `translate3d(${this.tranX}px, 0, 0)`,
};
},
},
methods: {
onScroll() {
this.$nextTick(() => {
const contentWidth = this.scrollCon.clientWidth;
const contentItemWidth = this.$refs.skuContentItem.clientWidth;
const distance = contentItemWidth - contentWidth;
this.present = this.scrollCon.scrollLeft / distance;
});
},
},
mounted() {},
render() {
const { skuRow, isShowBigPicture, hasScrollTab } = this;
const multipleNode = skuRow.is_multiple && (
<span class={bem('title-multiple')}>{t('multiple')}</span>
);
const SkuScroll = (
<div class={bem('scroll')}>
<div class={bem('scroll__content')} ref="skuScroll">
<div
class={bem('scroll__content--active')}
style={this.scrollStyle}
></div>
</div>
</div>
);
const SkuContent = (
<div class={bem('content')} ref="skuContent">
<div class={bem('content__top')} ref="skuContentItem">
{this.slots('sku-item-group-one')}
</div>
<div class={bem('content__bottom')}>
{this.slots('sku-item-group-two')}
</div>
</div>
);
return (
<div class={[bem(), BORDER_BOTTOM, isShowBigPicture && bem('picture')]}>
<div class={bem('title')}>
{skuRow.k}
{multipleNode}
</div>
{isShowBigPicture ? SkuContent : this.slots()}
{isShowBigPicture && hasScrollTab && SkuScroll}
</div>
);
},
});
-41
View File
@@ -1,41 +0,0 @@
// Utils
import { createNamespace } from '../../utils';
import { inherit } from '../../utils/functional';
import { BORDER_BOTTOM } from '../../utils/constant';
// Types
import { CreateElement, RenderContext } from 'vue/types';
import { DefaultSlots } from '../../utils/types';
import { SkuTreeItemData } from '../../../types/sku';
export type SkuRowProps = {
skuRow: SkuTreeItemData;
};
const [createComponent, bem, t] = createNamespace('sku-row');
function SkuRow(
h: CreateElement,
props: SkuRowProps,
slots: DefaultSlots,
ctx: RenderContext<SkuRowProps>
) {
const multipleNode = props.skuRow.is_multiple && (
<span class={bem('title-multiple')}>{t('multiple')}</span>
);
return (
<div class={[bem(), BORDER_BOTTOM]} {...inherit(ctx)}>
<div class={bem('title')}>
{props.skuRow.k}
{multipleNode}
</div>
{slots.default && slots.default()}
</div>
);
}
SkuRow.props = {
skuRow: Object,
};
export default createComponent<SkuRowProps>(SkuRow);
+25 -7
View File
@@ -13,6 +13,7 @@ export default createComponent({
type: Array,
default: () => [],
},
isShowBigPicture: Boolean,
},
computed: {
@@ -33,25 +34,42 @@ export default createComponent({
});
}
},
onPreviewImg(event) {
event.stopPropagation();
this.skuEventBus.$emit(
'sku:previewImage',
this.skuValue.imgUrl || this.skuValue.img_url
);
},
},
render() {
const choosed = this.skuValue.id === this.selectedSku[this.skuKeyStr];
const imgUrl = this.skuValue.imgUrl || this.skuValue.img_url;
const BEM_NAME = this.isShowBigPicture
? 'van-sku-row__picture-item'
: 'van-sku-row__item';
return (
<span
class={[
'van-sku-row__item',
{
'van-sku-row__item--active': choosed,
'van-sku-row__item--disabled': !this.choosable,
},
`${BEM_NAME}`,
choosed ? `${BEM_NAME}--active` : '',
!this.choosable ? `${BEM_NAME}--disabled` : '',
]}
onClick={this.onSelect}
>
{imgUrl && <img class="van-sku-row__item-img" src={imgUrl} />}
<span class="van-sku-row__item-name">{this.skuValue.name}</span>
{this.isShowBigPicture && (
<img
class={`${BEM_NAME}-img-icon`}
src="https://img.yzcdn.cn/upload_files/2020/06/18/Fn6Qf0fGRFyuD8xh0Gi1w2ng59G1.png"
onClick={this.onPreviewImg}
/>
)}
{imgUrl && (
<img class={`${BEM_NAME}-img`} src={imgUrl} v-lazy={imgUrl} />
)}
<span class={`${BEM_NAME}-name`}>{this.skuValue.name}</span>
</span>
);
},