mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
chore(CouponList): refactor with composition api
This commit is contained in:
parent
c29aa94564
commit
be3f2cbce9
@ -55,7 +55,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.x",
|
"@babel/runtime": "7.x",
|
||||||
"@vant/icons": "1.3.0",
|
"@vant/icons": "1.3.0",
|
||||||
"@vant/use": "^0.0.1",
|
"@vant/use": "^0.0.2",
|
||||||
"vue-lazyload": "1.2.3"
|
"vue-lazyload": "1.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
|
import { watch, computed, nextTick, onMounted, reactive } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { createNamespace } from '../utils';
|
import { createNamespace } from '../utils';
|
||||||
|
|
||||||
|
// Composition
|
||||||
|
import { useWindowSize } from '@vant/use';
|
||||||
|
import { useRefs } from '../composition/use-refs';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import Tab from '../tab';
|
import Tab from '../tab';
|
||||||
import Tabs from '../tabs';
|
import Tabs from '../tabs';
|
||||||
@ -65,178 +71,168 @@ export default createComponent({
|
|||||||
|
|
||||||
emits: ['change', 'exchange', 'update:code'],
|
emits: ['change', 'exchange', 'update:code'],
|
||||||
|
|
||||||
data() {
|
setup(props, { emit }) {
|
||||||
return {
|
const [couponRefs, setCouponRefs] = useRefs();
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
tab: 0,
|
tab: 0,
|
||||||
winHeight: window.innerHeight,
|
code: props.code || '',
|
||||||
currentCode: this.code || '',
|
});
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
const { height: windowHeight } = useWindowSize();
|
||||||
buttonDisabled() {
|
|
||||||
return (
|
|
||||||
!this.exchangeButtonLoading &&
|
|
||||||
(this.exchangeButtonDisabled ||
|
|
||||||
!this.currentCode ||
|
|
||||||
this.currentCode.length < this.exchangeMinLength)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
listStyle() {
|
const buttonDisabled = computed(
|
||||||
return {
|
() =>
|
||||||
height: this.winHeight - (this.showExchangeBar ? 140 : 94) + 'px',
|
!props.exchangeButtonLoading &&
|
||||||
};
|
(props.exchangeButtonDisabled ||
|
||||||
},
|
!state.code ||
|
||||||
},
|
state.code.length < props.exchangeMinLength)
|
||||||
|
);
|
||||||
|
|
||||||
watch: {
|
const listStyle = computed(() => ({
|
||||||
code(code) {
|
height: windowHeight.value - (props.showExchangeBar ? 140 : 94) + 'px',
|
||||||
this.currentCode = code;
|
}));
|
||||||
},
|
|
||||||
|
|
||||||
currentCode(code) {
|
const onExchange = () => {
|
||||||
this.$emit('update:code', code);
|
emit('exchange', state.code);
|
||||||
},
|
|
||||||
|
|
||||||
displayedCouponIndex: 'scrollToShowCoupon',
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.scrollToShowCoupon(this.displayedCouponIndex);
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
onClickExchangeButton() {
|
|
||||||
this.$emit('exchange', this.currentCode);
|
|
||||||
|
|
||||||
// auto clear currentCode when not use vModel
|
// auto clear currentCode when not use vModel
|
||||||
if (!this.code) {
|
if (!props.code) {
|
||||||
this.currentCode = '';
|
state.code = '';
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
// scroll to show specific coupon
|
const scrollToCoupon = (index) => {
|
||||||
scrollToShowCoupon(index) {
|
nextTick(() => {
|
||||||
if (index === -1) {
|
if (couponRefs.value[index]) {
|
||||||
return;
|
couponRefs.value[index].scrollIntoView();
|
||||||
}
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
const { card, list } = this.$refs;
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
if (list && card && card[index]) {
|
|
||||||
list.scrollTop = card[index].$el.offsetTop - 100;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
|
|
||||||
genEmpty() {
|
const renderEmpty = () => (
|
||||||
return (
|
<div class={bem('empty')}>
|
||||||
<div class={bem('empty')}>
|
<img src={props.emptyImage} />
|
||||||
<img src={this.emptyImage} />
|
<p>{t('empty')}</p>
|
||||||
<p>{t('empty')}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
genExchangeButton() {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
plain
|
|
||||||
type="danger"
|
|
||||||
class={bem('exchange')}
|
|
||||||
text={this.exchangeButtonText || t('exchange')}
|
|
||||||
loading={this.exchangeButtonLoading}
|
|
||||||
disabled={this.buttonDisabled}
|
|
||||||
onClick={this.onClickExchangeButton}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { coupons, disabledCoupons } = this;
|
|
||||||
|
|
||||||
const count = this.showCount ? ` (${coupons.length})` : '';
|
|
||||||
const title = (this.enabledTitle || t('enable')) + count;
|
|
||||||
|
|
||||||
const disabledCount = this.showCount ? ` (${disabledCoupons.length})` : '';
|
|
||||||
const disabledTitle = (this.disabledTitle || t('disabled')) + disabledCount;
|
|
||||||
|
|
||||||
const ExchangeBar = this.showExchangeBar && (
|
|
||||||
<div class={bem('exchange-bar')}>
|
|
||||||
<Field
|
|
||||||
vModel={this.currentCode}
|
|
||||||
clearable
|
|
||||||
border={false}
|
|
||||||
class={bem('field')}
|
|
||||||
placeholder={this.inputPlaceholder || t('placeholder')}
|
|
||||||
maxlength="20"
|
|
||||||
/>
|
|
||||||
{this.genExchangeButton()}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const onChange = (index) => () => this.$emit('change', index);
|
const renderExchangeBar = () => {
|
||||||
|
if (props.showExchangeBar) {
|
||||||
const CouponTab = (
|
return (
|
||||||
<Tab title={title}>
|
<div class={bem('exchange-bar')}>
|
||||||
<div
|
<Field
|
||||||
class={bem('list', { 'with-bottom': this.showCloseButton })}
|
vModel={state.code}
|
||||||
style={this.listStyle}
|
clearable
|
||||||
>
|
border={false}
|
||||||
{coupons.map((coupon, index) => (
|
class={bem('field')}
|
||||||
<Coupon
|
placeholder={props.inputPlaceholder || t('placeholder')}
|
||||||
ref="card"
|
maxlength="20"
|
||||||
key={coupon.id}
|
|
||||||
coupon={coupon}
|
|
||||||
chosen={index === this.chosenCoupon}
|
|
||||||
currency={this.currency}
|
|
||||||
onClick={onChange(index)}
|
|
||||||
/>
|
/>
|
||||||
))}
|
<Button
|
||||||
{!coupons.length && this.genEmpty()}
|
plain
|
||||||
</div>
|
type="danger"
|
||||||
</Tab>
|
class={bem('exchange')}
|
||||||
|
text={props.exchangeButtonText || t('exchange')}
|
||||||
|
loading={props.exchangeButtonLoading}
|
||||||
|
disabled={buttonDisabled.value}
|
||||||
|
onClick={onExchange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCouponTab = () => {
|
||||||
|
const { coupons } = props;
|
||||||
|
const count = props.showCount ? ` (${coupons.length})` : '';
|
||||||
|
const title = (props.enabledTitle || t('enable')) + count;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tab title={title}>
|
||||||
|
<div
|
||||||
|
class={bem('list', { 'with-bottom': props.showCloseButton })}
|
||||||
|
style={listStyle.value}
|
||||||
|
>
|
||||||
|
{coupons.map((coupon, index) => (
|
||||||
|
<Coupon
|
||||||
|
key={coupon.id}
|
||||||
|
ref={setCouponRefs(index)}
|
||||||
|
coupon={coupon}
|
||||||
|
chosen={index === props.chosenCoupon}
|
||||||
|
currency={props.currency}
|
||||||
|
onClick={() => emit('change', index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{!coupons.length && renderEmpty()}
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderDisabledTab = () => {
|
||||||
|
const { disabledCoupons } = props;
|
||||||
|
const count = props.showCount ? ` (${disabledCoupons.length})` : '';
|
||||||
|
const title = (props.disabledTitle || t('disabled')) + count;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tab title={title}>
|
||||||
|
<div
|
||||||
|
class={bem('list', { 'with-bottom': props.showCloseButton })}
|
||||||
|
style={listStyle.value}
|
||||||
|
>
|
||||||
|
{disabledCoupons.map((coupon) => (
|
||||||
|
<Coupon
|
||||||
|
disabled
|
||||||
|
key={coupon.id}
|
||||||
|
coupon={coupon}
|
||||||
|
currency={props.currency}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{!disabledCoupons.length && renderEmpty()}
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.code,
|
||||||
|
(value) => {
|
||||||
|
state.code = value;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const DisabledCouponTab = (
|
watch(
|
||||||
<Tab title={disabledTitle}>
|
() => state.code,
|
||||||
<div
|
(value) => {
|
||||||
class={bem('list', { 'with-bottom': this.showCloseButton })}
|
emit('update:code', value);
|
||||||
style={this.listStyle}
|
}
|
||||||
>
|
|
||||||
{disabledCoupons.map((coupon) => (
|
|
||||||
<Coupon
|
|
||||||
disabled
|
|
||||||
key={coupon.id}
|
|
||||||
coupon={coupon}
|
|
||||||
currency={this.currency}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{!disabledCoupons.length && this.genEmpty()}
|
|
||||||
</div>
|
|
||||||
</Tab>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
watch(() => props.displayedCouponIndex, scrollToCoupon);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
scrollToCoupon(props.displayedCouponIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => (
|
||||||
<div class={bem()}>
|
<div class={bem()}>
|
||||||
{ExchangeBar}
|
{renderExchangeBar()}
|
||||||
<Tabs vModel={this.tab} class={bem('tab')} border={false}>
|
<Tabs vModel={state.tab} class={bem('tab')} border={false}>
|
||||||
{CouponTab}
|
{renderCouponTab()}
|
||||||
{DisabledCouponTab}
|
{renderDisabledTab()}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<div class={bem('bottom')}>
|
<div class={bem('bottom')}>
|
||||||
<Button
|
<Button
|
||||||
vShow={this.showCloseButton}
|
vShow={props.showCloseButton}
|
||||||
round
|
round
|
||||||
block
|
block
|
||||||
type="danger"
|
type="danger"
|
||||||
class={bem('close')}
|
class={bem('close')}
|
||||||
text={this.closeButtonText || t('close')}
|
text={props.closeButtonText || t('close')}
|
||||||
onClick={onChange(-1)}
|
onClick={() => {
|
||||||
|
emit('change', -1);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2156,10 +2156,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@vant/touch-emulator/-/touch-emulator-1.2.0.tgz#486300b23e57db9ce9231a04e0a0c621c68692d8"
|
resolved "https://registry.yarnpkg.com/@vant/touch-emulator/-/touch-emulator-1.2.0.tgz#486300b23e57db9ce9231a04e0a0c621c68692d8"
|
||||||
integrity sha512-sJ97zU85zOq51qoi7+CpBEcOyH3CitjP1KC7/GQwqaurUJni+EP7/F9n0HMnAh8GXMjgtgDBNJ5z48x+coNKYQ==
|
integrity sha512-sJ97zU85zOq51qoi7+CpBEcOyH3CitjP1KC7/GQwqaurUJni+EP7/F9n0HMnAh8GXMjgtgDBNJ5z48x+coNKYQ==
|
||||||
|
|
||||||
"@vant/use@^0.0.1":
|
"@vant/use@^0.0.2":
|
||||||
version "0.0.1"
|
version "0.0.2"
|
||||||
resolved "https://registry.npmjs.org/@vant/use/-/use-0.0.1.tgz#66ed5dd186e54a6ec1b48604bfd8c0f466d9d568"
|
resolved "https://registry.npmjs.org/@vant/use/-/use-0.0.2.tgz#9ea72642e0d6ef664f19e80b73fdb59b9f403d21"
|
||||||
integrity sha512-AQrKFoiC4sZqRI6mx4a4iHekcpcvNYcZDo/0/WTMejtjKygaKMlImmOR36JWYinhvQwjO6GnAgQDvuO/hNwCPA==
|
integrity sha512-kPgqwBMKaeKPQ/LZjjVDHKxo2Thi4w5M186+Yg4jATW7qCcfd0CujDmqlETfFjBCbw40C1HVu/kmhXE0cQPPUg==
|
||||||
|
|
||||||
"@vue/babel-helper-vue-transform-on@^1.0.0-rc.2":
|
"@vue/babel-helper-vue-transform-on@^1.0.0-rc.2":
|
||||||
version "1.0.0-rc.2"
|
version "1.0.0-rc.2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user