2022-01-29 业务需求封装一个antd-vue的下拉输入框

我们先来看效果

点击获取焦点时


image.png

选中项目后


image.png

鼠标悬浮时
image.png

获取焦点 输入内容后 支持查询功能,并提示已选功能


image.png

点击清空按钮后回到最开始的获取焦点
image.png

自动支持全选 和反选全选
image.png

原生的ANTD的 兼容原本的单选功能,
image.png

调用方式 因为我这里是循环输出,所有你只需要对应自己的变量即可

<div class="title-right">
      <slot name="right">
             <template v-for="(item, i) in btns">
                  <span :key="i" class="input-select">
                        <Ytselect v-model="form[item.keyName || 'key'+i]" @change="change(item)" :options="item.options" :tipSize="5" class="title-right_select" :mode="item.mode"/>
                  </span>
           </template>
      </slot>
 </div>

以下是设计逻辑, 大量应用ES6 语法 。

我的写组件的思路 尽量只关心输入输出的数据,内部数据预定义,并且保持多种状态。可以扩展,插槽等,尽量让开发组员只做配属数据 不做逻辑本功能的逻辑处理。

<template>
    <span :class="['kyol-Ytselect',keyName]" :style="{width}">
        <a-select :mode="mode" v-model="myValue" :open="!mode ? undefined : open" class="select" v-bind="config" v-on="events" @change="change(myValue)" show-search>
            <a-select-option value="all" v-if="mode || !isSearch">
                {{selectAllText}}
            </a-select-option>
            <template v-for="(item, i) in selectOptions">
                <a-select-option :key="i" :value="item.value" :disabled="item.disabled" v-if="!item.hide"  >
                    <slot name="innerOption" :record="item" :index="i">
                        <a-tooltip placement="top">
                            <template slot="title" v-if=" tipSize && item.label && item.label.length >= tipSize ">
                                <!-- 提示文字 -->
                                <span>{{item.label}}</span>
                            </template>
                            <!-- 正常文字 -->
                            <span>{{item.label}}</span>
                        </a-tooltip>
                    </slot>
                </a-select-option>
            </template>
        </a-select>
       <a-tooltip placement="top" v-if="mode">
            <template slot="title" v-if="showSelectors.length">
                <!-- 提示文字 -->
                <span>{{showSelectors}}</span>
            </template>
            <!-- 正常文字 -->
            <a-input v-model="inputValue" ref="input" @focus="toggle(true)" @blur="toggle(false)" :placeholder="placeholder" class="input"  allowClear @change="inputChange" @click.native="toggle(true)">
            </a-input>
        </a-tooltip>
    </span>
</template>
<script>
export default {
    /**
     * author: luowei 
     * 多功能组件优化选项框, 输入输入多选和单选的作用
     */
    name: 'Ytselect',
    model:{
        prop: 'value',
        event: 'outData'
    },
    slots:{
        innerOption: 'option 内容体显示插槽'
    },
    props: {
        value: String | Number | Array,
        keyName: String,        // 当前组件的唯一标识符
        width: String,
        mode: String | Boolean,           // 选择模式同antd
        selectAllText: {       // 全选文字设置
            type: String,
            default: '全部'
        },
        options:{           // 下拉选项组
            type: Array,
            default: Array, // [{label, value, disabled, hide : false} ]
        },
        tipSize:{          // 提示文字超过长度 则提示
            type: Number | String,
            default: 0
        },
        placeholder: {    
            type: String, default: '请选择内容'
        },
        LabelsSplit: {       // input的展示文字的分隔符
             type: String, default: '、'
        },
        config: Object,  // 其他配置属性
        events: Object,  // 其他配置函数,
    },
    data(){
        return {
            selectOptions:[],      // 本地选择下拉数组
            myValue: undefined,   // 被选中后的数据
            open: false,         // 开启下拉
            lastSelect: false,  // 上一次选择内容对比值
            selected:'',    // 选择框的内容个数
            inputValue:'',  // 输入框的内容
            isSearch: false, // 搜索状态,关闭ALL选项
        }
    },
    computed:{
        showSelectors(){
            return this.options.filter(({value}) => (this.myValue || []).includes(value) ).map( ({label}) => label).join(this.LabelsSplit)
        }
    },
    watch:{
        value:{
            handler(cval){
                this.myValue = cval
            },
            immediate: true
        },
        options:{
            handler(cval){
                this.selectOptions = cval.map(item =>({...item,disabled:false, hide: false}))
                this.mode && this.computedInputText()
            },
            immediate: true
        }
    },
    methods:{
        toggle( status ){
            // 只存在为真,则显示为空,为false时刻监听了值变化
            if(status){
                 this.inputValue = ''
                 this.selectOptions.forEach(item => item.hide = false)
            } else {
                this.computedInputText()
            }  
            this.open = status
        },
        // 监听显示被选择个数的内容
        computedInputText(){
            const length = (this.myValue ?? []).filter( value => value !== 'all').length
            this.inputValue = this.selected = length ? `已经选中${length}项目` : ''
        },
        change(){
            const { myValue,lastSelect, options} = this 
            if(this.mode){
                const allSpan = options.map( item => item.value)
                const hasAll = myValue.includes('all')  // 取值包含 全部
                const valueSize = myValue.length // 取值之后长度
                const length = options.length
                if(  !lastSelect && ( valueSize === length || hasAll)) {
                    // 累计全选
                    this.myValue =[ 'all', ...allSpan ]
                } else if( hasAll && valueSize === length ){
                    // 累计不全选
                    this.myValue = this.myValue.filter(value => value !== 'all')
                }else if(lastSelect && !hasAll){
                    this.myValue = []
                }
                this.lastSelect = this.myValue.includes('all')
                this.computedInputText()
            }
            this.throwData()
        },
        // 输入框变化
        inputChange(){
            if(this.myValue.length && this.inputValue ===''){
                // 清空操作
                this.lastSelect = false
                this.myValue = []
                this.$refs['input'].focus()
            }else {
                // 开启搜索模式
                this.selectOptions.forEach( item => item.hide = !item.label.includes(this.inputValue))
                this.isSearch = true
            }

        },
        throwData(){
            this.$emit('outData', this.myValue)
            this.$emit('change', { keyName: this.keyName, value: this.myValue})
        },
    }
    
}
</script>
<style lang="scss" scoped>
.kyol-Ytselect{
    display: inline-block;
    min-width:150px;
    width:100%;
    position: relative;
    .select{
        width:100%;
        /deep/ .ant-select-selection--multiple{
            height:35px;
            overflow: hidden;
        }
    }
    .input{
        position:absolute;
        left:0;
        right:0;
        top:0;
    }
}

</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容