vue 下拉列表组件 缓动动画 css样式 升级

4 篇文章 0 订阅
3 篇文章 0 订阅

input式的下拉列表的东西

  • 由于极其不爽这个input的下拉列表的样式所以自己写了一个
  • 这个三角的东西是用的图片所以 自己弄一个上去吧

之前的那个有个bug, 就是它没有出来的时候都会档住下面的东西
其实还有一个思路就是改变外面边框的高度这样就不会在拉上去的时候挡住, 下面的东西

展示

在这里插入图片描述

不会档住的形式

  • 核心思路就是将内部的bottom变换改成外面over-flow: hidden 的盒子的高度变化

DropDownList.vue

<template>
   <div 
   class="drop-down-list" 
   :style = "getStyle"
   ref = "drop"
   @click = "dropDown"
   >
   	{{value}}
   	<img 
   	src="~assets/img/common/triangle.svg" 
   	:class = "getClass" 
   	class = "icon" alt="">
   	
   	<div 
   	class = "down-list"
   	:style = "getDropStyle"
   	ref = "downListOuter">
   		<div ref = 'downlist' 
   		class = "list-in"
   		>
   			<list-item 
   			v-for = "item in list" 
   			:item = "item"
   			@itemClick = "itemClick"
   			:importance = "getImportance(item)">
   				<!-- 阻止事件冒泡 -->
   			</list-item>
   		</div>
   	</div>
   </div>
</template>

<script>
   import ListItem from './ListItem'
   
   export default {
   	name: 'DropDownList',
   	data() {
   		return {
   			value: this.list[0],
   			isDown: false,
   			time: -1,
   			only: true,
   			dropDownHeight: "100px",
   			initHeight: ""
   		}
   	},
   	props: {
   		list: {
   			type: Array,
   			default () {
   				return [
   					"成都",
   					"北京",
   					"上海"
   				]
   			}
   		},
   		width: {
   			type: String,
   			default: "72%"
   		},
   	},
   	components: {
   		ListItem
   	},
   	mounted() {
   		console.log( "mounted: " + window.getComputedStyle(this.$refs.downlist).height )
   		this.dropDownHeight = window.getComputedStyle(this.$refs.downlist).height
   	},
   	methods: {
   		getImportance(item) {
   			console.log(this.value == item)
   			return this.value == item
   		},
   		itemClick(value) {
   			this.value = value
   		},
   		dropDown() {
   			// // 缓动动画
   			let n = 0.08
   			if( this.time != -1 ) {
   				clearInterval(this.time)
   			}
   			// if( this.only ) {
   			// 	this.only = false;
   				this.isDown = !this.isDown;
   				if( this.isDown ) {
   					this.$refs.downListOuter.style.zIndex = 0;
   					this.dropDownList(n)
   				} else {
   					this.dropUpList(n)
   				}
   			// }
   		},
   		dropDownList(n) {
   			// 正往下拉的情况
   			const downlist = this.$refs.downlist
   			const downListOuter = this.$refs.downListOuter
   			// 关闭上一个计时器
   			if( this.time != -1 ) {
   				clearInterval(this.time)
   			}
   			
   				downlist.style.bottom = 0 + "px"

   			
   			let index2;
   			if( this.initHeight == "" ) {
   				this.initHeight = this.getNumber(downListOuter.style.height);
   				console.log(this.initHeight)
   			}
   			let result2 = this.initHeight;
   			// 让下拉列表窗口的高度等于0
   			downListOuter.style.height = 0 + "px";
   			
   			let index;
   			let result = 0;
   			this.time = setInterval( ()=>{
   				index = this.getNumber(downlist.style.bottom)
   				result = 0;
   				
   				// downlist.style.bottom = index - (index - result) * n + "px";
   				
   				index2 = this.getNumber(downListOuter.style.height);
   				downListOuter.style.height = index2 - (index2 - result2) * n + "px";
   				
   				if( Math.abs(this.getNumber(downListOuter.style.height) - result2) < 0.1  ) {
   					clearInterval(this.time)
   					// downlist.style.bottom = result + "px";
   					downListOuter.style.height = result2 + "px";
   				}
   			} , 10 )
   		},
   		dropUpList(n) {
   			const downlist = this.$refs.downlist
   			const downListOuter = this.$refs.downListOuter
   			// 关闭上一个计时器
   			if( this.time != -1 ) {
   				clearInterval(this.time)
   			}
   			
   			let index2;
   			let result2 = 0;
   			
   			// 初始化高度 100%
   			let index;
   			let result = this.getNumber(downlist.parentElement.style.height);
   			
   			this.time = setInterval( ()=>{
   				index = this.getNumber(downlist.style.bottom)
   				// downlist.style.bottom = index + (result - index) * n + "px";
   				
   				index2 = this.getNumber(downListOuter.style.height);
   				downListOuter.style.height = index2 + (result2 - index2) * n + "px";
   				console.log("downListOuter.style.height", downListOuter.style.height)
   				
   				if( Math.abs(downListOuter.style.height - result2) < 0.1  ) {
   					clearInterval(this.time)
   					downlist.style.bottom = result + "px";
   					downListOuter.style.height = result2 + "px";
   					this.$refs.downListOuter.style.zIndex = -10;
   				}
   			} , 10 )
   		},
   		getNumber( inputStr ) {
   			// 字符串转化成数字
   			return Number(inputStr.replace("px", ""))
   		}
   	},
   	computed: {
   		getStyle() {
   			return {
   				width: this.width,
   			}
   		},
   		getClass() {
   			return {
   				'rotate': this.isDown
   			}
   		},
   		getDropStyle() {
   			return {
   				height: this.dropDownHeight
   			}
   		}
   	}
   }
