[微信小程序]自定义组件—下拉选择
小程序项目中需要使用下拉框组件 本想使用原生选择器 但是需求必须完全还原设计图 无奈参考网上各路大神 记录一下自定义组件
第一步在json中需要配置:
component 为 true 设为自定义组件
singComponent 作为引用组件的页面的json的声明配置项,值为引用的组件路径。
JSON
// An highlighted block
{
"component": true,
"usingComponent": {}
}
wxml中写组件的基本结构和需要绑定的属性,值和事件
tapDistrictNav : 下拉框折叠事件
selectDistrictLeft : 区域下拉联动父级事件
selectItems : 选中值的点击方法
data-nav: 用来判断当前下拉框的值
data-model : 具体值
ps:这里没有进行代码精简优化 算是比较糙的一版 后期可以改进一下
WXML
// An highlighted block
<view class="nav">
<view class="nav-child {{folding_open1? 'active' : ''}}" bindtap="tapDistrictNav" hidden='{{dropDownMenuDistrictData.length > 0 ? false :true}}' data-nav="{{dropDownMenuTitle[0]}}">
<view class="nav-title">{{district_right_select_name.length > 0 ?district_right_select_name : dropDownMenuTitle[0]}}</view>
<view class="icon"></view>
</view>
<view class="nav-child borders {{folding_open2? 'active' : ''}}" bindtap="tapDistrictNav" hidden='{{dropDownMenuSourceData.length > 0 ? false : true}}' data-nav="{{dropDownMenuTitle[1]}}">
<view class="nav-title">{{selected_source_name.length > 0 ?selected_source_name : dropDownMenuTitle[1]}}</view>
<view class="icon"></view>
</view>
<view class="nav-child borders-right {{folding_open3? 'active' : ''}}" bindtap="tapDistrictNav" hidden='{{dropDownMenuStyleData.length > 0 ? false : true}}' data-nav="{{dropDownMenuTitle[2]}}">
<view class="nav-title">{{selected_style_name.length > 0 ?selected_style_name : dropDownMenuTitle[2]}}</view>
<view class="icon"></view>
</view>
<view class="nav-child {{folding_open4 ? 'active' : ''}}" bindtap="tapDistrictNav" hidden='{{dropDownMenuFilterData.length > 0 ? false : true}}' data-nav="{{dropDownMenuTitle[3]}}">
<view class="nav-title">{{selected_filter_name.length > 0 ?selected_filter_name : dropDownMenuTitle[3]}}</view>
<view class="icon"></view>
</view>
</view>
<view class="district {{folding_open1 ? 'show' : 'disappear'}} ">
<view class="half half-left">
<view
class="{{district_left_select == item.id ? 'current_left_select' : ''}}"
wx:for="{{dropDownMenuDistrictData}}"
bindtap="selectDistrictLeft"
data-model='{{item}}'
wx:key="unique">
{{item.title}}
</view>
</view>
<view class="half half-right">
<view
class="{{district_right_select == item.id ? 'current_right_select' : ''}}"
wx:for="{{dropDownMenuDistrictDataRight}}"
bindtap="selectItems"
data-model='{{item}}'
data-nav="{{dropDownMenuTitle[0]}}"
wx:key="unique">
{{item.title}}
</view>
</view>
</view>
<view class="container container_hd {{folding_open2 ? 'show' : 'disappear'}} ">
<view class='z-height'>
<view>
<block wx:for="{{dropDownMenuSourceData}}" wx:key="unique">
<view
class="sortitem {{selected_source_id==item.id ? ' active ' : ' '}}"
data-model='{{item}}'
data-nav="{{dropDownMenuTitle[1]}}"
bindtap='selectItems'>
{{item.title}}
</view>
</block>
</view>
</view>
</view>
<view class="container container_hd {{folding_open3 ? 'show' : 'disappear'}} ">
<view class='z-height'>
<view>
<block wx:for="{{dropDownMenuStyleData}}" wx:key="unique">
<view
class="sortitem {{selected_style_id==item.id ? ' active ' : ' '}}"
data-model='{{item}}'
data-nav="{{dropDownMenuTitle[2]}}"
bindtap='selectItems'>
{{item.title}}
</view>
</block>
</view>
</view>
</view>
<view class="container container_hd {{folding_open4 ? 'show' : 'disappear'}} ">
<view class='z-height'>
<view>
<block wx:for="{{dropDownMenuFilterData}}" wx:key="unique">
<view
class="sortitem {{selected_filter_id==item.id ? ' active ' : ' '}}"
data-model='{{item}}'
data-nav="{{dropDownMenuTitle[3]}}"
bindtap='selectItems'>
{{item.title}}
</view>
</block>
</view>
</view>
</view>
wxss样式不多说 没什么需要改动 引用时可以用margin或者定位改变在父组件位置
WXSS
// An highlighted block
.page {
width: 100%;
height: 100%;
background: #fff;
overflow: hidden;
}
.position {
position: absolute;
}
.nav {
position: relative;
z-index: 99;
display: flex;
border-bottom: 1px solid #f7f7f7;
background: #fff;
}
.nav-child {
display: flex;
flex: 1;
text-align: center;
height: 48rpx;
align-items: center;
justify-content: center;
font-size: 24rpx;
margin: 20rpx 0;
}
.borders-right {
border-right: 1px solid #e6e6e6;
}
.borders-left {
border-left: 1px solid #e6e6e6;
}
.borders {
border-left: 1px solid #e6e6e6;
border-right: 1px solid #e6e6e6;
}
.nav-title {
display: inline-block;
}
.icon {
display: inline-block;
border: 4px solid transparent;
border-top: 4px solid #9b9b9b;
margin-left: 5px;
margin-top: 10rpx;
}
.container {
position: relative;
z-index: 4;
font-size: 14px;
}
.slidedown {
transform: translateY(0%);
}
.district {
position: absolute;
display: none;
z-index: 5;
width: 100%;
height: 100%;
overflow-y: scroll;
background-color: rgba(0, 0, 0, 0.5);
}
.district .half {
overflow-y: scroll;
float: left;
width: 50%;
height: 600rpx;
line-height: 80rpx;
box-sizing: border-box;
font-size: 14px;
}
.half view {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
padding-left: 15rpx;
}
.half-left {
background: #f7f7f7;
}
.half-center {
background: #fff;
}
.half-right {
background: #fff;
}
.half-right view {
border-bottom: 1px solid #f7f7f7;
}
.current_left_select {
background: #fff;
}
.current_right_select {
background: #fff;
color: #E22317;
}
.nav-child.active .nav-title {
color: #E22317;
}
.nav-child.active .icon {
border-bottom: 4px solid #E22317;
border-top: 0;
}
@keyframes slidown {
from {
transform: translateY(-100%);
}
to {
transform: translateY(0%);
}
}
.slidown {
display: block;
animation: slidown 0.2s ease-in both;
}
@keyframes slidup {
from {
transform: translateY(0%);
}
to {
transform: translateY(-100%);
}
}
.z-height {
overflow-y: scroll;
background: #fff;
}
.slidup {
display: block;
animation: slidup 0.2s ease-in both;
}
.disappear {
display: none;
}
.show {
display: block;
}
.slidowntop {
display: flex;
flex-direction: row;
padding: 20rpx 24rpx 10rpx 24rpx;
}
.emptyall {
margin-left: 475rpx;
color: #E22317;
}
.emptyallright {
width: 80rpx;
text-align: center;
}
.endselect {
width: 350rpx;
text-align: left;
}
.return {
margin-left: 200rpx;
color: #E22317;
}
.slidowncenter {
margin-top: 20rpx;
padding-top: 20rpx;
padding-left: 24rpx;
display: flex;
flex-direction: row;
align-content: space-between;
border-top: solid #d1d3d4 1rpx;
}
.slidownbottom {
margin-top: 10rpx;
padding: 10rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sortitem {
border-bottom: solid #f7f7f7 1rpx;
justify-content: space-between;
padding: 20rpx 30rpx;
}
.sortitem.active {
color: #E22317;
}
.container_hd {
width: 100%;
height: 100%;
position: absolute;
overflow-y: scroll;
background-color: rgba(0, 0, 0, 0.5);
}
组件js 同wxml 代码比较糙 因为开始假设区域是静态数据 所以方法有待改进 可以只传一个当前行政区划代码 在组件里进行请求 获取数据
JS
// An highlighted block
Component({
properties: {
dropDownMenuTitle: {
type: Array,
value: [],
},
dropDownMenuDistrictData: {
type: Array,
value: [],
observer: function(newVal, oldVal) {
console.log(newVal,oldVal)
let model = newVal[0] ? newVal[0] : null
this.selectDefaltDistrictLeft(model)
}
},
dropDownMenuSourceData: {
type: Array,
value: []
},
dropDownMenuStyleData: {
type: Array,
value: []
},
dropDownMenuFilterData: {
type: Array,
value: []
},
},
data: {
// private properity
folding_open1:false, //区域
folding_open2:false, //来源
folding_open3:false, //租售状态
folding_open4:false, //排序
shownavindex: '',
dropDownMenuDistrictDataRight: {},
district_left_select: '',
district_right_select: '',
district_right_select_name: '',
selected_style_id: 0,
selected_style_name: '',
selected_source_id: 0,
selected_source_name: '',
selected_filter_id: 0,
selected_filter_name: '',
},
methods: {
//全部折叠
foldingSetData(){
this.setData({
folding_open1: false,
folding_open2: false,
folding_open3: false,
folding_open4: false,
shownavindex: 0
})
},
//收起展开
tapDistrictNav: function(e) {
// console.log(e)
let navId = e.currentTarget.dataset.nav;
let navName = e._relatedInfo.anchorTargetText
// console.log("nav",navId)
if (this.data.folding_open1 || this.data.folding_open2 || this.data.folding_open3 || this.data.folding_open4) {
this.foldingSetData()
}else{
switch(true) {
case navId == '区域':
this.setData({
folding_open1: true,
shownavindex: e.currentTarget.dataset.nav
})
break;
case navId == '来源':
this.setData({
folding_open2: true,
shownavindex: e.currentTarget.dataset.nav
})
break;
case navId == '租售':
this.setData({
folding_open3: true,
shownavindex: e.currentTarget.dataset.nav
})
break
case navId == '排序':
this.setData({
folding_open4: true,
shownavindex: e.currentTarget.dataset.nav
})
break
default:
this.foldingSetData()
}
}
// console.log(e)
},
selectDefaltDistrictLeft(model) {
if (!model) {
return
}
var model = model.childModel;
// console.log("model",model)
var selectedId = model.id
var selectedTitle = model.title;
this.setData({
dropDownMenuDistrictDataRight: model ? model : '',
district_left_select: selectedId,
district_right_select: '',
})
},
//
selectDistrictLeft: function(e) {
var model = e.target.dataset.model.childModel;
var selectedId = e.target.dataset.model.id
var selectedTitle = e.target.dataset.model.title;
this.setData({
dropDownMenuDistrictDataRight: model ? model : '',
district_left_select: selectedId,
district_right_select: '',
})
},
// 提炼代码
selectItems(e){
console.log(e)
let navId = e.currentTarget.dataset.nav;
let selectedId = e.target.dataset.model.id
let selectedTitle = e.target.dataset.model.title;
this.closeHyFilter();
if(navId == '区域'){
this.setData({
district_right_select: selectedId,
district_right_select_name: selectedTitle
})
}else if(navId == '来源'){
this.setData({
selected_source_id: selectedId,
selected_source_name: selectedTitle
})
}else if(navId == '租售'){
this.setData({
selected_style_id: selectedId,
selected_style_name: selectedTitle
})
}else if(navId == '排序'){
this.setData({
selected_filter_id: selectedId,
selected_filter_name: selectedTitle
})
}
this.triggerEvent("selectedItem", {
index: this.data.shownavindex,
selectedId: selectedId,
selectedTitle: selectedTitle
})
},
/*关闭筛选 */
closeHyFilter: function() {
if (this.data.folding_open1 || this.data.folding_open2 || this.data.folding_open3 || this.data.folding_open4) {
this.foldingSetData()
}
},
},
//组件生命周期函数,在组件实例进入页面节点树时执行
attached: function() {
},
})