uniapp封裝select組件


1.前言

  • 官方的picker組件不能禁用某個下拉項,所以就有了這個下拉組件
  • 組件只適配了寬屏模式,效果參照element-ui的select組件
  • demo地址:lianlizhou / ep-select

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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM