mirror of
https://github.com/youzan/vant.git
synced 2025-10-20 02:31:21 +00:00
[improvement] AddressEdit: jsx (#2503)
This commit is contained in:
332
packages/address-edit/index.js
Normal file
332
packages/address-edit/index.js
Normal file
@@ -0,0 +1,332 @@
|
||||
import { use, isObj } from '../utils';
|
||||
import Area from '../area';
|
||||
import Field from '../field';
|
||||
import Popup from '../popup';
|
||||
import Toast from '../toast';
|
||||
import Button from '../button';
|
||||
import Dialog from '../dialog';
|
||||
import Detail from './Detail';
|
||||
import SwitchCell from '../switch-cell';
|
||||
import validateMobile from '../utils/validate/mobile';
|
||||
|
||||
const [sfc, bem, t] = use('address-edit');
|
||||
|
||||
const defaultData = {
|
||||
name: '',
|
||||
tel: '',
|
||||
country: '',
|
||||
province: '',
|
||||
city: '',
|
||||
county: '',
|
||||
areaCode: '',
|
||||
postalCode: '',
|
||||
addressDetail: '',
|
||||
isDefault: false
|
||||
};
|
||||
|
||||
export default sfc({
|
||||
props: {
|
||||
areaList: Object,
|
||||
isSaving: Boolean,
|
||||
isDeleting: Boolean,
|
||||
validator: Function,
|
||||
showDelete: Boolean,
|
||||
showPostal: Boolean,
|
||||
searchResult: Array,
|
||||
showSetDefault: Boolean,
|
||||
showSearchResult: Boolean,
|
||||
saveButtonText: String,
|
||||
deleteButtonText: String,
|
||||
showArea: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showDetail: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
detailRows: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
addressInfo: {
|
||||
type: Object,
|
||||
default: () => ({ ...defaultData })
|
||||
},
|
||||
telValidator: {
|
||||
type: Function,
|
||||
default: validateMobile
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
data: {},
|
||||
showAreaPopup: false,
|
||||
detailFocused: false,
|
||||
errorInfo: {
|
||||
tel: false,
|
||||
name: false,
|
||||
postalCode: false,
|
||||
addressDetail: false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
// hide bottom field when use search && detail get focused
|
||||
hideBottomFields() {
|
||||
return this.searchResult.length && this.detailFocused;
|
||||
},
|
||||
|
||||
areaListLoaded() {
|
||||
return isObj(this.areaList) && Object.keys(this.areaList).length;
|
||||
},
|
||||
|
||||
areaText() {
|
||||
const { country, province, city, county, areaCode } = this.data;
|
||||
if (areaCode) {
|
||||
const arr = [country, province, city, county];
|
||||
if (province && province === city) {
|
||||
arr.splice(1, 1);
|
||||
}
|
||||
return arr.filter(text => text).join('/');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
addressInfo: {
|
||||
handler(val) {
|
||||
this.data = {
|
||||
...defaultData,
|
||||
...val
|
||||
};
|
||||
|
||||
this.setAreaCode(val.areaCode);
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
|
||||
areaList() {
|
||||
this.setAreaCode(this.data.areaCode);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onFocus(key) {
|
||||
this.errorInfo[key] = false;
|
||||
this.detailFocused = key === 'addressDetail';
|
||||
this.$emit('focus', key);
|
||||
},
|
||||
|
||||
onChangeDetail(val) {
|
||||
this.data.addressDetail = val;
|
||||
this.$emit('change-detail', val);
|
||||
},
|
||||
|
||||
onAreaConfirm(values) {
|
||||
this.showAreaPopup = false;
|
||||
this.assignAreaValues();
|
||||
this.$emit('change-area', values);
|
||||
},
|
||||
|
||||
assignAreaValues() {
|
||||
const { area } = this.$refs;
|
||||
if (area) {
|
||||
const detail = area.getArea();
|
||||
detail.areaCode = detail.code;
|
||||
delete detail.code;
|
||||
Object.assign(this.data, detail);
|
||||
}
|
||||
},
|
||||
|
||||
onSave() {
|
||||
const items = ['name', 'tel', 'areaCode', 'addressDetail'];
|
||||
|
||||
if (this.showPostal) {
|
||||
items.push('postalCode');
|
||||
}
|
||||
|
||||
const isValid = items.every(item => {
|
||||
const msg = this.getErrorMessage(item);
|
||||
if (msg) {
|
||||
this.errorInfo[item] = true;
|
||||
Toast(msg);
|
||||
}
|
||||
return !msg;
|
||||
});
|
||||
|
||||
if (isValid && !this.isSaving) {
|
||||
this.$emit('save', this.data);
|
||||
}
|
||||
},
|
||||
|
||||
getErrorMessage(key) {
|
||||
const value = String(this.data[key] || '').trim();
|
||||
|
||||
if (this.validator) {
|
||||
const message = this.validator(key, value);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'name':
|
||||
return value ? '' : t('nameEmpty');
|
||||
case 'tel':
|
||||
return this.telValidator(value) ? '' : t('telInvalid');
|
||||
case 'areaCode':
|
||||
return value ? '' : t('areaEmpty');
|
||||
case 'addressDetail':
|
||||
return value ? '' : t('addressEmpty');
|
||||
case 'postalCode':
|
||||
return value && !/^\d{6}$/.test(value) ? t('postalEmpty') : '';
|
||||
}
|
||||
},
|
||||
|
||||
onDelete() {
|
||||
Dialog.confirm({
|
||||
title: t('confirmDelete')
|
||||
})
|
||||
.then(() => {
|
||||
this.$emit('delete', this.data);
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit('cancel-delete', this.data);
|
||||
});
|
||||
},
|
||||
|
||||
// get values of area component
|
||||
getArea() {
|
||||
return this.$refs.area ? this.$refs.area.getValues() : [];
|
||||
},
|
||||
|
||||
// set area code to area component
|
||||
setAreaCode(code) {
|
||||
this.data.areaCode = code || '';
|
||||
|
||||
if (code) {
|
||||
this.$nextTick(this.assignAreaValues);
|
||||
}
|
||||
},
|
||||
|
||||
setAddressDetail(value) {
|
||||
this.data.addressDetail = value;
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { data, errorInfo, hideBottomFields } = this;
|
||||
const onFocus = name => () => this.onFocus(name);
|
||||
|
||||
return (
|
||||
<div class={bem()}>
|
||||
<Field
|
||||
v-model={data.name}
|
||||
clearable
|
||||
label={t('name')}
|
||||
placeholder={t('namePlaceholder')}
|
||||
error={errorInfo.name}
|
||||
onFocus={onFocus('name')}
|
||||
/>
|
||||
<Field
|
||||
v-model={data.tel}
|
||||
clearable
|
||||
type="tel"
|
||||
label={t('tel')}
|
||||
placeholder={t('telPlaceholder')}
|
||||
error={errorInfo.tel}
|
||||
onFocus={onFocus('tel')}
|
||||
/>
|
||||
<Field
|
||||
v-show={this.showArea}
|
||||
readonly
|
||||
label={t('area')}
|
||||
placeholder={t('areaPlaceholder')}
|
||||
value={this.areaText}
|
||||
onClick={() => {
|
||||
this.showAreaPopup = true;
|
||||
}}
|
||||
/>
|
||||
<Detail
|
||||
v-show={this.showDetail}
|
||||
focused={this.detailFocused}
|
||||
value={data.addressDetail}
|
||||
error={errorInfo.addressDetail}
|
||||
detail-rows={this.detailRows}
|
||||
search-result={this.searchResult}
|
||||
show-search-result={this.showSearchResult}
|
||||
onFocus={onFocus('addressDetail')}
|
||||
onBlur={() => {
|
||||
this.detailFocused = false;
|
||||
}}
|
||||
onInput={this.onChangeDetail}
|
||||
onSelect-search={event => {
|
||||
this.$emit('select-search', event);
|
||||
}}
|
||||
/>
|
||||
{this.showPostal && (
|
||||
<Field
|
||||
v-show={!hideBottomFields}
|
||||
v-model={data.postalCode}
|
||||
type="tel"
|
||||
maxlength="6"
|
||||
label={t('postal')}
|
||||
placeholder={t('postal')}
|
||||
error={errorInfo.postalCode}
|
||||
onFocus={onFocus('postalCode')}
|
||||
/>
|
||||
)}
|
||||
{this.$slots.default}
|
||||
{this.showSetDefault && (
|
||||
<SwitchCell
|
||||
v-model={data.isDefault}
|
||||
v-show={!hideBottomFields}
|
||||
title={t('defaultAddress')}
|
||||
onChange={event => {
|
||||
this.$emit('change-default', event);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div v-show={!hideBottomFields} class={bem('buttons')}>
|
||||
<Button
|
||||
block
|
||||
loading={this.isSaving}
|
||||
type="danger"
|
||||
text={this.saveButtonText || t('save')}
|
||||
onClick={this.onSave}
|
||||
/>
|
||||
{this.showDelete && (
|
||||
<Button
|
||||
block
|
||||
loading={this.isDeleting}
|
||||
text={this.deleteButtonText || t('delete')}
|
||||
onClick={this.onDelete}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Popup
|
||||
v-model={this.showAreaPopup}
|
||||
position="bottom"
|
||||
lazy-render={false}
|
||||
get-container="body"
|
||||
>
|
||||
<Area
|
||||
ref="area"
|
||||
loading={!this.areaListLoaded}
|
||||
value={data.areaCode}
|
||||
area-list={this.areaList}
|
||||
onConfirm={this.onAreaConfirm}
|
||||
onCancel={() => {
|
||||
this.showAreaPopup = false;
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user