1.前言
2.封裝思路
- 此組件使用了字體圖標,素材來源於iconfont
- 組件分為3個部分:輸入框容器,下拉容器,蒙版容器
- 輸入框容器:展示已選中的選項,點擊則展示下拉容器和蒙版容器
- 下拉容器:使用絕對定位,展示備選下拉項,以及相應的點擊事件
- 蒙版容器:使用fixed定位,全屏覆蓋,點擊隱藏下拉容器和自身
3.基本用法
<template>
<view class="content">
<view style="display: flex;justify-content: center;padding:10px;">
<ep-select :disabled="false" v-model="select" :options="options" @change="change"></ep-select>
</view>
</view>
</template>
<script>
export default {
data() {
return {
select: '',
options:[
{value:"1",label:"上海"},{value:"2",label:"深圳"},{value:"3",label:"廣州",disabled:true}
]
}
},
onLoad() {
},
methods: {
change(e){
console.log('select = ',this.select)
}
}
}
</script>
- 效果

4.參數說明
參數 |
類型 |
默認值 |
說明 |
value |
String,Number |
'' |
當前選中項的支持v-model |
options |
Array |
[] |
下拉選項列表,disabled屬性代表當前項禁用 |
value_key |
String |
value |
指定 Object 中 key 的值作為選擇器選中內容,以此同步給value屬性 |
label_key |
String |
label |
指定 Object 中 key 的值作為選擇器展示內容 |
參數 |
類型 |
默認值 |
說明 |
change |
EventHandle |
- |
下拉選擇切換事件 |
5.完整代碼
<template>
<view class="ep-picker-box">
<!-- 蒙版區域 開始 -->
<view class="ep-mask-box" v-show="show" @click="show=false"></view>
<!-- 蒙版區域 開始 -->
<!-- 輸入框區域 開始 -->
<view class="ep-input-box" @click="openOptions" :class="{'disabled':disabled}">
<view style="display: flex;align-items: center;min-height: 36px;">{{showLabel}}</view>
<text v-if="!show" class="iconfont icon-xiala"></text>
<text v-else class="iconfont icon-xialashang"></text>
</view>
<!-- 輸入框區域 結束 -->
<!-- 彈出的下拉區域 開始 -->
<view v-show="show" class="ep-picker-content-wrap">
<scroll-view class="ep-picker-content" :scroll-y="true">
<!-- 展示下拉項列表 開始 -->
<view v-for="item in options" :key="item[value_key]"
:class="{'disabled':item.disabled,'active':value==item[value_key]}"
class="option-item"
@click="itemClick(item)"
>{{item[label_key]}}</view>
<!-- 展示下拉項列表 結束 -->
<!-- 下拉列表為空 開始 -->
<view v-if="options.length==0" class="option-no-data">無數據</view>
<!-- 下拉列表為空 結束 -->
</scroll-view>
<text class="triangle"></text>
</view>
<!-- 彈出的下拉區域 結束 -->
</view>
</template>
<script>
export default{
data(){
return {
show: false,
left: 0,
}
},
props:{
value:{
type:[String,Number],
default:""
},
options:{
type: Array,
default: function(){
return []
}
},
value_key:{
type:String,
default:"value"
},
label_key:{
type:String,
default:"label"
},
disabled:{
type:Boolean,
default:false
}
},
model:{
prop:'value',
event:"valChange"
},
methods:{
//點擊選中選項
itemClick(item){
if(item.disabled) return
//關閉
this.show = false
//修改v-model的值
this.$emit('valChange',item[this.value_key])
//將事件通知父組件
this.$emit('change',item[this.value_key])
},
//展開選項
openOptions(){
if(!this.disabled){
this.show = true
}
}
},
computed:{
showLabel(){
var index = this.options.findIndex(item=>{
return item[this.value_key] == this.value
})
if(index != -1){
return this.options[index][this.label_key]
}else if(!this.value){
return "請選擇"
}else{
return this.value
}
}
}
}
</script>
<style scoped>
/* 引入字體圖標 */
@import './iconfont.css';
.ep-picker-box{
width:100%;
box-sizing: border-box;
position: relative;
font-size: 14px;
color: #333;
max-width: 300px;
}
.ep-mask-box{
position: fixed;
z-index: 999;
top: 0;
right: 0;
left: 0;
bottom: 0;
background:none;
}
.ep-input-box{
border: 1px solid rgb(229, 229, 229);
border-radius: 4px;
padding-left:10px;
position: relative;
cursor: pointer;
}
/* 整個下拉組件禁用樣式 */
.ep-input-box.disabled{
cursor:not-allowed;
background-color: #f5f7fa;
color: #999;
}
/* 展開收起箭頭樣式 */
.ep-input-box .iconfont{
position: absolute;
top: 50%;
right: 5px;
font-size: 20px;
transform: translateY(-50%);
color:#B8B8B8;
}
/* 下拉容器樣式 外層 */
.ep-picker-content-wrap{
width: 100%;
position: absolute;
top: 45px;
left: 0;
z-index: 9999;
padding-top:6px;
}
/* 下拉容器樣式 內層 */
.ep-picker-content-wrap .ep-picker-content{
background-color: #fff;
padding:3px 0;
box-shadow: 0 0 20px 5px rgb(0 0 0 / 30%);
border-radius: 5px;
max-height:181px;
}
/* 下拉項通用樣式 */
.ep-picker-content-wrap .ep-picker-content .option-item{
padding: 8px 18px;
cursor: pointer;
}
/* 無下拉項數據時樣式 */
.ep-picker-content-wrap .ep-picker-content .option-no-data{
padding: 8px 18px;
cursor: text;
color:#999;
text-align: center;
}
/* 鼠標移入下拉項樣式 */
.ep-picker-content-wrap .ep-picker-content .option-item:hover{
background-color: #f5f7fa;
}
/* 已選中的下拉項樣式 */
.ep-picker-content-wrap .ep-picker-content .option-item.active{
color:#007AFF;
}
/* 禁用的下拉項樣式 */
.ep-picker-content-wrap .ep-picker-content .option-item.disabled{
color:#c0c4cc;
}
.ep-picker-content-wrap .ep-picker-content .option-item.disabled:hover{
cursor:not-allowed;
}
/* 下拉容器指示箭頭樣式 */
.ep-picker-content-wrap .triangle{
width: 0;
height: 0;
border-top: 6px solid rgba(0,0,0,0);
border-right: 6px solid rgba(0,0,0,0);
border-bottom: 6px solid #fff;
border-left: 6px solid rgba(0,0,0,0);
position: absolute;
top:-6px;
left:50%;
transform: translateX(-50%);
box-sizing: content-box;
}
</style>