mirror of
https://gitee.com/vant-contrib/vant-weapp.git
synced 2025-05-29 09:49:16 +08:00
refactor(TreeSelect): refactor with sidebar (#2224)
BREAKING CHANGE: rename prop active of sidebar to activeKey
This commit is contained in:
parent
50f7540a4e
commit
e1f80b569d
@ -1,6 +1,5 @@
|
||||
<demo-block title="单选模式">
|
||||
<van-tree-select
|
||||
content-item-class="content-item-class"
|
||||
items="{{ items }}"
|
||||
main-active-index="{{ mainActiveIndex }}"
|
||||
active-id="{{ activeId }}"
|
||||
@ -11,7 +10,6 @@
|
||||
|
||||
<demo-block title="多选模式">
|
||||
<van-tree-select
|
||||
content-item-class="content-item-class"
|
||||
max="2"
|
||||
items="{{ items }}"
|
||||
main-active-index="{{ mainActiveIndexMulti }}"
|
||||
@ -23,13 +21,26 @@
|
||||
|
||||
<demo-block title="自定义内容">
|
||||
<van-tree-select
|
||||
content-item-class="content-item-class"
|
||||
items="{{ items }}"
|
||||
main-active-index="{{ mainActiveIndexMulti }}"
|
||||
active-id="{{ activeIdMulti }}"
|
||||
bind:click-item="onClickItemMulti"
|
||||
bind:click-nav="onClickNavMulti"
|
||||
items="{{ [{ text: '分组 1' }, { text: '分组 2' }] }}"
|
||||
height="55vw"
|
||||
main-active-index="{{ mainActiveIndex }}"
|
||||
active-id="{{ activeId }}"
|
||||
bind:click-item="onClickItem"
|
||||
bind:click-nav="onClickNav"
|
||||
>
|
||||
<image src="https://img.yzcdn.cn/vant/apple-1.jpg" slot="content" />
|
||||
<van-image
|
||||
wx:if="{{ mainActiveIndex === 0 }}"
|
||||
src="https://img.yzcdn.cn/vant/apple-1.jpg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
slot="content"
|
||||
/>
|
||||
<van-image
|
||||
wx:elif="{{ mainActiveIndex === 1 }}"
|
||||
src="https://img.yzcdn.cn/vant/apple-2.jpg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
slot="content"
|
||||
/>
|
||||
</van-tree-select>
|
||||
</demo-block>
|
||||
|
@ -282,6 +282,22 @@
|
||||
// Search
|
||||
@search-background-color: #f7f8fA;
|
||||
|
||||
// Sidebar
|
||||
@sidebar-width: 85px;
|
||||
|
||||
// SidebarItem
|
||||
@sidebar-font-size: @font-size-md;
|
||||
@sidebar-line-height: 20px;
|
||||
@sidebar-text-color: @text-color;
|
||||
@sidebar-disabled-text-color: @gray;
|
||||
@sidebar-padding: 20px @padding-sm 20px @padding-xs;
|
||||
@sidebar-active-color: @active-color;
|
||||
@sidebar-background-color: @background-color-light;
|
||||
@sidebar-selected-font-weight: @font-weight-bold;
|
||||
@sidebar-selected-text-color: @text-color;
|
||||
@sidebar-selected-border-color: @red;
|
||||
@sidebar-selected-background-color: @white;
|
||||
|
||||
// Stepper
|
||||
@stepper-active-color: #e8e8e8;
|
||||
@stepper-background-color: @active-color;
|
||||
@ -346,6 +362,15 @@
|
||||
@divider-content-left-width: 10%;
|
||||
@divider-content-right-width: 10%;
|
||||
|
||||
// TreeSelect
|
||||
@tree-select-font-size: @font-size-md;
|
||||
@tree-select-nav-background-color: @background-color-light;
|
||||
@tree-select-content-background-color: @white;
|
||||
@tree-select-nav-item-padding: @padding-sm @padding-xs @padding-sm @padding-sm;
|
||||
@tree-select-item-height: 44px;
|
||||
@tree-select-item-active-color: @red;
|
||||
@tree-select-item-disabled-color: @gray;
|
||||
|
||||
// Uploader
|
||||
@uploader-size: 80px;
|
||||
@uploader-icon-size: 24px;
|
||||
|
@ -1,6 +1,12 @@
|
||||
@import '../common/style/var.less';
|
||||
@import '@vant/icons/src/index.less';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.van-icon {
|
||||
&--image {
|
||||
width: 1em;
|
||||
|
@ -16,7 +16,7 @@
|
||||
bind:error="onError"
|
||||
/>
|
||||
|
||||
<div
|
||||
<view
|
||||
wx:if="{{ loading && showLoading }}"
|
||||
class="loading-class van-image__loading"
|
||||
>
|
||||
@ -29,8 +29,8 @@
|
||||
name="photo-o"
|
||||
size="22"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
</view>
|
||||
<view
|
||||
wx:if="{{ error && showError }}"
|
||||
class="error-class van-image__error"
|
||||
>
|
||||
@ -43,5 +43,5 @@
|
||||
name="warning-o"
|
||||
size="22"
|
||||
/>
|
||||
</div>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -4,40 +4,45 @@
|
||||
.van-sidebar-item {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
padding: 20px 12px 20px 9px;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
word-wrap: break-word;
|
||||
border-left: 3px solid transparent;
|
||||
user-select: none;
|
||||
.theme(color, '@gray-darker');
|
||||
.theme(background-color, '@background-color');
|
||||
.theme(padding, '@sidebar-padding');
|
||||
.theme(font-size, '@sidebar-font-size');
|
||||
.theme(line-height, '@sidebar-line-height');
|
||||
.theme(color, '@sidebar-text-color');
|
||||
.theme(background-color, '@sidebar-background-color');
|
||||
|
||||
&--hover {
|
||||
.theme(background-color, '@active-color');
|
||||
&__text {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&--hover:not(&--disabled) {
|
||||
.theme(background-color, '@sidebar-active-color');
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
&--active {
|
||||
font-weight: bold;
|
||||
.theme(color, '@text-color');
|
||||
.theme(border-color, '@red');
|
||||
&--selected {
|
||||
.theme(color, '@sidebar-selected-text-color');
|
||||
.theme(font-weight, '@sidebar-selected-font-weight');
|
||||
.theme(border-color, '@sidebar-selected-border-color');
|
||||
|
||||
&::after {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&--active,
|
||||
&--active&--hover {
|
||||
.theme(background-color, '@white');
|
||||
&--selected,
|
||||
&--selected&--hover {
|
||||
.theme(background-color, '@sidebar-selected-background-color');
|
||||
}
|
||||
|
||||
&__text {
|
||||
position: relative;
|
||||
&--disabled {
|
||||
.theme(color, '@sidebar-disabled-text-color');
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
import { VantComponent } from '../common/component';
|
||||
|
||||
VantComponent({
|
||||
classes: [
|
||||
'active-class',
|
||||
'disabled-class',
|
||||
],
|
||||
|
||||
relation: {
|
||||
type: 'ancestor',
|
||||
name: 'sidebar',
|
||||
@ -12,18 +17,19 @@ VantComponent({
|
||||
props: {
|
||||
dot: Boolean,
|
||||
info: null,
|
||||
title: String
|
||||
title: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick() {
|
||||
const { parent } = this;
|
||||
|
||||
if (!parent) {
|
||||
if (!parent || this.data.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parent.items.indexOf(this);
|
||||
const index = parent.children.indexOf(this);
|
||||
|
||||
parent.setActive(index).then(() => {
|
||||
this.$emit('click', index);
|
||||
@ -31,8 +37,8 @@ VantComponent({
|
||||
});
|
||||
},
|
||||
|
||||
setActive(active: boolean) {
|
||||
return this.setData({ active });
|
||||
setActive(selected: boolean) {
|
||||
return this.setData({ selected });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
<wxs src="../wxs/utils.wxs" module="utils" />
|
||||
|
||||
<view
|
||||
class="{{ utils.bem('sidebar-item', { active }) }} van-hairline custom-class"
|
||||
class="{{ utils.bem('sidebar-item', { selected, disabled }) }} {{ selected ? 'active-class' : '' }} {{ disabled ? 'disabled-class' : '' }} custom-class"
|
||||
hover-class="van-sidebar-item--hover"
|
||||
hover-stay-time="70"
|
||||
bind:tap="onClick"
|
||||
|
@ -1,5 +1,6 @@
|
||||
@import '../common/style/var.less';
|
||||
@import '../common/style/theme.less';
|
||||
|
||||
.van-sidebar {
|
||||
width: 85px;
|
||||
.theme(width, '@sidebar-width');
|
||||
}
|
||||
|
@ -5,17 +5,19 @@ VantComponent({
|
||||
name: 'sidebar-item',
|
||||
type: 'descendant',
|
||||
linked(target) {
|
||||
this.items.push(target);
|
||||
this.setActive(this.data.active);
|
||||
this.children.push(target);
|
||||
this.setActive(this.data.activeKey);
|
||||
},
|
||||
unlinked(target) {
|
||||
this.items = this.items.filter(item => item !== target);
|
||||
this.setActive(this.data.active);
|
||||
this.items = this.children.filter(
|
||||
(item: WechatMiniprogram.Component.TrivialInstance) => item !== target
|
||||
);
|
||||
this.setActive(this.data.activeKey);
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
active: {
|
||||
activeKey: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
observer: 'setActive'
|
||||
@ -23,28 +25,28 @@ VantComponent({
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
this.items = [];
|
||||
this.children = [];
|
||||
this.currentActive = -1;
|
||||
},
|
||||
|
||||
methods: {
|
||||
setActive(active: number) {
|
||||
const { items, currentActive } = this;
|
||||
setActive(activeKey: number) {
|
||||
const { children, currentActive } = this;
|
||||
|
||||
if (!items.length) {
|
||||
if (!children.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.currentActive = active;
|
||||
this.currentActive = activeKey;
|
||||
|
||||
const stack = [];
|
||||
|
||||
if (currentActive !== active && items[currentActive]) {
|
||||
stack.push(items[currentActive].setActive(false));
|
||||
if (currentActive !== activeKey && children[currentActive]) {
|
||||
stack.push(children[currentActive].setActive(false));
|
||||
}
|
||||
|
||||
if (items[active]) {
|
||||
stack.push(items[active].setActive(true));
|
||||
if (children[activeKey]) {
|
||||
stack.push(children[activeKey].setActive(true));
|
||||
}
|
||||
|
||||
return Promise.all(stack);
|
||||
|
@ -1,6 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"van-icon": "../icon/index"
|
||||
"van-icon": "../icon/index",
|
||||
"van-sidebar": "../sidebar/index",
|
||||
"van-sidebar-item": "../sidebar-item/index"
|
||||
}
|
||||
}
|
||||
|
@ -3,73 +3,47 @@
|
||||
|
||||
.van-tree-select {
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
user-select: none;
|
||||
.theme(font-size, '@tree-select-font-size');
|
||||
|
||||
&__nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 35%;
|
||||
min-width: 120px;
|
||||
.theme(background-color, '@background-color-light');
|
||||
}
|
||||
flex: 1;
|
||||
.theme(background-color, '@tree-select-nav-background-color');
|
||||
|
||||
&__nitem {
|
||||
position: relative;
|
||||
padding: 0 9px 0 15px;
|
||||
line-height: 44px;
|
||||
|
||||
&--active::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 3.6px;
|
||||
content: '';
|
||||
.theme(background-color, '@red');
|
||||
&__inner {
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&--active {
|
||||
font-weight: bold;
|
||||
.theme(background-color, '@white');
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
.theme(color, '@gray-dark');
|
||||
}
|
||||
--sidebar-padding: @tree-select-nav-item-padding;
|
||||
}
|
||||
|
||||
&__content {
|
||||
box-sizing: border-box;
|
||||
width: 65%;
|
||||
margin-left: 35%;
|
||||
padding-left: 15px;
|
||||
.theme(background-color, '@white');
|
||||
flex: 2;
|
||||
.theme(background-color, '@tree-select-content-background-color');
|
||||
}
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
line-height: 44px;
|
||||
|
||||
.theme(padding, '0 32px 0 @padding-md');
|
||||
.theme(line-height, '@tree-select-item-height');
|
||||
|
||||
&--active {
|
||||
.theme(color, '@red');
|
||||
.theme(color, '@tree-select-item-active-color');
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
.theme(color, '@gray-dark');
|
||||
.theme(color, '@tree-select-item-disabled-color');
|
||||
}
|
||||
}
|
||||
|
||||
&__selected {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 15px;
|
||||
bottom: 0;
|
||||
height: 24px;
|
||||
margin: auto 0;
|
||||
line-height: 24px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
.theme(right, '@padding-md');
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { VantComponent } from '../common/component';
|
||||
import { Weapp } from 'definitions/weapp';
|
||||
|
||||
const ITEM_HEIGHT = 44;
|
||||
import { addUnit } from '../common/utils';
|
||||
|
||||
VantComponent({
|
||||
classes: [
|
||||
@ -14,15 +13,20 @@ VantComponent({
|
||||
],
|
||||
|
||||
props: {
|
||||
items: Array,
|
||||
items: {
|
||||
type: Array,
|
||||
observer: 'updateSubItems'
|
||||
},
|
||||
activeId: null,
|
||||
mainActiveIndex: {
|
||||
type: Number,
|
||||
value: 0
|
||||
value: 0,
|
||||
observer: 'updateSubItems'
|
||||
},
|
||||
maxHeight: {
|
||||
type: Number,
|
||||
value: 300
|
||||
height: {
|
||||
type: [Number, String],
|
||||
value: 300,
|
||||
observer: 'updateHeight'
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
@ -31,24 +35,11 @@ VantComponent({
|
||||
},
|
||||
|
||||
data: {
|
||||
subItems: [],
|
||||
mainHeight: 0,
|
||||
itemHeight: 0
|
||||
subItems: []
|
||||
},
|
||||
|
||||
watch: {
|
||||
items() {
|
||||
this.updateSubItems().then(() => {
|
||||
this.updateMainHeight();
|
||||
});
|
||||
},
|
||||
|
||||
maxHeight() {
|
||||
this.updateItemHeight(this.data.subItems);
|
||||
this.updateMainHeight();
|
||||
},
|
||||
|
||||
mainActiveIndex: 'updateSubItems'
|
||||
created() {
|
||||
this.updateHeight();
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -57,9 +48,11 @@ VantComponent({
|
||||
const { item } = event.currentTarget.dataset;
|
||||
const isArray = Array.isArray(this.data.activeId);
|
||||
// 判断有没有超出右侧选择的最大数
|
||||
const isOverMax = isArray && (this.data.activeId.length >= this.data.max);
|
||||
const isOverMax = isArray && this.data.activeId.length >= this.data.max;
|
||||
// 判断该项有没有被选中, 如果有被选中,则忽视是否超出的条件
|
||||
const isSelected = isArray ? this.data.activeId.indexOf(item.id) > -1 : this.data.activeId === item.id;
|
||||
const isSelected = isArray
|
||||
? this.data.activeId.indexOf(item.id) > -1
|
||||
: this.data.activeId === item.id;
|
||||
|
||||
if (!item.disabled && (!isOverMax || isSelected)) {
|
||||
this.$emit('click-item', item);
|
||||
@ -68,7 +61,7 @@ VantComponent({
|
||||
|
||||
// 当一个导航被点击时
|
||||
onClickNav(event: Weapp.Event) {
|
||||
const { index } = event.currentTarget.dataset;
|
||||
const index = event.detail;
|
||||
const item = this.data.items[index];
|
||||
if (!item.disabled) {
|
||||
this.$emit('click-nav', { index });
|
||||
@ -80,26 +73,13 @@ VantComponent({
|
||||
const { items, mainActiveIndex } = this.data;
|
||||
const { children = [] } = items[mainActiveIndex] || {};
|
||||
|
||||
this.updateItemHeight(children);
|
||||
return this.set({ subItems: children });
|
||||
},
|
||||
|
||||
// 更新组件整体高度,根据最大高度和当前组件需要展示的高度来决定
|
||||
updateMainHeight() {
|
||||
const { items = [], subItems = [] } = this.data;
|
||||
const maxHeight = Math.max(
|
||||
items.length * ITEM_HEIGHT,
|
||||
subItems.length * ITEM_HEIGHT
|
||||
);
|
||||
|
||||
this.setData({ mainHeight: Math.min(maxHeight, this.data.maxHeight) });
|
||||
},
|
||||
|
||||
// 更新子项列表高度,根据可展示的最大高度和当前子项列表的高度决定
|
||||
updateItemHeight(subItems) {
|
||||
const itemHeight = Math.min(subItems.length * ITEM_HEIGHT, this.data.maxHeight);
|
||||
|
||||
return this.setData({ itemHeight });
|
||||
updateHeight() {
|
||||
this.setData({
|
||||
innerHeight: addUnit(this.data.height)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -3,29 +3,27 @@
|
||||
|
||||
<view
|
||||
class="van-tree-select"
|
||||
style="height: {{ mainHeight }}px"
|
||||
style="height: {{ innerHeight }}"
|
||||
>
|
||||
<scroll-view scroll-y class="van-tree-select__nav">
|
||||
<view
|
||||
wx:for="{{ items }}"
|
||||
wx:key="index"
|
||||
class="van-ellipsis main-item-class {{ utils.bem('tree-select__nitem', { active: mainActiveIndex === index, disabled: item.disabled }) }} {{ mainActiveIndex === index ? 'main-active-class' : '' }} {{ item.disabled ? 'main-disabled-class' : '' }}"
|
||||
data-index="{{ index }}"
|
||||
bind:tap="onClickNav"
|
||||
>
|
||||
{{ item.text }}
|
||||
</view>
|
||||
<van-sidebar bind:change="onClickNav" custom-class="van-tree-select__nav__inner">
|
||||
<van-sidebar-item
|
||||
wx:for="{{ items }}"
|
||||
wx:key="index"
|
||||
custom-class="main-item-class"
|
||||
active-class="main-active-class"
|
||||
disabled-class="main-disabled-class"
|
||||
title="{{ item.text }}"
|
||||
disabled="{{ item.disabled }}"
|
||||
/>
|
||||
</van-sidebar>
|
||||
</scroll-view>
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="van-tree-select__content"
|
||||
style="height: {{ itemHeight }}px"
|
||||
>
|
||||
<scroll-view scroll-y class="van-tree-select__content">
|
||||
<slot name="content" />
|
||||
<view
|
||||
wx:for="{{ subItems }}"
|
||||
wx:key="id"
|
||||
class="van-ellipsis van-hairline--bottom content-item-class {{ utils.bem('tree-select__item', { active: wxs.isActive(activeId, item.id), disabled: item.disabled }) }} {{ wxs.isActive(activeId, item.id) ? 'content-active-class' : '' }} {{ item.disabled ? 'content-disabled-class' : '' }}"
|
||||
class="van-ellipsis content-item-class {{ utils.bem('tree-select__item', { active: wxs.isActive(activeId, item.id), disabled: item.disabled }) }} {{ wxs.isActive(activeId, item.id) ? 'content-active-class' : '' }} {{ item.disabled ? 'content-disabled-class' : '' }}"
|
||||
data-item="{{ item }}"
|
||||
bind:tap="onSelectItem"
|
||||
>
|
||||
|
Loading…
x
Reference in New Issue
Block a user