vue⾃定义可输⼊的选择框组件
vue⾃定义可输⼊的选择框组件
props:
属性说明类型默认值selectDataList下拉框中的内容Array空数组
([])
value输⼊框中的内容String 空字符串("")
transfer是否将下拉框加⼊到body的直接⼦节点中,在 Tabs、带有 fixed 的 Table 列内使⽤时,建议添加此属性,它将不受⽗级样式影响,从⽽达到更好的效果
Boolean false placeholder输⼊框中的提⽰信息String请选择事件 events:
事件名说明返回值
inputChange在输⼊框中改变值时才会触发,js改变输⼊框绑定的值不会触发输⼊框中当前值
selectChange选择下拉框内容发⽣改变时触发当前选择的值
InputAndSelect.vue ⽂件
<style lang="scss" scoped>
.icon-unfold-transform {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
.select-dropdown {
position: absolute;
z-index: 1060;
will-change: top, left;
visibility: visible;
top: 28px;
left: 0px;
width: inherit;
max-height: 210px;
padding: 5px 0;
margin: 5px 0;
background-color: #fff;
box-sizing: border-box;
border-radius: 2px;
box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
overflow: auto;
.
select-not-found {
text-align: center;
color: #999;
}
.select-dropdown-list {
.select-item {
height: 30px;
line-height: 16px;
display: flex;
align-items: baseline;
margin: 0;
padding: 7px 12px;
clear: both;
color: #333;
font-size: 12px;
white-space: nowrap;
list-style: none;
cursor: pointer;
transition: all .2s ease-in-out;
}
}
}
.
select-input {
width: inherit;
height: 28px;
position: relative;
text-align: left;
box-sizing: border-box;
outline: 0;
background-color: #fff;
border-radius: 2px;
border: 1px solid #d7dde4;
-webkit-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;
> input {
width: 100%;
vertical-align: top;
display: inline-block;
height: 28px;
line-height: 28px;
padding: 0 24px 0 8px;
font-size: 12px;
outline: 0;
border: none;
-
webkit-box-sizing: border-box;
box-sizing: border-box;
color: #333;
background-color: transparent;
position: relative;
}
.select-arrow {
position: absolute;
right: 0;
top: -2px;
height: 28px;
line-height: 28px;
padding: 0 10px;
cursor: pointer;
> i {
font-size: 12px;
color: #9ea7b4;
transition: all .2s ease-in-out;
display: block;
}
}
}
.
select-input-color {
border-color: #3597f5;
box-shadow: 0 0 0 2px rgba(41, 141, 255, .2);
}
.select-input:hover {
border-color: #3597f5;
}
</style>
<template>
<div >
<div class="parent" >
<div class="select-input" :class="{'select-input-color':iconUnfoldClass['icon-unfold-transform']}">
<input class="inputDom" :placeholder="placeholder" v-model="value" type="text" autocomplete="off"              @input="inputChange"
>
<div @click="changeIconDirection($event)" class="select-arrow">
<i class="iconfont icon-unfold"
:class="iconUnfoldClass"></i>
</div>
</div>
<div class="select-dropdown" :>        <ul class="select-not-found" :>
<li>⽆匹配数据</li>
</ul>
<ul class="select-dropdown-list" :>borderbox
<li @click="selectChange(item)" class="select-item" v-for="(item,index) in selectDataList"
:key="index">
{{item.label}}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: "InputAndSelect",
props: {
selectDataList: {
type: Array,
default: [],
// 验证必须有label和value
validator: function (value) {
return value.every(item => {
return item.hasOwnProperty("label") && item.hasOwnProperty("value")
})
}
},
// value 与 this.$emit('input', this.value) 配合实现input 输⼊框 v-model双向绑定功能
value: {
type: String,
default: "",
},
// 是否将下拉框加⼊到body的直接⼦节点中
// 在 Tabs、带有 fixed 的 Table 列内使⽤时,建议添加此属性,它将不受⽗级样式影响,从⽽达到更好的效果
transfer: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: "请选择",
}
},
data() {
return {
iconUnfoldClass: {
'icon-unfold-transform': false
},
//记录点击切换按钮时对应的事件
ev: null
}
},
methods: {
//在输⼊框中改变值时才会触发,js改变输⼊框绑定的值不会触发
inputChange() {
console.log("inputValue改变了====", this.value)
this.$emit('input', this.value)
this.$emit('inputChange', this.value)
},
//选择内容发⽣改变时触发
selectChange(item) {
this.value = item.value
this.iconUnfoldClass["icon-unfold-transform"] = false
this.$emit('input', this.value)
this.$emit('selectChange', item)
},
changeIconDirection(e) {
/
/点击切换图标按钮时,先保存当前点击的事件,在后⾯监听的click事件中,判断如果不是当前点击的事件,则收起下拉框
this.ev = e
this.iconUnfoldClass["icon-unfold-transform"] = !this.iconUnfoldClass["icon-unfold-transform"]
if (this.iconUnfoldClass["icon-unfold-transform"]) {
this.checkTransfer()
let inputDom = this.$el.querySelector(".inputDom")
inputDom.focus()
}
},
checkTransfer() {
if (ansfer) {
// 组件监听页⾯resize只能⽤addEventListener,否则不会⽣效
window.addEventListener('resize', this.checkTransfer, false)
// 监听scroll事件的事件传递必须使⽤捕获阶段,让外部元素事件先触发
// document.addEventListener('scroll', this.checkTransfer, true)
//window.innerHeight  document.documentElement.clientHeight 都是获取可是去⾼度
//window.innerHeight获取的⾼度包含横向滚动条,⽽document.documentElement.clientHeight不包含横向滚动条
let bodyHeight = document.documentElement.clientHeight // body 可视区域⾼度
let matchHeight = this.matchDom.clientHeight // 匹配DOM的⾼度
let rect = BoundingClientRect() // 取出匹配⽗级DOM的矩形对象
// getBoundingClientRect.bottom为元素下边与页⾯上边的距离,所以元素下边与页⾯下边距离 = 页⾯⾼度 - getBoundingClientRect.bottom          let bottom = bodyHeight - rect.bottom
this.matchDom.style.left = rect.left + 'px' // 匹配DOM的left与⽗级⼀致
let dropdownWidth = rect.width + 'px' //下拉框宽度与⽗级dom⼀致
this.matchDom.style.width = dropdownWidth
if (bottom >= matchHeight) { // ⽗级距离页⾯下边的⾼度⼤于等于匹配DOM的⾼度,则往下展⽰
this.matchDom.style.bottom = 'auto'
this.p = (p + rect.height) + 'px' // 匹配DOM的top = ⽗级矩形对象top + ⽗级的⾼度
} else { // ⽗级距离页⾯下边的⾼度⼩于匹配DOM的⾼度,则往上展⽰
this.p = 'auto'
this.matchDom.style.bottom = (bottom + rect.height) + 'px' // 匹配DOM的bottom = ⽗级矩形对象bottom + ⽗级的⾼度          }
}
},
// 点击切换图标按钮以外的其他地⽅触发,关闭下拉框
clickOther(e) {
// 判断如果不是当前点击的事件,则收起下拉框
if (this.ev == e) return
if (this.iconUnfoldClass["icon-unfold-transform"]) {
this.iconUnfoldClass["icon-unfold-transform"] = false
}
}
},
computed: {
isExistedSelectData() {
return this.selectDataList.length > 0 ? true : false
},
matchDom() { // 匹配框,需要相对于body
return this.$el.getElementsByClassName('select-dropdown')[0]
},
matchParent() { // 匹配框⽗级
return this.$el.getElementsByClassName('parent')[0]
}
},
created() {
if (ansfer) {
// 将匹配的下拉框从原有位置移到body节点中
this.$nextTick(() => {
const body = document.querySelector('body')
// 将匹配DOM添加到body中
if (body.append) { // 在IE11中 document.appendChild会报错: javascript runtime error:HierarchyRequestError
body.append(this.matchDom)
} else {
body.appendChild(this.matchDom)
}
})
}
},
mounted() {
window.addEventListener("click", this.clickOther);
},
}
</script>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。