Select组件完整代码
wxml
html
<view class="dropdown_component dropdown_wrapper" catch:tap="toggleDropdown">
<slot></slot>
<view
wx:if="{{showSelectText}}"
class="dropdown_sel_text custom_option_select_class"
>{{triggerText}}</view
>
<slot name="slot_right"></slot>
<!-- 选项列表 -->
<!-- 这里需要动态计算展开后的高度,否则动画上会出现意料之外的效果 -->
<scroll-view
scroll-y="{{true}}"
class="dropdown_options custom_options_class {{showDropdown?'show':'hide'}}"
style="height: {{showDropdown ? options.length * 76 : 0}}rpx;"
>
<view
class="dropdown_option custom_option_class {{item.value === value ? 'active' : ''}}"
style="{{ item.value === value ? 'color:' + activeColor : '' }}"
wx:for="{{ options }}"
wx:key="value"
catch:tap="selectOption"
data-value="{{ item.value }}"
>
{{ item.text }}
</view>
</scroll-view>
</view>
js
js
/**
* Select 下拉组件
* - 可联动:在组件上设置`class`和`classSelector`两个属性
*/
Component({
options: {
multipleSlots: true, // 在组件定义时的选项中启用多slot支持
},
/**
* 组件:<custom-component class="custom_options_class"></custom-component>
* 页面:<custom-component custom_options_class="red-text" />
*/
externalClasses: ["custom_options_class", "custom_option_select_class"],
properties: {
value: {
type: [String, Number],
optionalTypes: [null, undefined],
value: "",
observer(newV, oldV) {
if (this.properties.options.length) {
this.updateOptionText(newV);
}
},
},
options: {
type: Array,
value: [],
observer(newV, oldV) {
if (newV.length) {
this.updateOptionText(this.properties.value);
}
},
},
showSelectText: {
type: Boolean,
value: true,
},
activeColor: {
type: String,
value: "#000000",
},
/**
* 若要做到展开新的,关闭其它已经展开的组件,需要在使用组件时设置 `class`和`classSelector`两个属性
* 例如:<dropdown class="dd_comp" classSelector=".dd_comp" />
* 这样才会产生联动效果,具体实现见 `closeBrothers` 方法
*/
classSelector: {
type: String,
optionalTypes: [null, undefined],
value: "",
},
},
data: {
showDropdown: false,
},
lifetimes: {
attached() {},
ready() {},
},
methods: {
closeBrothers() {
if (!this.properties.classSelector) {
return;
}
// 获取组件使用者,相当于拿到兄弟组件的关联容器
let owner = this.selectOwnerComponent();
// 获取所有兄弟组件实例
let brothers = owner.selectAllComponents(this.properties.classSelector);
if (brothers.length) {
brothers.map((compItem) => {
// 关闭当前状态是“展开”的组件
if (compItem.data.showDropdown) {
compItem.close();
}
});
}
},
/**
* 切换“展开”、“关闭”
*/
toggleDropdown() {
if (this.data.showDropdown) {
this.close();
} else {
// 关闭其它打开的dropdown组件
this.closeBrothers();
this.open();
}
},
open() {
this.setData({
showDropdown: true,
});
},
close() {
this.setData({
showDropdown: false,
});
},
selectOption(event) {
const { value } = event.currentTarget.dataset;
this.triggerEvent(
"onchange",
{
value,
option: this.getSelOption(value),
},
{}
);
this.updateOptionText(value);
this.toggleDropdown();
},
/**
* 更新选中后展示的选项文字,并通知父组件更新menu展示项的title
* @param {*} value
*/
updateOptionText(value) {
this.setData({
triggerText: this.getSelOption(value)?.text || "",
});
},
/**
* 更新根据value选中项后,展示的title文字
* @param {*} value
*/
getSelOption(value) {
const option = this.properties.options.find(
(item) => item.value === value
);
return option || {};
},
},
});
wxss
css
.dropdown_wrapper {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.dropdown_options {
overflow: visible !important;
position: absolute;
top: calc(100% + 20rpx);
right: 0;
min-width: 60px;
max-width: 150px;
z-index: 1001;
background-color: #fff;
padding: 0;
transition: all 0.2s ease-out;
border-radius: 16rpx;
border-left: solid 1rpx #f1f1f1;
border-right: solid 1rpx #f1f1f1;
box-sizing: border-box;
}
.show {
/* height: xxx; 实时计算 */
max-height: 400rpx;
border-top: solid 1rpx #f1f1f1;
border-bottom: solid 1rpx #f1f1f1;
box-shadow: 0 0 18rpx 10rpx #f1f1f1;
}
.show::before {
content: "";
/* border: solid 20rpx transparent;
border-bottom: solid 30rpx #fdd000; */
height: 26rpx;
width: 26rpx;
background-color: #fff;
box-shadow: -10rpx -10rpx 18rpx 0 #f1f1f1;
position: absolute;
top: -10rpx;
left: 50%;
transform: translateX(-50%) rotate(45deg);
z-index: 0;
}
.hide {
height: 0;
max-height: 0;
border-top: none;
border-bottom: none;
}
.dropdown_option {
text-align: center;
padding: 20rpx;
font-size: 26rpx;
}
.dropdown_option:nth-child(2n) {
border-top: solid 1rpx #ccc;
border-bottom: solid 1rpx #ccc;
}
.dropdown_sel_text {
font-size: 30rpx;
color: #000;
}
.dropdown_sel_text {
font-size: 30rpx;
color: #000;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
}