mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[improvement] AddressEdit: jsx (#2503)
This commit is contained in:
parent
4b8bd8e9be
commit
25c00b1023
81
packages/address-edit/Detail.js
Normal file
81
packages/address-edit/Detail.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { use, isAndroid } from '../utils';
|
||||||
|
import Cell from '../cell';
|
||||||
|
import Field from '../field';
|
||||||
|
|
||||||
|
const [sfc, bem, t] = use('address-edit-detail');
|
||||||
|
const android = isAndroid();
|
||||||
|
|
||||||
|
export default sfc({
|
||||||
|
props: {
|
||||||
|
value: String,
|
||||||
|
error: Boolean,
|
||||||
|
focused: Boolean,
|
||||||
|
detailRows: Number,
|
||||||
|
searchResult: Array,
|
||||||
|
showSearchResult: Boolean
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
searchList() {
|
||||||
|
if (this.showSearchResult && this.focused) {
|
||||||
|
return this.searchResult || [];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
showIcon() {
|
||||||
|
return this.value && this.focused;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onSelect(express) {
|
||||||
|
this.$emit('select-search', express);
|
||||||
|
this.$emit('input', `${express.address || ''} ${express.name || ''}`.trim());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render(h) {
|
||||||
|
return (
|
||||||
|
<Cell class={bem()}>
|
||||||
|
<Field
|
||||||
|
autosize
|
||||||
|
ref="field"
|
||||||
|
rows={this.detailRows}
|
||||||
|
clearable={!android}
|
||||||
|
type="textarea"
|
||||||
|
maxlength="200"
|
||||||
|
value={this.value}
|
||||||
|
error={this.error}
|
||||||
|
label={t('label')}
|
||||||
|
placeholder={t('placeholder')}
|
||||||
|
{...{ on: this.$listeners }}
|
||||||
|
>
|
||||||
|
{this.showIcon && android && (
|
||||||
|
<div
|
||||||
|
slot="icon"
|
||||||
|
class={bem('finish')}
|
||||||
|
onClick={() => {
|
||||||
|
this.$refs.field.blur();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('complete')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
{this.searchList.map(express => (
|
||||||
|
<Cell
|
||||||
|
key={express.name + express.address}
|
||||||
|
title={express.name}
|
||||||
|
label={express.address}
|
||||||
|
icon="location-o"
|
||||||
|
clickable
|
||||||
|
onClick={() => {
|
||||||
|
this.onSelect(express);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Cell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
@ -1,81 +0,0 @@
|
|||||||
<template>
|
|
||||||
<cell :class="b()">
|
|
||||||
<field
|
|
||||||
v-on="$listeners"
|
|
||||||
autosize
|
|
||||||
ref="field"
|
|
||||||
:rows="detailRows"
|
|
||||||
:clearable="!isAndroid"
|
|
||||||
type="textarea"
|
|
||||||
maxlength="200"
|
|
||||||
:value="value"
|
|
||||||
:error="error"
|
|
||||||
:label="$t('label')"
|
|
||||||
:placeholder="$t('placeholder')"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="showIcon && isAndroid"
|
|
||||||
v-text="$t('complete')"
|
|
||||||
slot="icon"
|
|
||||||
:class="b('finish')"
|
|
||||||
@click="$refs.field.blur()"
|
|
||||||
/>
|
|
||||||
</field>
|
|
||||||
<cell
|
|
||||||
v-for="express in searchList"
|
|
||||||
:key="express.name + express.address"
|
|
||||||
:title="express.name"
|
|
||||||
:label="express.address"
|
|
||||||
icon="location-o"
|
|
||||||
clickable
|
|
||||||
@click="onSelect(express)"
|
|
||||||
/>
|
|
||||||
</cell>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import create from '../utils/create';
|
|
||||||
import Field from '../field';
|
|
||||||
import { isAndroid } from '../utils';
|
|
||||||
|
|
||||||
export default create({
|
|
||||||
name: 'address-edit-detail',
|
|
||||||
|
|
||||||
components: {
|
|
||||||
Field
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
value: String,
|
|
||||||
error: Boolean,
|
|
||||||
focused: Boolean,
|
|
||||||
detailRows: Number,
|
|
||||||
searchResult: Array,
|
|
||||||
showSearchResult: Boolean
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.isAndroid = isAndroid();
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
searchList() {
|
|
||||||
if (this.showSearchResult && this.focused) {
|
|
||||||
return this.searchResult || [];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
|
|
||||||
showIcon() {
|
|
||||||
return this.value && this.focused;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
onSelect(express) {
|
|
||||||
this.$emit('select-search', express);
|
|
||||||
this.$emit('input', `${express.address || ''} ${express.name || ''}`.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,115 +1,16 @@
|
|||||||
<template>
|
import { use, isObj } from '../utils';
|
||||||
<div :class="b()">
|
import Area from '../area';
|
||||||
<field
|
|
||||||
v-model="data.name"
|
|
||||||
clearable
|
|
||||||
:label="$t('name')"
|
|
||||||
:placeholder="$t('namePlaceholder')"
|
|
||||||
:error="errorInfo.name"
|
|
||||||
@focus="onFocus('name')"
|
|
||||||
/>
|
|
||||||
<field
|
|
||||||
v-model="data.tel"
|
|
||||||
clearable
|
|
||||||
type="tel"
|
|
||||||
:label="$t('tel')"
|
|
||||||
:placeholder="$t('telPlaceholder')"
|
|
||||||
:error="errorInfo.tel"
|
|
||||||
@focus="onFocus('tel')"
|
|
||||||
/>
|
|
||||||
<field
|
|
||||||
v-show="showArea"
|
|
||||||
readonly
|
|
||||||
:label="$t('area')"
|
|
||||||
:placeholder="$t('areaPlaceholder')"
|
|
||||||
:value="areaText"
|
|
||||||
@click="showAreaPopup = true"
|
|
||||||
/>
|
|
||||||
<address-edit-detail
|
|
||||||
v-show="showDetail"
|
|
||||||
:focused="detailFocused"
|
|
||||||
:value="data.addressDetail"
|
|
||||||
:error="errorInfo.addressDetail"
|
|
||||||
:detail-rows="detailRows"
|
|
||||||
:search-result="searchResult"
|
|
||||||
:show-search-result="showSearchResult"
|
|
||||||
@focus="onFocus('addressDetail')"
|
|
||||||
@blur="detailFocused = false"
|
|
||||||
@input="onChangeDetail"
|
|
||||||
@select-search="$emit('select-search', $event)"
|
|
||||||
/>
|
|
||||||
<field
|
|
||||||
v-if="showPostal"
|
|
||||||
v-show="!hideBottomFields"
|
|
||||||
v-model="data.postalCode"
|
|
||||||
type="tel"
|
|
||||||
maxlength="6"
|
|
||||||
:label="$t('postal')"
|
|
||||||
:placeholder="$t('postal')"
|
|
||||||
:error="errorInfo.postalCode"
|
|
||||||
@focus="onFocus('postalCode')"
|
|
||||||
/>
|
|
||||||
<slot />
|
|
||||||
<switch-cell
|
|
||||||
v-if="showSetDefault"
|
|
||||||
v-show="!hideBottomFields"
|
|
||||||
v-model="data.isDefault"
|
|
||||||
:title="$t('defaultAddress')"
|
|
||||||
@change="$emit('change-default', $event)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-show="!hideBottomFields"
|
|
||||||
:class="b('buttons')"
|
|
||||||
>
|
|
||||||
<van-button
|
|
||||||
block
|
|
||||||
:loading="isSaving"
|
|
||||||
type="danger"
|
|
||||||
:text="saveButtonText || $t('save')"
|
|
||||||
@click="onSave"
|
|
||||||
/>
|
|
||||||
<van-button
|
|
||||||
v-if="showDelete"
|
|
||||||
block
|
|
||||||
:loading="isDeleting"
|
|
||||||
:text="deleteButtonText || $t('delete')"
|
|
||||||
@click="onDelete"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<popup
|
|
||||||
v-model="showAreaPopup"
|
|
||||||
position="bottom"
|
|
||||||
:lazy-render="false"
|
|
||||||
get-container="body"
|
|
||||||
>
|
|
||||||
<van-area
|
|
||||||
ref="area"
|
|
||||||
:loading="!areaListLoaded"
|
|
||||||
:value="data.areaCode"
|
|
||||||
:area-list="areaList"
|
|
||||||
@confirm="onAreaConfirm"
|
|
||||||
@cancel="showAreaPopup = false"
|
|
||||||
/>
|
|
||||||
</popup>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/* eslint-disable camelcase */
|
|
||||||
import create from '../utils/create';
|
|
||||||
import { isObj } from '../utils';
|
|
||||||
import Field from '../field';
|
import Field from '../field';
|
||||||
import VanButton from '../button';
|
|
||||||
import Popup from '../popup';
|
import Popup from '../popup';
|
||||||
import Toast from '../toast';
|
import Toast from '../toast';
|
||||||
|
import Button from '../button';
|
||||||
import Dialog from '../dialog';
|
import Dialog from '../dialog';
|
||||||
import VanArea from '../area';
|
import Detail from './Detail';
|
||||||
import AddressEditDetail from './Detail';
|
|
||||||
import SwitchCell from '../switch-cell';
|
import SwitchCell from '../switch-cell';
|
||||||
import validateMobile from '../utils/validate/mobile';
|
import validateMobile from '../utils/validate/mobile';
|
||||||
|
|
||||||
|
const [sfc, bem, t] = use('address-edit');
|
||||||
|
|
||||||
const defaultData = {
|
const defaultData = {
|
||||||
name: '',
|
name: '',
|
||||||
tel: '',
|
tel: '',
|
||||||
@ -123,18 +24,7 @@ const defaultData = {
|
|||||||
isDefault: false
|
isDefault: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default create({
|
export default sfc({
|
||||||
name: 'address-edit',
|
|
||||||
|
|
||||||
components: {
|
|
||||||
Field,
|
|
||||||
Popup,
|
|
||||||
VanArea,
|
|
||||||
VanButton,
|
|
||||||
SwitchCell,
|
|
||||||
AddressEditDetail
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
areaList: Object,
|
areaList: Object,
|
||||||
isSaving: Boolean,
|
isSaving: Boolean,
|
||||||
@ -276,7 +166,6 @@ export default create({
|
|||||||
|
|
||||||
getErrorMessage(key) {
|
getErrorMessage(key) {
|
||||||
const value = String(this.data[key] || '').trim();
|
const value = String(this.data[key] || '').trim();
|
||||||
const { $t } = this;
|
|
||||||
|
|
||||||
if (this.validator) {
|
if (this.validator) {
|
||||||
const message = this.validator(key, value);
|
const message = this.validator(key, value);
|
||||||
@ -287,21 +176,21 @@ export default create({
|
|||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'name':
|
case 'name':
|
||||||
return value ? '' : $t('nameEmpty');
|
return value ? '' : t('nameEmpty');
|
||||||
case 'tel':
|
case 'tel':
|
||||||
return this.telValidator(value) ? '' : $t('telInvalid');
|
return this.telValidator(value) ? '' : t('telInvalid');
|
||||||
case 'areaCode':
|
case 'areaCode':
|
||||||
return value ? '' : $t('areaEmpty');
|
return value ? '' : t('areaEmpty');
|
||||||
case 'addressDetail':
|
case 'addressDetail':
|
||||||
return value ? '' : $t('addressEmpty');
|
return value ? '' : t('addressEmpty');
|
||||||
case 'postalCode':
|
case 'postalCode':
|
||||||
return value && !/^\d{6}$/.test(value) ? $t('postalEmpty') : '';
|
return value && !/^\d{6}$/.test(value) ? t('postalEmpty') : '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onDelete() {
|
onDelete() {
|
||||||
Dialog.confirm({
|
Dialog.confirm({
|
||||||
title: this.$t('confirmDelete')
|
title: t('confirmDelete')
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$emit('delete', this.data);
|
this.$emit('delete', this.data);
|
||||||
@ -328,6 +217,116 @@ export default create({
|
|||||||
setAddressDetail(value) {
|
setAddressDetail(value) {
|
||||||
this.data.addressDetail = 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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
|
@ -75,6 +75,7 @@ exports[`renders demo correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="van-cell van-cell--center van-cell--borderless van-switch-cell">
|
<div class="van-cell van-cell--center van-cell--borderless van-switch-cell">
|
||||||
<div class="van-cell__title"><span>设为默认收货地址</span>
|
<div class="van-cell__title"><span>设为默认收货地址</span>
|
||||||
</div>
|
</div>
|
||||||
@ -87,7 +88,8 @@ exports[`renders demo correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button> <button class="van-button van-button--default van-button--normal van-button--block"><span class="van-button__text">删除</span></button></div>
|
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button>
|
||||||
|
<button class="van-button van-button--default van-button--normal van-button--block"><span class="van-button__text">删除</span></button></div>
|
||||||
<div class="van-popup van-popup--bottom" style="display:none;">
|
<div class="van-popup van-popup--bottom" style="display:none;">
|
||||||
<div class="van-picker van-area">
|
<div class="van-picker van-area">
|
||||||
<div class="van-hairline--top-bottom van-picker__toolbar">
|
<div class="van-hairline--top-bottom van-picker__toolbar">
|
||||||
|
@ -60,10 +60,10 @@ exports[`create a AddressEdit 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!---->
|
|
||||||
<!---->
|
|
||||||
|
|
||||||
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button>
|
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button>
|
||||||
<!---->
|
|
||||||
</div>
|
</div>
|
||||||
<div name="popup-slide-bottom" class="van-popup van-popup--bottom" style="display:none;">
|
<div name="popup-slide-bottom" class="van-popup van-popup--bottom" style="display:none;">
|
||||||
<div class="van-picker van-area">
|
<div class="van-picker van-area">
|
||||||
@ -165,6 +165,7 @@ exports[`create a AddressEdit with props 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="van-cell van-cell--center van-cell--borderless van-switch-cell">
|
<div class="van-cell van-cell--center van-cell--borderless van-switch-cell">
|
||||||
<div class="van-cell__title"><span>设为默认收货地址</span>
|
<div class="van-cell__title"><span>设为默认收货地址</span>
|
||||||
</div>
|
</div>
|
||||||
@ -178,7 +179,6 @@ exports[`create a AddressEdit with props 1`] = `
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button>
|
<div class="van-address-edit__buttons"><button class="van-button van-button--danger van-button--normal van-button--block"><span class="van-button__text">保存</span></button>
|
||||||
<!---->
|
|
||||||
</div>
|
</div>
|
||||||
<div name="popup-slide-bottom" class="van-popup van-popup--bottom" style="display:none;">
|
<div name="popup-slide-bottom" class="van-popup van-popup--bottom" style="display:none;">
|
||||||
<div class="van-picker van-area">
|
<div class="van-picker van-area">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user