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:hover{
border-color: #3597f5;
}
.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;
}
}
}
</style>
<template>
<div style="width:inherit;">
<div class="parent" style="position: relative;width:inherit;">
<div class="select-input">
<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" :style="{display: iconUnfoldClass['icon-unfold-transform']?'block':'none'}">
<ul class="select-not-found" :style="{display: !isExistedSelectData?'block':'none'}">
<li>无匹配数据</li>
</ul>
<ul class="select-dropdown-list" :style="{display: isExistedSelectData?'block':'none'}">
<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 = document.querySelector(".inputDom")
inputDom.focus()
}
},
checkTransfer() {
if (this.transfer) {
// 组件监听页面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 = this.matchParent.getBoundingClientRect() // 取出匹配父级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.matchDom.style.top = (rect.top + rect.height) + 'px' // 匹配DOM的top = 父级矩形对象top + 父级的高度
} else { // 父级距离页面下边的高度小于匹配DOM的高度,则往上展示
this.matchDom.style.top = '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 (this.transfer) {
// 将匹配的下拉框从原有位置移到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>
vue自定义可输入的选择框组件的更多相关文章
- 原生js实现一个自定义下拉单选选择框
浏览器自带的原生下拉框不太美观,而且各个浏览器表现也不一致,UI一般给的下拉框也是和原生的下拉框差别比较大的,这就需要自己写一个基本功能的下拉菜单/下拉选择框了.最近,把项目中用到的下拉框组件重新封装 ...
- CSS自定义select下拉选择框(不用其他标签模拟)
今天群里有人问到怎么自定义select下拉选择框的样式,于是群里就展开了激烈的讨论,刚开始一直就是考虑怎样使用纯CSS实现,把浏览器默认的样式覆盖掉,但最后均因兼容问题处理不好而失败告终,最后的解决方 ...
- 微信小程序之自定义select下拉选项框组件
知识点:组件,animation,获取当前点击元素的索引与内容 微信小程序中没有select下拉选项框,所以只有自定义.自定义的话,可以选择模板的方式,也可以选择组件的方式来创建. 这次我选择了组件, ...
- Nuxt/Vue自定义导航栏Topbar+标签栏Tabbar组件
基于Vue.js实现自定义Topbar+Tabbar组件|仿咸鱼底部凸起导航 最近一直在倒腾Nuxt项目,由于Nuxt.js是基于Vue.js的服务端渲染框架,只要是会vue,基本能很快上手了. 一般 ...
- [RN] React Native 自定义 底部 弹出 选择框 实现
React Native 自定义 底部选择框 实现 效果如图所示: 实现方法: 一.组件封装 CustomAlertDialog.js import React, {Component} from ' ...
- WeChat-SmallProgram:自定义select下拉选项框组件
1):创建组件所需的文件 2):自定义组件 CSS 及 JS 组件的wxml: <view class='com-selectBox'> <view class='com-sCont ...
- 关于隐式创建vue实例实现简化弹出框组件显示步骤
我们在使用vue写alert组件的时候,经常是定义了一个alert.vue,然后引入alert.vue,然后配置参数等等,非常繁琐,那有没有一种方式可以像window.alert("内容&q ...
- Flex AIR自定义Mobile的弹出框组件
做Flex Mobile开发的人应该知道,Flex为手机应用并没有提供弹出框组件,需要自定义. 通过查找文档.资料,我做出一个效果还算不错的弹出框组件,可以适用于手机设备上,不多讲,直接贴源码,相信对 ...
- 使用vue自定义简单的消息提示框
<style scoped> /** 弹窗动画*/ a { text-decoration: none } .drop-enter-active { /* 动画进入过程:0.5s */ t ...
随机推荐
- 最小生成树的java实现
文章目录 一.概念 二.算法 2.1 Prim算法 2.2 Kruskal算法 笔记来源:中国大学MOOC王道考研 一.概念 连通图:图中任意两点都是连通的,那么图被称作连通图 生成树:连通图包含全部 ...
- 感知机算法(PLA)代码实现
目录 1. 引言 2. 载入库和数据处理 3. 感知机的原始形式 4. 感知机的对偶形式 5. 多分类情况-one vs. rest 6. 多分类情况-one vs. one 7. sklearn实现 ...
- 一个有趣的问题, 你知道SqlDataAdapter中的Fill是怎么实现的吗
一:背景 1. 讲故事 最近因为各方面原因换了一份工作,去了一家主营物联柜的公司,有意思的是物联柜上的终端是用 wpf 写的,代码也算是年久失修,感觉技术债还是蛮重的,前几天在调试一个bug的时候,看 ...
- CCNA - Part11 - 隔离广播域的 VLAN 来了
之前在对交换机的介绍中,我们知道交换机的作用就是隔离广播域,在不需要跨网段传输时,在同一子网中转发数据包从而进行通信.实现的核心原理就是在交换机中拥有一张 MAC 表,记录了对应终端设备和接口之间的关 ...
- DJANGO-天天生鲜项目从0到1-001-环境框架搭建
本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...
- python txt装换成excel
工作中,我们需要经常吧一些导出的数据文件,例如sql查出来的结果装换成excel,用文件发送.这次为大家带上python装换excel的脚本 记得先安装wlwt模块,适用版本,python2-3 #c ...
- 性能测试必备知识(6)- 如何查看“CPU 上下文切换”
做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 课前准备,安装 sysbench 下载 sy ...
- ElasticSearch(三)springboot整合ES
最基础的整合: 一.maven依赖 <parent> <groupId>org.springframework.boot</groupId> <artifac ...
- Python环境那点儿事(Windows篇)
Python环境配置那点儿事(Windows篇) 版本选择 (根据你的开发经验选择合适版) 适当版2.7 适当版3.6 适当版3.7 下载链接:python.org 安装 正规的Windows10操作 ...
- 笑谈AlphaGo对战人类从模仿到超越之奥义
起源 故事从一个围棋说起,人类赖以自豪的智慧,为什么这么说,因为据统计,从这19乘19的方格中摆棋,可以有10的340次方的可能,用一个更形象的比拟,全宇宙的原子加起来,也比这个数要小. 也就是说,如 ...