一、起因
接到的项目需求,查看ui设计图后,由于微信小程序官方设计的下拉选择框不符合需求,而且常用的第三方库也没有封装类似的,所以选择自己自定义组件。在此记录一下,方便日后复用。
ui设计图如下:
微信官方提供的选择框
对比发现并不能实现我们想要的功能。
二、自定义组件
2.1 封装品牌组件
代码如下
- wxml
html
<view class="select_all_view">
<!-- 内容说明,可以没有 -->
<view class="select_title" wx:if="{{title}}">{{title}}</view>
<view class="select_view">
<!-- 输入框 -->
<view class="inputPlaceholder" bindtap="startChange">
<text class="text" wx:if='{{select}}' >{{select}}</text>
<text class="text" wx:else="{{select}}" >{{placeholder}}</text>
<view class="icon" wx:if='{{changable}}'>
<van-icon name="arrow-down" />
</view>
<view class="icon" wx:else='{{changable}}'>
<van-icon name="arrow" />
</view>
</view>
<!-- 下拉展开后的可选择内容 -->
<view class="content" wx:if='{{changable}}'>
<view class="{{item.id==selectId ? 'active':''}}" wx:for="{{selectcontent}}" wx:key="idnex" bindtap="changecontent" data-datavalue="{{item}}">
{{item.name}}
</view>
</view>
</view>
</view>
- wxss
php
/* components/select-postSale.wxss */
.select_all_view{
display: flex;
z-index: 999;
}
.select_view{
display: inline;
width: 200rpx;
height: 64rpx;
}
.select_title{
margin-right: 10rpx;
}
.inputPlaceholder{
min-width: 230rpx;
height: 64rpx;
background: #FFFFFF;
border: 2rpx solid #D9D9D9;
border-radius: 12rpx 12rpx 12rpx 12rpx;
padding: 4rpx 0rpx 10rpx 10rpx;
border-radius: 10rpx;
position: relative;
overflow:hidden;
text-overflow: ellipsis;
white-space:nowrap;
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #000000;
line-height: 33rpx;
}
.select_view .inputPlaceholder .text{
height: 40rpx;
position: relative;
top: 16rpx;
left: 12rpx;
}
.icon{
position: absolute;
right: 12rpx;
top: 20rpx;
}
.content{
position: absolute;
z-index: 999;
min-width: 200rpx;
max-height: 208rpx;
background: #FFFFFF;
box-shadow: 0rpx 12rpx 32rpx 0rpx rgba(0,0,0,0.08), 0rpx 6rpx 12rpx -8rpx rgba(0,0,0,0.12), 0rpx 18rpx 56rpx 16rpx rgba(0,0,0,0.05);
border-radius: 16rpx 16rpx 16rpx 16rpx;
opacity: 1;
margin-top: 8rpx;
padding: 20rpx;
overflow-x: hidden;
overflow-y: scroll;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content>.inputPlaceholder{
padding: 10rpx 0;
}
.select_view .active{
color:#46678d;
}
- json
php
{
"component": true,
"usingComponents": {
"van-icon": "@vant/weapp/icon/index"
}
}
- js
java
// components/select-postSale.js
Component({
properties: {
title:{
type: String,
value: ""
},
nameList: {
type: Array,
value: [],
observer: function(){
//有的时候选项组是后端获取数据来的,初始化时可能为[],所以这里使用obersver,当父组件中值改变时触发
this.processData();
}
},
nowId: {
type: Number,
value: -1
},
nowName: {
type: String,
value: "",
observer: function(){
this.setData({select: this. properties.nowName,
selectId: this.properties.nowId,});
}
},
placeholder: {
type: String,
value: ""
}
},
/**
* 页面的初始数据
*/
data: {
selectcontent: [],
changable: false, //箭头切换
select: undefined, //选中的值
selectId: undefined, //选中的id
},
methods: {
// 下拉框收起和展开
startChange(e) {
this.setData({
changable: !this.data.changable
})
},
// 选择数据后回显
changecontent(e) {
this.setData({
select: e.currentTarget.dataset.datavalue.name,
selectId: e.currentTarget.dataset.datavalue.id,
changable: false
})
this.triggerEvent("handleChange", {selectId: this.data.selectId, select: this.data.select});//向父组件传参
},
//处理数据,复制一遍,因为子组件不能直接改变父组件的传进来的值。
processData(){
let options = [];
let that = this;
this.properties.nameList.forEach((item) => {
options.push({
id: item.id,
name: item.name,
});
}); //forEach
this.setData({
selectcontent: options,
select: that.properties.nowName,
selectId: that.properties.nowId,
});
}
}
})
2.2 组件调用
在要使用组件的页面js中添加自己想要的数据
- js
html
data: {
curfId: 1,
brandList: [{name: "万达影视" ,id: 1},
{name: "金逸影视" ,id: 2},
{name: "CGV" ,id: 3}
],
curBrandName:"万达影视" ,
}
- wxml
html
<select-postSale nowId="{{curfId}}" nameList="{{brandList}}" nowName="{{curBrandName}}" placeholder="请选择品牌" bind:handleChange="changeBrand"></select-postSale>
ui设计图与效果对比
可以看到效果已经基本实现.具体细节需要优化一下