feat(Cascader): select options

This commit is contained in:
chenjiahan 2020-12-20 13:52:27 +08:00 committed by neverland
parent 0352f5d9a6
commit 347758a935
6 changed files with 91 additions and 21 deletions

View File

@ -1,6 +1,7 @@
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
import Tab from '../tab'; import Tab from '../tab';
import Tabs from '../tabs'; import Tabs from '../tabs';
import Icon from '../icon';
const [createComponent, bem] = createNamespace('cascader'); const [createComponent, bem] = createNamespace('cascader');
@ -47,12 +48,40 @@ export default createComponent({
{ {
title: this.placeholder || this.t('placeholder'), title: this.placeholder || this.t('placeholder'),
options: this.options, options: this.options,
selected: null,
}, },
]; ];
} }
}, },
genHeader() { onSelect(option, tabIndex) {
this.tabs[tabIndex].title = option.text;
this.tabs[tabIndex].selected = option.value;
if (this.tabs.length > tabIndex + 1) {
this.tabs = this.tabs.slice(0, tabIndex + 1);
}
if (option.children) {
const nextTab = {
title: this.placeholder || this.t('placeholder'),
options: option.children,
selected: null,
};
if (this.tabs[tabIndex + 1]) {
this.$set(this.tabs, tabIndex + 1, nextTab);
} else {
this.tabs.push(nextTab);
}
this.$nextTick(() => {
this.activeTab++;
});
}
},
renderHeader() {
return ( return (
<div class={bem('header')}> <div class={bem('header')}>
<h2 class={bem('title')}>{this.slots('title') || this.title}</h2> <h2 class={bem('title')}>{this.slots('title') || this.title}</h2>
@ -60,23 +89,41 @@ export default createComponent({
); );
}, },
genTabs() { renderOptions(options, selected, tabIndex) {
return ( return (
<Tabs class={bem('tabs')}> <ul class={bem('options')}>
{this.tabs.map((item) => ( {options.map((option) => {
<Tab title={item.title}>{this.genOptions(item.options)}</Tab> const isSelected = option.value === selected;
))} return (
</Tabs> <li
class={bem('option', { selected: isSelected })}
onClick={() => {
this.onSelect(option, tabIndex);
}}
>
<span>{option.text}</span>
{isSelected ? (
<Icon name="success" class={bem('selected-icon')} />
) : null}
</li>
);
})}
</ul>
); );
}, },
genOptions(options) { renderTabs() {
return ( return (
<ul class={bem('options')}> <Tabs vModel={this.activeTab} animated swipeable class={bem('tabs')}>
{options.map((option) => ( {this.tabs.map((item, tabIndex) => (
<li class={bem('option')}>{option.text}</li> <Tab
title={item.title}
titleClass={bem('tab-title', { unselected: !item.selected })}
>
{this.renderOptions(item.options, item.selected, tabIndex)}
</Tab>
))} ))}
</ul> </Tabs>
); );
}, },
}, },
@ -84,8 +131,8 @@ export default createComponent({
render() { render() {
return ( return (
<div class={bem()}> <div class={bem()}>
{this.genHeader()} {this.renderHeader()}
{this.genTabs()} {this.renderTabs()}
</div> </div>
); );
}, },

View File

@ -19,10 +19,6 @@
.van-tab { .van-tab {
flex: none; flex: none;
padding: 0 10px; padding: 0 10px;
&--active {
color: #969799;
}
} }
&.van-tabs--line .van-tabs__wrap { &.van-tabs--line .van-tabs__wrap {
@ -31,19 +27,42 @@
} }
} }
&__tab-title {
color: @gray-8;
font-weight: @font-weight-bold;
&--unselected {
color: @gray-6;
}
}
&__option { &__option {
padding: 10px 16px; display: flex;
font-size: 14px; align-items: center;
line-height: 20px; justify-content: space-between;
padding: 10px @padding-md;
font-size: @font-size-md;
line-height: @line-height-md;
&:active { &:active {
background-color: @active-color; background-color: @active-color;
} }
&--selected {
color: @red;
}
}
&__selected-icon {
color: @red;
font-size: 18px;
} }
&__options { &__options {
box-sizing: border-box; box-sizing: border-box;
height: 384px; height: 384px;
padding-top: 6px; padding-top: 6px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
} }
} }

View File

@ -252,6 +252,7 @@ export default {
| to | Target route of the link, same as to of vue-router | _string \| object_ | - | | to | Target route of the link, same as to of vue-router | _string \| object_ | - |
| replace | If true, the navigation will not leave a history record | _boolean_ | `false` | | replace | If true, the navigation will not leave a history record | _boolean_ | `false` |
| title-style | Custom title style | _any_ | - | | title-style | Custom title style | _any_ | - |
| title-class | Custom title class name | _any_ | - |
### Tabs Events ### Tabs Events

View File

@ -260,6 +260,7 @@ export default {
| to | 点击后跳转的目标路由对象,同 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - | | to | 点击后跳转的目标路由对象,同 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - |
| replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` | | replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` |
| title-style | 自定义标题样式 | _any_ | - | | title-style | 自定义标题样式 | _any_ | - |
| title-class | 自定义标题类名 | _any_ | - |
### Tabs Events ### Tabs Events

View File

@ -16,6 +16,7 @@ export default createComponent({
badge: [Number, String], badge: [Number, String],
title: String, title: String,
titleStyle: null, titleStyle: null,
titleClass: null,
disabled: Boolean, disabled: Boolean,
}, },

View File

@ -372,6 +372,7 @@ export default createComponent({
title={item.title} title={item.title}
color={this.color} color={this.color}
style={item.titleStyle} style={item.titleStyle}
class={item.titleClass}
isActive={index === this.currentIndex} isActive={index === this.currentIndex}
disabled={item.disabled} disabled={item.disabled}
scrollable={scrollable} scrollable={scrollable}