</script>

<style scoped>
   .drop-down-list {
   	position: relative;
   	display: flex;
   	justify-content: space-between;
   	border-radius: 5px;
   	padding: 5px 10px 5px 10px;
   	font-size: 16px;
   	border: 1px solid #ccc;
   	transition: all .5s;
   	
   }

   .drop-down-list:hover {
   	outline: none;
   	box-shadow: 0 0px 15px skyblue;
   }
   
   .bg-red {
   	background-color: red;
   }
   
   .icon {
   	width: 20px;
   	margin-top: 3px;
   	transform: rotate(180deg);
   	transition: all 0.3s;
   }
   
   .rotate {
   	transform: rotate(0deg); 
   	transform-origin: 50% 50%; 
   }
   
   .down-list {
   	position: absolute;
   	top: calc(100% + 5px);
   	left: 0px;
   	width: 100%;
   	background-color: transparent;
   	
   	z-index: -10;
   	overflow: hidden;
   }
   
   .list-in {
   	position: absolute;
   	bottom: 100%;
   	
   	/* height: 100%; */
   	width: 100%;
   	padding: 10px 0px;
   	background-color: white;
   	
   	border-radius: 0 0 5px 5px;
   }
</style>

文件结构

在这里插入图片描述

DropDownList.vue

<template>
	<div 
	class="drop-down-list" 
	:style = "getStyle"
	ref = "drop"
	@click = "dropDown"
	>
		{{value}}
		<img 
		src="~assets/img/common/triangle.svg" 
		:class = "getClass" 
		class = "icon" alt="">
		
		<div 
		class = "down-list"
		:style = "getDropStyle"
		ref = "downListOuter">
			<div ref = 'downlist' 
			class = "list-in"
			>
				<list-item 
				v-for = "item in list" 
				:item = "item"
				@itemClick = "itemClick"
				:importance = "getImportance(item)">
					<!-- 阻止事件冒泡 -->
				</list-item>
			</div>
		</div>
	</div>
</template>

