基于移动UI库VUX封装的弹框选择器

919 阅读3分钟

工作中,开发使用的移动端UI库是VUX。但是VUX的选择控件selector在手机上呈现了类原生样式,如图一,实在不太美观。并且选项太多时无法达到渐进匹配的功能。

因此,决定在VUX的基础上用x-inputx-dialog封装一个类似选择器的控件,实现弹框选择,输入渐进匹配更能,并且在样式上看起来更美观些。效果如图二。

该组件是在VUX上封装的,您的项目首先需要使用VUX依赖

自定义组件

mySelectDialog

<template>
    <div >
        <div >
            <div  class="div_box" @click="showDialog">
                <template v-if=" label ">
                    <span >{{ label }}</span>
                    <span style="float: right;height:30px;"><x-icon style="margin-top: 5px;" type="ios-arrow-forward" size="20"></x-icon></span>
                </template>
                <template v-else>
                    <span  class="placeholder">{{ placeholder }}</span>
                    <span style="float: right;height:30px;"><x-icon style="margin-top: 5px;" type="ios-arrow-forward" size="20"></x-icon></span>
                </template>
            </div>
        </div>
        <div v-transfer-dom>
            <x-dialog v-model="dialogVisible">
                <div class="dialog_header">
                    <span style="float:left;">&nbsp;{{ placeholder }}</span>
                    <span style="float: right;"><icon  name="close" scale="4" @click.native="onclickClose"></icon></span>
                </div>
                <div style="background-color: #F0F0F0;margin: 10px;">
                    <x-input placeholder="请输入搜索内容" v-model="queryValue" @on-change="queryValueChange"></x-input>
                </div>
                <div style="height: calc(50vh);overflow: auto;">
                    <ul>
                        <li v-for="(item,index) in liData" style="padding: 5px;border: 1px solid #F0F0F0;" @click="onClick_li(item)">{{ item[valueMap[1]] }}</li>
                    </ul>
                </div>
            </x-dialog>
        </div>
    </div>
</template>
import { XInput, XButton,TransferDomDirective as TransferDom, XDialog  } from 'vux'
    export default {
    props:{
        value:[String,Number,Object],
        data:Array,
        valueMap:{
            type:Array,
            default:() => ['key','label']
        },
        placeholder:{
            type:String,
            default:'请选择'
        },
    },
    directives: { TransferDom },
    components: { XInput, XButton, XDialog },
    data() {
        return {
            liData:[],
            queryValue:'',
            dialogVisible:false
        }
    },
    mounted: function() { //生命周期
        this.liData = this.data.slice(0);
    },
    computed: { //计算属性
        label(){
            if( typeof this.value === 'object'  ){
                return this.value[this.valueMap[1]];
            }else{
                let label = '';
                for( let i = 0; i < this.data.length; i++ ){
                    if( this.value == this.data[i][this.valueMap[0]] ) label = this.data[i][this.valueMap[1]];
                }	
                return label;
            }
        }
    },
    methods: { //函数
        showDialog:function(){
            this.dialogVisible = true;
        },
        onclickClose:function(){
            this.queryValue = '';
            this.dialogVisible = false;
        },
        onClick_li:function(val){
            this.queryValue = '';
            this.dialogVisible = false;
            if( typeof this.value === 'object'  ){
                this.$emit('input', val);
            }else{
                this.$emit('input', val[this.valueMap[0]]);
            }
        },
        queryValueChange:function(){
            this.liData = [];
            for( let i = 0; i < this.data.length; i++){
                if( this.data[i][this.valueMap[1]].indexOf( this.queryValue ) > -1 ){
                    this.liData.push( this.data[i] );
                }
            }
        },
    },
    created: function() {
    
    },
    watch: {
        data:function(nval,oval){
            this.liData = nval.slice(0);
        },
        value:function (nval,oval) {
            this.$emit('change', nval);
        }
    }
}
.div_box{
    background-color: #F0F0F0;
    width: 100%;
    height:50px;
    line-height: 30px;
    padding: 10px 15px;
    box-sizing: border-box;
}
.placeholder{
    color: #a9a9a9;
}
.dialog_header{
    height: 40px;
    background-color: #d81e06;
    line-height: 40px;
    color: #fff;
}

属性

参数 说明 类型 默认值
value / v-model 绑定值 string / number / object --
data 选择列表 Array --
valueMap 设置键值对映射用以自动转换接口数据, 如 ['key', 'label'] Array ['key','label']
placeholder 占位符 string 请选择

事件

事件 说明 回调参数
change 选中值发生变化时触发 目前的选中值

补充

组件的data属性,选择列表的数组目前只支持元素为{"key":1,"label":"test"}类型的对象数组,暂不支持基础数据类型的数组,如["张三","李四","王五"]

应用

v-model绑定的属性是string类型时,选择后的值为选择列表映射对象的key,而不是label。

<template>
    <div>
        <my-select-dialog v-model="department" :data="departmentData"  placeholder="请选择部门" @change="onChange"></my-select-dialog>
    </div>
</template>
<script>
    import  mySelectDialog  from './components/mySelectDialog.vue';
    export default {
        components: { mySelectDialog },
        data() {
            return {
                department:'',
                departmentData:[
                    {
                        "key":1,
                        "label":"电脑部"
                    },
                    {
                        "key":2,
                        "label":"设计部"
                    },
                    {
                        "key":3,
                        "label":"生产部"
                    }
                ],
            }
        },
        methods: { //函数
            onChange:function(val){
                console.log(val);
            }
        }
    }
</script>

设置键值对映射:

<template>
    <div>
        <my-select-dialog v-model="user" :value-map="['user_key','user_name']" :data="userData"  placeholder="请选择用户" @change="onChange"></my-select-dialog>
    </div>
</template>
<script>
    import  mySelectDialog  from './components/mySelectDialog.vue';
    export default {
        components: { mySelectDialog },
        data() {
            return {
                user:{},
                userData:[
                    {
                        "user_key":1,
                        "user_name":"管理员"
                    },
                    {
                        "user_key":2,
                        "user_name":"张三"
                    },
                    {
                        "user_key":3,
                        "user_name":"李四"
                    }
                ],
            }
        },
        methods: { //函数	
            onChange:function(val){
                console.log(val);
            },
        }
    }
</script>