vue实现滑块slider(赋源码)

2,681

因为项目用到滑块,只要一处使用到看了第三方库觉得没必要引入导致项目太臃肿: 先上代码:

<template>
	<div class="slider" ref="mySlider">
		<div class="left-btn" :class="{active:myPosition.isBtn==2}"></div>
		<div class="propo"></div>
		<div class="propo-bg"></div>
		<div class="right-btn" :class="{active:myPosition.isBtn==1}"></div>
	</div>
</template>
<script type="text/javascript">
	export default {
		name: 'slider',
		props:{
			"valueFun":{
				type:Function,
				required: true,
			},
			"max":{
				type:Number,
				default:100
			},
			"min":{
				type:Number,
				default:0
			}
		},
		data(){
			return{
				myPosition:{
					left:0,
					right:0,
					now:0,
					isBtn:0,
					propoWidth:0
				},
				myDefault:null
			}
		},
		methods:{

		},
		mounted(){
			//滑块
			let that = this
			let mySlider = this.$refs.mySlider
			let propo = mySlider.children[1]
			let rightBtn = mySlider.children[3]
			let leftBtn = mySlider.children[0]
			let myWidth = 0

			const elementLeft = (e) => { //计算x坐标
				var offset = e.offsetLeft;
				if(e.offsetParent != null) offset += elementLeft(e.offsetParent);
				return offset;
			}

			const myCount = () => { //计算滑动
				if(this.myPosition.right>this.myPosition.left){ //判断滑动范围
					this.myPosition.propoWidth = this.myPosition.right - this.myPosition.left
					propo.style.width = this.myPosition.propoWidth+'%'
					propo.style.left = this.myPosition.left + '%'
					this.valueFun(parseInt(this.myPosition.left),parseInt(this.myPosition.right),parseInt(this.myPosition.propoWidth))
				}else if(this.myPosition.right<this.myPosition.left){
					this.myPosition.propoWidth = this.myPosition.left - this.myPosition.right
					propo.style.width = this.myPosition.propoWidth+'%'
					propo.style.left = this.myPosition.right+'%'
					this.valueFun(parseInt(this.myPosition.right),parseInt(this.myPosition.left),parseInt(this.myPosition.propoWidth))
				}
			}

			this.myDefault = () => {//初始化
				this.myPosition.right = this.max
				this.myPosition.left = this.min
				
				if(this.max > this.min){
					this.myPosition.propoWidth = this.max - this.min
					propo.style.left = this.myPosition.left + '%'
				}else{
					this.myPosition.propoWidth = this.min - this.max
					propo.style.left = this.myPosition.right + '%'
				}
				
				propo.style.width = this.myPosition.propoWidth+'%'
				leftBtn.style.left = this.myPosition.right + '%'
				rightBtn.style.left = this.myPosition.left + '%'
				this.valueFun(this.myPosition.left,this.myPosition.right,this.myPosition.propoWidth)
			}

			let mySliderX = elementLeft(mySlider) //滑动块x坐标

			mySlider.addEventListener('touchmove',(e)=>{ //屏幕滑动事件
				let pageX = e.touches[0].pageX-mySliderX //获取滑动x坐标
				myWidth = (pageX/mySlider.offsetWidth)*100 //计算百分比
				if(myWidth>100){ //判断不超出范围
					myWidth=100
				}else if(myWidth<0){
					myWidth=0
				}

				if(this.myPosition.isBtn == 1){//判断焦点
					this.myPosition.left = myWidth
					rightBtn.style.left = myWidth+'%' 
				}else if(this.myPosition.isBtn == 2){
					this.myPosition.right = myWidth
					leftBtn.style.left = myWidth+'%' 
				}
				
				myCount()
				e.preventDefault()

			})

			mySlider.addEventListener('touchstart',(e)=>{//屏幕触摸事件
				let touchX = e.touches[0].pageX-mySliderX
				let btnWidth = (leftBtn.offsetWidth/mySlider.offsetWidth)/2*100 //计算按钮宽度
				this.myPosition.now = (touchX/mySlider.offsetWidth)*100
				mySliderX = elementLeft(mySlider) //滑动块x坐标
				if(this.myPosition.now <= this.myPosition.left+btnWidth&&this.myPosition.now >= this.myPosition.left-btnWidth){ //计算区间 获取焦点
					this.myPosition.isBtn = 1
				}else if(this.myPosition.now <= this.myPosition.right+btnWidth&&this.myPosition.now >= this.myPosition.right-btnWidth){
					this.myPosition.isBtn = 2
				}else{
					this.myPosition.isBtn = 0
				}
			})

			this.myDefault()
		},
		watch:{
			min(New,old){
				this.myDefault()
			},
			max(New,old){
				this.myDefault()
			}
		}
	}
</script>
<style lang="scss">
	.slider{
			width: 100%;
			position:relative;
			height: 0.5rem;
			.left-btn,.right-btn{
				position: absolute;
				top: -0.34rem;
				transform:translate(-50%,0);
				&:before{
					content: ""; 
					display: block;
					width: 0; 
					height: 0.4rem;
					border-left: 0.17rem solid transparent; 
					border-right: 0.17rem solid transparent; 
					border-bottom: 0.17rem solid #B6B6B6; 
				}
				&:after{
					content: "";
					display: block;
				    height: 0.30rem;
				    width: 0.34rem;
				    background: #B6B6B6;
				    border-bottom-left-radius: 0.1rem;
				    border-bottom-right-radius: 0.1rem;
				}
			}
			.propo{
				width: 0%;
				height: 0.04rem;
				background: #FFD00D;
				position: absolute;
			    top: 0;
			    left: 0;
			    z-index: 2;
			}
			.propo-bg{
				background: #B6B6B6;
				border-radius: 0.04rem;
				height: 0.04rem;
				width:100%;
				position: absolute;
			    top: 0;
			    left: 0;
			    z-index: 1;
			}
			.active{
				&:before{
					border-bottom-color: #FF8C30
				}
				&:after{
					background: #FF8C30;
				}
			}
	}
</style>

实现思路: 首先通过$refs获取dom节点 通过touchstart事件获取触摸的x坐标 判断按钮焦点 通过touchmove判断之前的焦点并获取滑动距离 然后计算滑动距离(滑动的x坐标减掉最父级节点的x坐标,注:最父级节点是动态改变的 所以得动态获取)

调用方法:

<slider :value-fun="Val" :min="0" :max="100"></slider>

样式:

这里写图片描述

github : github.com/474782977/v…