首页 > 其他 > 详细

vue下拉选择组件

时间:2021-05-26 22:04:46      阅读:31      评论:0      收藏:0      [点我收藏+]

可以实现多选,联想搜索(仅单选支持)

功能展示

可联想搜索的单选

技术分享图片

 

 

 

多选

技术分享图片

 

 

 

 

 

 

 

 

使用介绍

支持从父组件传的参数有

‘redBorder‘,‘width‘,‘height‘,‘placeholder‘,‘optionList‘,‘selectOption‘,‘multiple‘,‘color‘,‘conflictList‘,‘disabled‘,‘isSearch‘——按照自己需要传入,不需要的可不传
redBorder: 边框是否变红(自己项目中做必填校验时需要,可忽略不传)——可传值  true/false
width: 文本框的长度(默认208px)——传入值示例 width="100px"
height: 文本框的高度(默认28px)——传入值示例 height="30px"
placeholder:文本框提示语(默认请选择)
optionList:下拉选择列表——传入值示例([{name: ‘下拉选项1‘,code: 1}]
selectOption: 默认选中项 ——传入值示例(单选 直接传选中项code :如1,多选则需要传选中的数组[{name: ‘下拉选项1‘,code: 1}]
multiple:是否多选——多选传true,单选传false或不传
color:文本框中文字颜色—— 传定义了颜色的类名
disabled:是否禁用——true/false
conflictList: 在项目中用来检查冲突时使用可忽略不传
isSearch: 是否支持联想搜索——true/false
 
触发到父组件可接收的方法
@input:联想搜索时input框输入时触发,可用来重新请求下拉列表
@change: 选中项发生改变时触发,可用来给选中项赋值
@visibleChange: 下拉列表收起/展开时触发 参数为true时表示展开,false表示收起(可实现点击下拉框实时获取下拉列表数据)
 
 
调用组件
// 引入组件
import selectOption from "../../../basic/selectOption";

components: { selectOption },
// 使用
        <selectOption
              :selectOption="role.code"
              :optionList="roleOption"
              placeholder="请选择角色"
              @change="selectRole"
            ></selectOption>    

// data中的变量
role:{name: ‘‘,code: ‘‘}
optionList: [{name: ‘角色1‘,code: ‘1‘}]
// methods中的方法
    // 点击选择某个角色时触发
    selectRole(val) {
      this.$set(this.role, "name", val.name);
      this.$set(this.role, "code", val.code);
    },

 

 
组件源码如下
注:由于字体颜色、字体大小、背景颜色、边框颜色、常用flex布局是直接写的公共样式库中的类名,故需样式需自己调整
<template>
    <div>
        <el-popover
        placement="bottom-start"
        :visible-arrow="false"
        :popper-class="$store.state.model == 1 ? ‘popperTop0‘ : ‘popperTop0 simpleStyle‘"
        v-model="optionShow"
        :disabled="disabled"
        trigger="click">
            <div class="selectBox rowJbAc" slot="reference" :class="[optionShow ? ‘borderMcA1‘ : ‘borderScA9‘,redBorder? ‘redBorder‘: ‘‘]" :style="{width: selectWidth,minHeight: selectHeight}">
                <!-- 复选且不为空时展示 -->
                <div class=" multipleTextBox fontScA2 fontSizeA flexRow" v-if="multiple && selectedOptions.length!=0" :class="[disabled ? ‘notAllow‘ : ‘pointer‘]">
                    <!-- <div v-for="(item,index) in selectedOptions" :class="[isConflict(2,item.code) ? ‘fontScC2‘ : ‘fontScA2‘]" :key="index">{{item.name}}</div> -->
                    <div v-for="(item,index) in selectedOptions" :key="index" class="rowAc multipleTextItem borderScN4 borderAll">
                        <div class="fontSizeA multipleText" :class="[isConflict(2,item.code) ? ‘fontScC2‘ : ‘fontScA2‘]">{{item.name}}</div>
                        <div class="icon-close-circle fontSizeA fontScN6 pointer" @click.stop="clearItem(index)"></div>
                    </div>
                    <!-- <input type="text" class="selectSearchInput fontSizeB fontScN8"  v-model="selectText" @input="inputEvent"> -->
                </div>
                <!-- 复选展示 -->
                <input type="text" @focus="inputFocus" ref="input" v-if="multiple &&selectedOptions.length==0" v-model="selectText" readonly class="input fontSizeA"  :class="{‘fontScA1‘: !color || color==‘fontScA2‘ ,‘fontScC2‘: color == ‘fontScC2‘,‘opacity‘:multiple&&selectedOptions.length!=0,‘notAllow‘:disabled }" :placeholder="selectPlaceholder">
                <!-- 单选展示 -->
                <input type="text" ref="input" v-if="!multiple" @focus="inputFocus" @blur="inputBlur" v-model="selectText" :readonly="!isSearch" class="input fontSizeA"  :class="[color? color: ‘fontScA2‘,disabled ? ‘notAllow‘ : ‘pointer‘]" :placeholder="selectPlaceholder" @input="inputEvent">
                <div class="fontSizeB fontScN5 arrowIcon rowAc" :class="[optionShow ? ‘icon-arrow-up‘ : ‘icon-arrow-down‘,disabled ? ‘notAllow‘ : ‘pointer‘]"></div>

                
            </div>
            <div class="optionWrap fontSizeA bgcScB1" :style="{minWidth: selectWidth}">
                <div class="optionItem hoverBgcScA10 rowJbAc textOver" v-for="(item,index) in optionList" :key="index"
                :class="[checkSelected(item) ? ‘fontMcA1‘ : ‘fontScA2‘]"
                @click.stop="clickOption(item)"  ref="selectInput">
                <!-- <input type="text" class="selectInputOpacity"> -->
                    {{item.name}}
                </div>
                <div v-if="optionList.length == 0" class="fontScA6 fontSizeA empty" >暂无数据</div>
            </div>
        </el-popover>
        
    </div>
    
</template>
<script>
export default {
    data() {
        return {
            selectWidth: ‘208px‘, // 选择框宽度
            selectHeight: ‘28px‘, // 选择框高度
            selectPlaceholder: ‘请选择‘, // 提示消息
            selectText: ‘‘,
            selectedOption: {name: ‘‘,code: ‘‘},// 记录当前选中的项————单选
            selectedOptions: [],// 记录当前选中的项————多选
            optionShow: false,// 选择框是否展示
            optionClick: false,// 是否点击选项
            isGetDefault: false, // 是否赋值默认数据
            oldSelectText: ‘‘, // 记录旧的输入值
        }
    },
    watch: {
        optionList(newValue) {
            // console.log(‘下拉列表:‘,newValue)
            this.setOption(‘listChange‘)
        },
        selectOption() {
            this.setOption(‘‘)
        },
        optionShow() {
            this.$emit(‘visibleChange‘,this.optionShow)
            if(this.optionShow) { // 滚动到对应的位置
                // this.$refs.input.focus()
                if(!this.multiple && this.selectedOption.name) {
                    setTimeout(()=>{
                        var idx = this.optionList.findIndex(item =>{return item.code == this.selectedOption.code})
                        if(idx != -1 && this.$refs.selectInput && this.$refs.selectInput[idx]) {
                            // this.$refs.selectInput[idx].focus()
                            this.$refs.selectInput[idx].scrollIntoView()
                        }
                    },20)
                    
                }
            }else {
                if(this.isSearch && this.$refs.input) {
                    this.$refs.input.blur()
                }
            }
        },
    },
    created() {
        this.$bus.$on(‘changeSelect‘)
    },
    // width ————宽度
    // placeholder———— 提示
    // optionList————选项列表{name: ‘‘,code: ‘‘}
    // selectOption————选中项
    props: [‘redBorder‘,‘width‘,‘height‘,‘placeholder‘,‘optionList‘,‘selectOption‘,‘multiple‘,‘color‘,‘conflictList‘,‘disabled‘,‘isSearch‘],
    mounted() {
        this.setOption(‘‘)
    },
    methods: {
        inputFocus() {
            
        },
        // input框失焦
        inputBlur() {
            this.selectText = this.selectedOption.name
            this.optionShow = false
        },
        //  点击选项选中
        clickOption(item) {
            // console.log(‘clickOption‘)
            this.optionClick = true
            if(this.multiple) { // 多选
                var idx = this.selectedOptions.findIndex(option => {return option.code == item.code})
                if(idx == -1) {
                    this.selectedOptions.push(item)
                }else {
                    this.selectedOptions.splice(idx,1)
                    
                }
                // this.selectedOptions.forEach((option,index) => {
                //     if(index == 0) {
                //         this.selectText = option.name
                //     }else {
                //         this.selectText += `,${option.name}`
                //     }
                // })
                this.$emit(‘change‘,this.selectedOptions)
            }else { // 单选
                this.optionShow = false
                this.selectText = item.name
                this.$set(this.selectedOption,‘name‘,item.name)
                this.$set(this.selectedOption,‘code‘,item.code)
                this.$emit(‘change‘,this.selectedOption)
            }
            
        },
        checkSelected(item) {
            
            if(this.multiple) { // 多选
                return this.selectedOptions.some((option) => {return item.code == option.code})
            }else { // 单选
                return item.code === this.selectedOption.code
            }

        },
        // 检查是否冲突
        isConflict(type,id) {
            if(!this.conflictList) {
                return false
            }
            return this.conflictList.some( item => { return item.type == type && item.id ==id })
        },
        // 赋值
        setOption(type) {
            // 判断父页面有无传对应的值
            if(this.width) {
                this.selectWidth = this.width
            }
            if(this.height) {
                this.selectHeight = this.height
            }
            if(this.placeholder) {
                this.selectPlaceholder = this.placeholder
            }
            // 有选中项
            if(type != ‘listChange‘ || !this.isGetDefault) {
                if(this.selectOption && this.selectOption != ‘‘) {

                    if(this.multiple) { // 多选
                        this.selectedOptions = []
                        this.selectOption.forEach((item,index) => {
                            // if(index == 0) {
                            //     this.selectText = item.name
                            // }else {
                            //     this.selectText += `,${item.name}`
                            // }
                            var idx = this.optionList.findIndex(option => {return option.code == item.code})
                            if(idx != -1) {
                                this.selectedOptions.push(this.optionList[idx])
                                
                            }
                        })
                    }else { // 单选
                    
                        var idx = this.optionList.findIndex(item => {return item.code == this.selectOption }) 
                        if(idx != -1) {
                            this.selectText = this.optionList[idx].name
                            this.$set(this.selectedOption,‘name‘,this.optionList[idx].name)
                            this.$set(this.selectedOption,‘code‘,this.optionList[idx].code)
                        }
                    }
                }else if(this.selectOption === 0) {
                    var idx = this.optionList.findIndex(item => {return item.code == this.selectOption }) 
                    if(idx != -1) {
                        this.selectText = this.optionList[idx].name
                        this.$set(this.selectedOption,‘name‘,this.optionList[idx].name)
                        this.$set(this.selectedOption,‘code‘,this.optionList[idx].code)
                    }
                }else {
                    if(!this.multiple) {
                        this.selectText = ‘‘
                        this.selectedOption = {name: ‘‘,code: ‘‘}
                    }else {
                        this.selectedOptions = []
                    }
                }
                this.isGetDefault = true
            }
            
        },
        inputEvent() {
            if(this.oldSelectText != this.selectText) {
                this.oldSelectText = this.selectText
                this.$emit(‘input‘,this.selectText)
            }
            
        },
        // 删除某个多选项
        clearItem(index) {
            console.log(‘sleectOption:‘,index,this.selectOption)
            this.selectedOptions.splice(index,1)
            this.$emit(‘change‘,this.selectedOptions)
        }

    }
}
</script>
<style lang="scss" scoped>
.selectSearchInput {
    flex: 1;
    min-width: 80px;
    border: none;
    outline: none;
}
.opacity {
    opacity: 0;
    position: absolute;
    top: 0;
    left: 0;
}
.multipleTextBox {
    flex-wrap: wrap;
    flex: 1;
    padding: 0 4px 0 8px;
    min-height: 26px;
}
.multipleTextItem {
    min-height: 20px;
    line-height: 20px;
    padding: 0 4px;
    margin-top: 2px;

    margin-bottom: 2px;
    box-sizing: border-box;
    border-radius: 2px;
    margin-right: 4px;
}
.multipleText {
    margin-right: 2px;
}
.optionWrap::-webkit-scrollbar{
    width:4px;
    height:4px;

}
.selectBox {
    position: relative;
    border-width: 1px;
    border-style: solid;
    border-radius: 4px;
    box-sizing: border-box;
    outline: none;
    .input {
        min-height: 26px;
        border-radius: 4px;
        line-height: 26px;
        text-indent: 8px;
        border: none;
        flex: 1;
        outline: none;
    }
    .arrowIcon {
        min-height: 26px;
        height: 100%;
        padding: 0 10px;
    }
    
}
.empty {
    height: 28px;
    line-height: 28px;
    text-align: center;
}
.optionWrap {
    // position: absolute;
    max-height: 300px;
    overflow: auto;
    // top: 28px;
    // left: 0px;
    // z-index: 4;
    // width: 100%;
    // padding: 2px 12px 12px;
    box-sizing: border-box;
    // border-style: solid;
    // border-width: 1px;
    border-radius: 4px;
}
.optionItem {
    position: relative;
    padding: 0 8px;
    box-sizing: border-box;
    // margin-top: 10px;
    height: 28px;
    border-radius: 5px;
    flex: 1;
    cursor: pointer;
}
// .selectInputOpacity {
//     width: 0px;
//     height: 0px;
//     opacity: 0;
//     position: absolute;
//     top: 0;
//     left: 0;
//     border: none;
//     outline: none;
// }


</style>

 

 

vue下拉选择组件

原文:https://www.cnblogs.com/pyx-blog/p/14814571.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!