<script>
	import ListItem from './ListItem'
	
	export default {
		name: 'DropDownList',
		data() {
			return {
				value: this.list[0],
				isDown: false,
				time: -1,
				only: true,
				dropDownHeight: "100px"
			}
		},
		props: {
			list: {
				type: Array,
				default () {
					return [
						"成都",
						"北京",
						"上海"
					]
				}
			},
			width: {
				type: String,
				default: "72%"
			},
		},
		components: {
			ListItem
		},
		mounted() {
			console.log( "mounted: " + window.getComputedStyle(this.$refs.downlist).height )
			this.dropDownHeight = window.getComputedStyle(this.$refs.downlist).height
		},
		methods: {
			getImportance(item) {
				console.log(this.value == item)
				return this.value == item
			},
			itemClick(value) {
				this.value = value
			},
			dropDown() {
				// // 缓动动画
				let n = 0.08
				if( this.time != -1 ) {
					clearInterval(this.time)
				}
				// if( this.only ) {
				// 	this.only = false;
					this.isDown = !this.isDown;
					if( this.isDown ) {
						this.$refs.downListOuter.style.zIndex = 0;
						this.dropDownList(n)
					} else {
						this.dropUpList(n)
					}
				// }
			},
			dropDownList(n) {
				// 正往下拉的情况
				const downlist = this.$refs.downlist
				// 关闭上一个计时器
				if( this.time != -1 ) {
					clearInterval(this.time)
				}
				
				// 初始化高度 100%不行
				if( downlist.style.bottom == "" ) {
					downlist.style.bottom = downlist.parentElement.style.height
				}
				
				let index;
				let result = 0;
				this.time = setInterval( ()=>{
					index = this.getNumber(downlist.style.bottom)
					result = 0;
					
					downlist.style.bottom = index - (index - result) * n + "px";
					
					
					if( Math.abs(this.getNumber(downlist.style.bottom) - result) < 0.1  ) {
						clearInterval(this.time)
						downlist.style.bottom = result + "px";
					}
				} , 10 )
			},
			dropUpList(n) {
				const downlist = this.$refs.downlist
				// 关闭上一个计时器
				if( this.time != -1 ) {
					clearInterval(this.time)
				}
				
				// 初始化高度 100%
				let index;
				let result = this.getNumber(downlist.parentElement.style.height);
				
				this.time = setInterval( ()=>{
					index = this.getNumber(downlist.style.bottom)
					downlist.style.bottom = index + (result - index) * n + "px";
					
					if( Math.abs(this.getNumber(downlist.style.bottom) - result) < 0.2  ) {
						clearInterval(this.time)
						downlist.style.bottom = result + "px";
						this.$refs.downListOuter.style.zIndex = -10;
					}
				} , 10 )
			},
			getNumber( inputStr ) {
				// 字符串转化成数字
				return Number(inputStr.replace("px", ""))
			}
		},
		computed: {
			getStyle() {
				return {
					width: this.width,
				}
			},
			getClass() {
				return {
					'rotate': this.isDown
				}
			},
			getDropStyle() {
				return {
					height: this.dropDownHeight
				}
			}
		}
	}
</script>

<style scoped>
	.drop-down-list {
		position: relative;
		display: flex;
		justify-content: space-between;
		border-radius: 5px;
		padding: 5px 10px 5px 10px;
		font-size: 16px;
		border: 1px solid #ccc;
		transition: all .5s;
	}

	.drop-down-list:hover {
		outline: none;
		box-shadow: 0 0px 15px skyblue;
	}
	
	.bg-red {
		background-color: red;
	}
	
	.icon {
		width: 20px;
		margin-top: 3px;
		transform: rotate(180deg);
		transition: all 0.3s;
	}
	
	.rotate {
		transform: rotate(0deg); 
		transform-origin: 50% 50%; 
	}
	
	.down-list {
		position: absolute;
		top: calc(100% + 5px);
		left: 0px;
		width: 100%;
		background-color: transparent;
		
		z-index: -10;
		overflow: hidden;
	}
	
	.list-in {
		position: absolute;
		bottom: 100%;
		
		/* height: 100%; */
		width: 100%;
		padding: 10px 0px;
		background-color: white;
		
		border-radius: 0 0 5px 5px;
	}
</style>

ListItem.vue

<template>
	<div 
	class = "list-item"
	@click = "itemClick(item)">
		{{item}}
	</div>
</template>

<script>
	export default {
		name: 'ListItem',
		methods: {
			itemClick(value) {
				this.$emit("itemClick", value)
			}
		},
		props: {
			item: {
				type: String,
				default: "item"
			}
		}
	}
</script>

<style scoped>
	.list-item {
		padding: 5px 10px;
	}
	
	.list-item:hover {
		background-color: #F0F1F2;
	}
</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值