美文网首页
2022-01-29 业务需求封装一个antd-vue的下拉输

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

作者: _DevilTimer | 来源:发表于2022-01-29 22:04 被阅读0次

    我们先来看效果

    点击获取焦点时


    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>
    

    相关文章

      网友评论

          本文标题:2022-01-29 业务需求封装一个antd-vue的下拉输

          本文链接:https://www.haomeiwen.com/subject/utbfkrtx.html