feat: sku to support large image mode
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user