mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat: migrate AddressList component
This commit is contained in:
parent
789a2fda1e
commit
abe8ae7cca
@ -67,5 +67,6 @@ module.exports = [
|
|||||||
'image-preview',
|
'image-preview',
|
||||||
'index-bar',
|
'index-bar',
|
||||||
'index-anchor',
|
'index-anchor',
|
||||||
|
'address-list',
|
||||||
'area',
|
'area',
|
||||||
];
|
];
|
||||||
|
91
src/address-list/Item.js
Normal file
91
src/address-list/Item.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// Utils
|
||||||
|
import { createNamespace } from '../utils';
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Tag from '../tag';
|
||||||
|
import Icon from '../icon';
|
||||||
|
import Cell from '../cell';
|
||||||
|
import Radio from '../radio';
|
||||||
|
|
||||||
|
const [createComponent, bem] = createNamespace('address-item');
|
||||||
|
|
||||||
|
export default createComponent({
|
||||||
|
props: {
|
||||||
|
data: Object,
|
||||||
|
disabled: Boolean,
|
||||||
|
switchable: Boolean,
|
||||||
|
defaultTagText: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['edit', 'click', 'select'],
|
||||||
|
|
||||||
|
setup(props, { slots, emit }) {
|
||||||
|
function onClick() {
|
||||||
|
if (props.switchable) {
|
||||||
|
emit('select');
|
||||||
|
}
|
||||||
|
emit('click');
|
||||||
|
}
|
||||||
|
|
||||||
|
const genRightIcon = () => (
|
||||||
|
<Icon
|
||||||
|
name="edit"
|
||||||
|
class={bem('edit')}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
emit('edit');
|
||||||
|
emit('click');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
function genTag() {
|
||||||
|
if (props.data.isDefault && props.defaultTagText) {
|
||||||
|
return (
|
||||||
|
<Tag type="danger" round class={bem('tag')}>
|
||||||
|
{props.defaultTagText}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function genContent() {
|
||||||
|
const { data } = props;
|
||||||
|
const Info = [
|
||||||
|
<div class={bem('name')}>
|
||||||
|
{`${data.name} ${data.tel}`}
|
||||||
|
{genTag()}
|
||||||
|
</div>,
|
||||||
|
<div class={bem('address')}>{data.address}</div>,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (props.switchable && !props.disabled) {
|
||||||
|
return (
|
||||||
|
<Radio name={data.id} iconSize={18}>
|
||||||
|
{Info}
|
||||||
|
</Radio>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const { disabled } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={bem({ disabled })} onClick={onClick}>
|
||||||
|
<Cell
|
||||||
|
v-slots={{
|
||||||
|
default: genContent,
|
||||||
|
'right-icon': genRightIcon,
|
||||||
|
}}
|
||||||
|
border={false}
|
||||||
|
valueClass={bem('value')}
|
||||||
|
/>
|
||||||
|
{slots.bottom?.({ ...props.data, disabled })}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
@ -1,126 +0,0 @@
|
|||||||
// Utils
|
|
||||||
import { createNamespace } from '../utils';
|
|
||||||
import { emit, inherit } from '../utils/functional';
|
|
||||||
|
|
||||||
// Components
|
|
||||||
import Tag from '../tag';
|
|
||||||
import Icon from '../icon';
|
|
||||||
import Cell from '../cell';
|
|
||||||
import Radio from '../radio';
|
|
||||||
|
|
||||||
// Types
|
|
||||||
import { CreateElement, RenderContext } from 'vue/types';
|
|
||||||
import { DefaultSlots, ScopedSlot } from '../utils/types';
|
|
||||||
|
|
||||||
export type AddressItemData = {
|
|
||||||
id: string | number;
|
|
||||||
tel: string | number;
|
|
||||||
name: string;
|
|
||||||
address: string;
|
|
||||||
isDefault: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddressItemProps = {
|
|
||||||
data: AddressItemData;
|
|
||||||
disabled?: boolean;
|
|
||||||
switchable?: boolean;
|
|
||||||
defaultTagText?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddressItemSlots = DefaultSlots & {
|
|
||||||
bottom?: ScopedSlot;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddressItemEvents = {
|
|
||||||
onEdit(): void;
|
|
||||||
onClick(): void;
|
|
||||||
onSelect(): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('address-item');
|
|
||||||
|
|
||||||
function AddressItem(
|
|
||||||
h: CreateElement,
|
|
||||||
props: AddressItemProps,
|
|
||||||
slots: AddressItemSlots,
|
|
||||||
ctx: RenderContext<AddressItemProps>
|
|
||||||
) {
|
|
||||||
const { disabled, switchable } = props;
|
|
||||||
|
|
||||||
function onClick() {
|
|
||||||
if (switchable) {
|
|
||||||
emit(ctx, 'select');
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(ctx, 'click');
|
|
||||||
}
|
|
||||||
|
|
||||||
const genRightIcon = () => (
|
|
||||||
<Icon
|
|
||||||
name="edit"
|
|
||||||
class={bem('edit')}
|
|
||||||
onClick={(event: Event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
emit(ctx, 'edit');
|
|
||||||
emit(ctx, 'click');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
function genTag() {
|
|
||||||
if (props.data.isDefault && props.defaultTagText) {
|
|
||||||
return (
|
|
||||||
<Tag type="danger" round class={bem('tag')}>
|
|
||||||
{props.defaultTagText}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function genContent() {
|
|
||||||
const { data } = props;
|
|
||||||
const Info = [
|
|
||||||
<div class={bem('name')}>
|
|
||||||
{`${data.name} ${data.tel}`}
|
|
||||||
{genTag()}
|
|
||||||
</div>,
|
|
||||||
<div class={bem('address')}>{data.address}</div>,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (switchable && !disabled) {
|
|
||||||
return (
|
|
||||||
<Radio name={data.id} iconSize={18}>
|
|
||||||
{Info}
|
|
||||||
</Radio>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Info;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={bem({ disabled })} onClick={onClick}>
|
|
||||||
<Cell
|
|
||||||
border={false}
|
|
||||||
valueClass={bem('value')}
|
|
||||||
scopedSlots={{
|
|
||||||
default: genContent,
|
|
||||||
'right-icon': genRightIcon,
|
|
||||||
}}
|
|
||||||
{...inherit(ctx)}
|
|
||||||
/>
|
|
||||||
{slots.bottom?.({ ...props.data, disabled })}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddressItem.props = {
|
|
||||||
data: Object,
|
|
||||||
disabled: Boolean,
|
|
||||||
switchable: Boolean,
|
|
||||||
defaultTagText: String,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createComponent<AddressItemProps, AddressItemEvents>(
|
|
||||||
AddressItem
|
|
||||||
);
|
|
97
src/address-list/index.js
Normal file
97
src/address-list/index.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Utils
|
||||||
|
import { createNamespace } from '../utils';
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Button from '../button';
|
||||||
|
import RadioGroup from '../radio-group';
|
||||||
|
import AddressItem from './Item';
|
||||||
|
|
||||||
|
const [createComponent, bem, t] = createNamespace('address-list');
|
||||||
|
|
||||||
|
export default createComponent({
|
||||||
|
props: {
|
||||||
|
list: Array,
|
||||||
|
modelValue: [Number, String],
|
||||||
|
disabledList: Array,
|
||||||
|
disabledText: String,
|
||||||
|
addButtonText: String,
|
||||||
|
defaultTagText: String,
|
||||||
|
switchable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: [
|
||||||
|
'add',
|
||||||
|
'edit',
|
||||||
|
'select',
|
||||||
|
'click-item',
|
||||||
|
'edit-disabled',
|
||||||
|
'select-disabled',
|
||||||
|
'update:modelValue',
|
||||||
|
],
|
||||||
|
|
||||||
|
setup(props, { slots, emit }) {
|
||||||
|
return () => {
|
||||||
|
function genList(list, disabled) {
|
||||||
|
if (!list) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.map((item, index) => (
|
||||||
|
<AddressItem
|
||||||
|
data={item}
|
||||||
|
key={item.id}
|
||||||
|
disabled={disabled}
|
||||||
|
switchable={props.switchable}
|
||||||
|
defaultTagText={props.defaultTagText}
|
||||||
|
scopedSlots={{
|
||||||
|
bottom: slots['item-bottom'],
|
||||||
|
}}
|
||||||
|
onSelect={() => {
|
||||||
|
emit(disabled ? 'select-disabled' : 'select', item, index);
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
emit('update:modelValue', item.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onEdit={() => {
|
||||||
|
emit(disabled ? 'edit-disabled' : 'edit', item, index);
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
emit('click-item', item, index);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
const List = genList(props.list);
|
||||||
|
const DisabledList = genList(props.disabledList, true);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={bem()}>
|
||||||
|
{slots.top?.()}
|
||||||
|
<RadioGroup modelValue={props.modelValue}>{List}</RadioGroup>
|
||||||
|
{props.disabledText && (
|
||||||
|
<div class={bem('disabled-text')}>{props.disabledText}</div>
|
||||||
|
)}
|
||||||
|
{DisabledList}
|
||||||
|
{slots.default?.()}
|
||||||
|
<div class={bem('bottom')}>
|
||||||
|
<Button
|
||||||
|
round
|
||||||
|
block
|
||||||
|
type="danger"
|
||||||
|
class={bem('add')}
|
||||||
|
text={props.addButtonText || t('add')}
|
||||||
|
onClick={() => {
|
||||||
|
emit('add');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
@ -1,110 +0,0 @@
|
|||||||
// Utils
|
|
||||||
import { createNamespace } from '../utils';
|
|
||||||
import { emit, inherit } from '../utils/functional';
|
|
||||||
|
|
||||||
// Components
|
|
||||||
import Button from '../button';
|
|
||||||
import RadioGroup from '../radio-group';
|
|
||||||
import AddressItem, { AddressItemData } from './Item';
|
|
||||||
|
|
||||||
// Types
|
|
||||||
import { CreateElement, RenderContext } from 'vue/types';
|
|
||||||
import { ScopedSlot, DefaultSlots } from '../utils/types';
|
|
||||||
|
|
||||||
export type AddressListProps = {
|
|
||||||
value?: string | number;
|
|
||||||
switchable: boolean;
|
|
||||||
disabledText?: string;
|
|
||||||
addButtonText?: string;
|
|
||||||
list?: AddressItemData[];
|
|
||||||
disabledList?: AddressItemData[];
|
|
||||||
defaultTagText?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddressListSlots = DefaultSlots & {
|
|
||||||
top?: ScopedSlot;
|
|
||||||
'item-bottom'?: ScopedSlot;
|
|
||||||
};
|
|
||||||
|
|
||||||
const [createComponent, bem, t] = createNamespace('address-list');
|
|
||||||
|
|
||||||
function AddressList(
|
|
||||||
h: CreateElement,
|
|
||||||
props: AddressListProps,
|
|
||||||
slots: AddressListSlots,
|
|
||||||
ctx: RenderContext<AddressListProps>
|
|
||||||
) {
|
|
||||||
function genList(list?: AddressItemData[], disabled?: boolean) {
|
|
||||||
if (!list) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.map((item, index) => (
|
|
||||||
<AddressItem
|
|
||||||
data={item}
|
|
||||||
key={item.id}
|
|
||||||
disabled={disabled}
|
|
||||||
switchable={props.switchable}
|
|
||||||
defaultTagText={props.defaultTagText}
|
|
||||||
scopedSlots={{
|
|
||||||
bottom: slots['item-bottom'],
|
|
||||||
}}
|
|
||||||
onSelect={() => {
|
|
||||||
emit(ctx, disabled ? 'select-disabled' : 'select', item, index);
|
|
||||||
|
|
||||||
if (!disabled) {
|
|
||||||
emit(ctx, 'input', item.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onEdit={() => {
|
|
||||||
emit(ctx, disabled ? 'edit-disabled' : 'edit', item, index);
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
emit(ctx, 'click-item', item, index);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
const List = genList(props.list);
|
|
||||||
const DisabledList = genList(props.disabledList, true);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={bem()} {...inherit(ctx)}>
|
|
||||||
{slots.top?.()}
|
|
||||||
<RadioGroup value={props.value}>{List}</RadioGroup>
|
|
||||||
{props.disabledText && (
|
|
||||||
<div class={bem('disabled-text')}>{props.disabledText}</div>
|
|
||||||
)}
|
|
||||||
{DisabledList}
|
|
||||||
{slots.default?.()}
|
|
||||||
<div class={bem('bottom')}>
|
|
||||||
<Button
|
|
||||||
round
|
|
||||||
block
|
|
||||||
type="danger"
|
|
||||||
class={bem('add')}
|
|
||||||
text={props.addButtonText || t('add')}
|
|
||||||
onClick={() => {
|
|
||||||
emit(ctx, 'add');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddressList.props = {
|
|
||||||
list: Array,
|
|
||||||
value: [Number, String],
|
|
||||||
disabledList: Array,
|
|
||||||
disabledText: String,
|
|
||||||
addButtonText: String,
|
|
||||||
defaultTagText: String,
|
|
||||||
switchable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createComponent<AddressListProps>(AddressList);
|
|
@ -327,10 +327,10 @@ module.exports = {
|
|||||||
// path: 'address-edit',
|
// path: 'address-edit',
|
||||||
// title: 'AddressEdit 地址编辑',
|
// title: 'AddressEdit 地址编辑',
|
||||||
// },
|
// },
|
||||||
// {
|
{
|
||||||
// path: 'address-list',
|
path: 'address-list',
|
||||||
// title: 'AddressList 地址列表',
|
title: 'AddressList 地址列表',
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
path: 'area',
|
path: 'area',
|
||||||
title: 'Area 省市区选择',
|
title: 'Area 省市区选择',
|
||||||
@ -661,10 +661,10 @@ module.exports = {
|
|||||||
// path: 'address-edit',
|
// path: 'address-edit',
|
||||||
// title: 'AddressEdit',
|
// title: 'AddressEdit',
|
||||||
// },
|
// },
|
||||||
// {
|
{
|
||||||
// path: 'address-list',
|
path: 'address-list',
|
||||||
// title: 'AddressList',
|
title: 'AddressList',
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
path: 'area',
|
path: 'area',
|
||||||
title: 'Area',
|
title: 'Area',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user