mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[improvement] TreeSelect: tsx (#2803)
This commit is contained in:
parent
0ddafc77d8
commit
9c1248db9a
@ -1,100 +0,0 @@
|
|||||||
import { use } from '../utils';
|
|
||||||
import Icon from '../icon';
|
|
||||||
|
|
||||||
const [sfc, bem] = use('tree-select');
|
|
||||||
|
|
||||||
export default sfc({
|
|
||||||
props: {
|
|
||||||
items: Array,
|
|
||||||
mainActiveIndex: Number,
|
|
||||||
activeId: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: Number,
|
|
||||||
default: 300
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
subItems() {
|
|
||||||
const selectedItem = this.items[this.mainActiveIndex] || {};
|
|
||||||
return selectedItem.children || [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
onClickNav(data, index) {
|
|
||||||
if (!data.disabled) {
|
|
||||||
this.$emit('navclick', index);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onItemSelect(data) {
|
|
||||||
if (!data.disabled) {
|
|
||||||
this.$emit('itemclick', data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render(h) {
|
|
||||||
const {
|
|
||||||
height,
|
|
||||||
items,
|
|
||||||
mainActiveIndex,
|
|
||||||
activeId,
|
|
||||||
subItems
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={bem()} style={{ height: height + 'px' }}>
|
|
||||||
<div class={bem('nav')}>
|
|
||||||
{items.map((item, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
class={[
|
|
||||||
'van-ellipsis',
|
|
||||||
bem('nitem', {
|
|
||||||
active: mainActiveIndex === index,
|
|
||||||
disabled: item.disabled
|
|
||||||
})
|
|
||||||
]}
|
|
||||||
onClick={() => {
|
|
||||||
this.onClickNav(item, index);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{ item.text }
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div class={bem('content')}>
|
|
||||||
{subItems.map(item => (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
class={[
|
|
||||||
'van-ellipsis',
|
|
||||||
bem('item', {
|
|
||||||
active: activeId === item.id,
|
|
||||||
disabled: item.disabled
|
|
||||||
})
|
|
||||||
]}
|
|
||||||
onClick={() => {
|
|
||||||
this.onItemSelect(item);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{ item.text }
|
|
||||||
{activeId === item.id && (
|
|
||||||
<Icon
|
|
||||||
name="checked"
|
|
||||||
size="16px"
|
|
||||||
class={bem('selected')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
105
packages/tree-select/index.tsx
Normal file
105
packages/tree-select/index.tsx
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { use } from '../utils';
|
||||||
|
import { emit, inherit } from '../utils/functional';
|
||||||
|
import Icon from '../icon';
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { CreateElement, RenderContext } from 'vue/types';
|
||||||
|
import { DefaultSlots } from '../utils/use/sfc';
|
||||||
|
|
||||||
|
export type TreeSelectItem = {
|
||||||
|
text: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children: TreeSelectChildren[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TreeSelectChildren = {
|
||||||
|
id: number;
|
||||||
|
text: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TreeSelectProps = {
|
||||||
|
height: number;
|
||||||
|
items: TreeSelectItem[];
|
||||||
|
activeId: number | string;
|
||||||
|
mainActiveIndex: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [sfc, bem] = use('tree-select');
|
||||||
|
|
||||||
|
function TreeSelect(
|
||||||
|
h: CreateElement,
|
||||||
|
props: TreeSelectProps,
|
||||||
|
slots: DefaultSlots,
|
||||||
|
ctx: RenderContext<TreeSelectProps>
|
||||||
|
) {
|
||||||
|
const { height, items, mainActiveIndex, activeId } = props;
|
||||||
|
|
||||||
|
const selectedItem = items[mainActiveIndex] || {};
|
||||||
|
const subItems = selectedItem.children || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={bem()} style={{ height: `${height}px` }} {...inherit(ctx)}>
|
||||||
|
<div class={bem('nav')}>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
class={[
|
||||||
|
'van-ellipsis',
|
||||||
|
bem('nitem', {
|
||||||
|
active: mainActiveIndex === index,
|
||||||
|
disabled: item.disabled
|
||||||
|
})
|
||||||
|
]}
|
||||||
|
onClick={() => {
|
||||||
|
if (!item.disabled) {
|
||||||
|
emit(ctx, 'navclick', index);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.text}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div class={bem('content')}>
|
||||||
|
{subItems.map(item => (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
class={[
|
||||||
|
'van-ellipsis',
|
||||||
|
bem('item', {
|
||||||
|
active: activeId === item.id,
|
||||||
|
disabled: item.disabled
|
||||||
|
})
|
||||||
|
]}
|
||||||
|
onClick={() => {
|
||||||
|
if (!item.disabled) {
|
||||||
|
emit(ctx, 'itemclick', item);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.text}
|
||||||
|
{activeId === item.id && (
|
||||||
|
<Icon name="checked" size="16px" class={bem('selected')} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeSelect.props = {
|
||||||
|
items: Array,
|
||||||
|
mainActiveIndex: Number,
|
||||||
|
activeId: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 300
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default sfc<TreeSelectProps>(TreeSelect);
|
@ -6,10 +6,12 @@ test('empty list', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('select item', () => {
|
test('select item', () => {
|
||||||
|
const onItemClick = jest.fn();
|
||||||
const item = {
|
const item = {
|
||||||
text: 'city1',
|
text: 'city1',
|
||||||
id: 1
|
id: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = mount(TreeSelect, {
|
const wrapper = mount(TreeSelect, {
|
||||||
propsData: {
|
propsData: {
|
||||||
items: [{
|
items: [{
|
||||||
@ -19,12 +21,17 @@ test('select item', () => {
|
|||||||
{ ...item, disabled: true }
|
{ ...item, disabled: true }
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
on: {
|
||||||
|
itemclick: onItemClick
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const items = wrapper.findAll('.van-tree-select__item');
|
const items = wrapper.findAll('.van-tree-select__item');
|
||||||
items.at(0).trigger('click');
|
items.at(0).trigger('click');
|
||||||
expect(wrapper.emitted('itemclick')[0][0]).toEqual(item);
|
expect(onItemClick.mock.calls[0][0]).toEqual(item);
|
||||||
items.at(1).trigger('click');
|
items.at(1).trigger('click');
|
||||||
expect(wrapper.emitted('itemclick')[1]).toBeFalsy();
|
expect(onItemClick.mock.calls[1]).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user