chore(CouponList): refactor with composition api

This commit is contained in:
chenjiahan 2020-09-14 19:22:09 +08:00
parent c29aa94564
commit be3f2cbce9
3 changed files with 145 additions and 149 deletions

View File

@ -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": {

View File

@ -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>

View File

@ -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"