自定义下拉框组件
基于element-ui的el-input 和jquery,可做部分替换
组件代码:
<template> <div class="customSelectClass" @click.stop> <el-input :ref="refName" v-model="customLabel" readonly :class="refName" :placeholder="placeholder" @focus="inputFocus" /> <span class="el-input__suffix"> <span class="el-input__suffix-inner"> <i class="el-select__caret el-input__icon el-icon-arrow-up" :class="{'is-reverse':!showDropDown}" /> </span> </span> <div class="input-icon"> <slot name="input-icon" /> </div> <div v-show="showDropDown" :class="'dropDown-'+refName+'-scroll'" class="drop-down" :style="{'width':dropDownWidth,'height':dropDownHeight,'bottom':dropDownBottom,'top':dropDownTop}" @scroll="dropDownScrollFun"> <div v-for="(item,index) in showContentArray" :key="index" class="drop-down-item" @click="itemClick(item)"> <div class="contentDiv" :class="{'activeContent':index === selectIndex}"> <div class="content" :class="['ellipsis-' + ellipsisNumber]" v-html="item[options.label]" /> <div class="item-icon"> <slot name="item-icon" :selectRow="{$index:index,data:item}" /> </div> </div> </div> </div> </div> </template> <script> import $ from 'jquery' export default { name: 'CustomSelect', props: { // 输入框的值 value: { type: String, default: '' }, label: { // 键值 type: String, default: '' }, // 参数配置 options: { type: Object, default() { return { 'key': 'key', // 下拉框key对应的field 'label': 'label', 'value': 'value' // 下拉value对应的field } } }, // 超出省略行数 0为不省略 ellipsisNumber: { type: Number, default: 0 }, // 内容数组 item为{key:'',value:''} contentArray: { type: Array, default() { return [] } }, // 映射项ref名称 refName: { type: String, default() { return this.UUIDRandomString(32) } }, // 下拉列表最大高度 dropDownMaxHeight: { type: String, default() { return '300px' } }, // 下拉列表高度 dropDownHeight: { type: String, default() { return 'auto' } }, // 下拉列表宽度 dropDownWidth: { type: String, default() { return '250px' } }, // 输入提示 placeholder: { type: String, default: '请选择' }, // 在这个class名下就不隐藏 noHideClass: { type: String, default: 'noHideClass' } }, data() { return { showContentArray: [], // 显示的内容列表 remoteContentArray: [], // 获取的远程数据数组 customValue: '', // 自定义输入框的值 customLabel: '', // curPage: 1, // 当前页数 selectIndex: -1, // 选中下标 dropDownBottom: 0, dropDownTop: 0, scrollBottomLoadDistance: 3, // 滚动到距离底部x距离时进行加载数据 moreLoading: false, // 加载更多loading showDropDown: false // 下拉框显示标记 } }, watch: { // 监听value值变化 value: { handler(val) { // 更新输入框的值 this.customValue = val }, immediate: true }, // 监听下拉框的显示标记 showDropDown(value) { // 当前为隐藏时 跳过 if (!value) { return } this.$nextTick(() => { const brotherArray = this.$parent.$children || [] // 循环隐藏非当前项的下拉框 brotherArray.forEach(item => { item.showDropDown = !(item && item.refName !== this.refName) }) }) } }, mounted() { this.$nextTick(() => { // 给document添加点击事件 点击空白处 关闭下拉框 document.addEventListener('click', this.hideDropDown) }) }, destroyed() { // 给document移除点击事件 document.removeEventListener('click', this.hideDropDown) }, methods: { UUIDRandomString(length) { const uuid = '0123456789abcdefghijklmnopqrstuvwxyz' let text = '' for (let i = 0; i < length; i++) { text += uuid.charAt(Math.floor(Math.random() * uuid.length)) } return text }, // 下拉框滚动条监听 dropDownScrollFun(val) { // 获取下拉框对象 const scroll = document.querySelector('.dropDown-' + this.refName + '-scroll') /** * 处理div内部滚动条滚动到底部后导致 再次滚动时触发外部的滚动条 * 处理方法为: * 当前内部滚动条滚动到距离底部小于等于2px时,将其滚动条位置 重置为距离底部2px * scrollTop: 可视区域顶部与滚动条顶部的距离 * scrollHeight: 整个滚动条的高度 * clientHeight: 可视区域的高度 */ // 当前滚动条距离底部还剩2px时 if (scroll.scrollHeight - (scroll.scrollTop + scroll.clientHeight) <= 2) { // 定位到距离底部2px的位置 scroll.scrollTop = (scroll.scrollHeight - scroll.clientHeight - 2) } }, // 输入框聚焦 inputFocus() { // 显示数据 this.filterShowArray() // 获取输入框对象 // eslint-disable-next-line no-undef const inputObj = $('.customSelectClass').find('.' + this.refName) if (inputObj && inputObj.length) { // 当前输入框底部距离页面顶部的高度 const clientRectBottom = inputObj.parent()[0].getBoundingClientRect().bottom // 当前输入框的高度 const inputHeight = inputObj.parent()[0].clientHeight // 当前下拉框本身的高度 const dropDownHeightVal = Number(this.dropDownHeight.replace('px', '')) // 当前可视区域的高度 const pageHeight = document.body.clientHeight // 下拉框显示部分超出了可视区域 if ((clientRectBottom + dropDownHeightVal) > pageHeight) { // 向上偏移 下拉框本身高度 额外加2 this.dropDownBottom = (inputHeight + 2) + 'px' this.dropDownTop = 'auto' } else { // 向下偏移 下拉框本身高度 额外加2 this.dropDownBottom = 'auto' this.dropDownTop = (inputHeight + 2) + 'px' } } }, // 隐藏下拉框方法 hideDropDown() { // 如果点击的不是这个class或者这个class的子节点则隐藏 if (!($(window.event.target).closest('.' + this.noHideClass).length)) { this.showDropDown = false } }, // 过滤数据 回显 filterShowArray() { // 设置到显示值数组中 this.showContentArray = JSON.parse(JSON.stringify(this.contentArray)) this.showDropDown = this.showContentArray.length > 0 }, // 选项点击 itemClick(item) { // 赋值 this.customValue = item[this.options.value] this.customLabel = item[this.options.label] // 更新外部值 this.$emit('input', this.customValue) // 更新外部值 this.$emit('update:label', this.customLabel) // 隐藏下拉框 this.showDropDown = false } } } </script> <style lang="scss" scoped> ::v-deep .el-icon-remove{ color: #cfcfcf !important; } ::v-deep .el-input__suffix .el-select__caret.is-reverse { transform: rotate(180deg); } .customSelectClass{ position: relative; .input-icon{ cursor: pointer; position: absolute; bottom: 0; right:0; } .drop-down{ &::-webkit-scrollbar { width:4px } &::-webkit-scrollbar-thumb { background:transparent; border-radius:4px } &:hover::-webkit-scrollbar-thumb { background:hsla(0,0%,53%,.4) } &:hover::-webkit-scrollbar-track { background:hsla(0,0%,53%,.1) } width: 250px; height: 300px; overflow-y: scroll; background-color: #FFF; position: absolute; border: 2px solid #E0E4ED; box-shadow: 2px 2px 8px #d8d5d5; border-radius: 5px; left: 0; z-index: 999999; } .drop-down-item{ .contentDiv{ display: flex; align-items:center; padding-left: 0.5vw; } .contentDiv:hover{ color: #1890ff; background-color: #f5f7fa; .item-icon{ display: block; } } .item-icon{ display: none; position: absolute; right: 0; transition: 0.3s; } .activeContent{ color: #1890ff; background-color: #f5f7fa; } .content{ text-align: left; cursor: pointer; padding: 5px 0 5px 5px; } ::v-deep .dividerClass{ margin:2px 0 !important; background-color: #e2e2e2 !important; } } } </style>
使用案例
<custom-select :ref="`dropDownSickName`+item.id" v-model="item.sickName" :ref-name="`sickName`+item.id" placeholder="请选择患者" :drop-down-width="'24vw'" :drop-down-max-height="'18vw'" :options="{ key:'itemId', label:'itemName', value:'itemId' }" :content-array="itemList" />
还没有评论,来说两句吧...