效果图:
继续让进度条向左:
进度条向右恢复:
思路:
(1)进度条宽度:进度条背景长度*(屏幕宽度/滚动区域),获取对应比例的进度条宽度
(2)进度条移动随滚动区域移动:根据移动距离占滚动区域的总长度的比例和进度条移动距离占总进度条的背景长度相同,换算进度条移动距离
1、触摸开始获取起始点
2、触摸过程获取点和起始点计算,获取滚动距离,进行换算
3、触摸结束获取结束时在触摸过程中的换算后的移动距离,放在2中,用于在上一次滑动结束后的位置继续滑动
结束触摸后,还要判断进度条宽度,进行宽度恢复
(3)边界继续拉动,进度条宽度减少,反向拉恢复
在触摸过程中:
通过上一次坐标和当前坐标判断方向,如果进度条已经被压缩,并且此时进度条移动的距离小于进度条原本宽度,就进行恢复,即左边界向右恢复
通过坐标判断方向,如果进度条已经被压缩,并且进度条的移动距离大于在进度条正常的情况下能移动的最大距离,即右边界向左拉恢复
增加判断的恢复临界值
代码示例:
<template>
<div class='hot-nav'>
<!-- 滚动区域 -->
<div class='hot-nav-cont'>
<div class='nav-cont-inner'>
<div class='inner-item' v-for='(item,index) in 16' :key='index'>
<img src="../../imgs/nav/nav_icon01.png" alt="">
<span>限时秒杀</span>
</div>
</div>
</div>
<!-- 进度条 -->
<div class='hot-bottom'>
<div class='hot-bar' :style='getTheBarWidth' ></div>
</div>
</div>
</template>
<script>
export default {
name:'hotnav',
data(){
return{
//初始值都是css中定义好的
//屏幕宽度
screenWidth:window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,
//滚动内容宽度
scrollContentW:720,
//进度条背景长度
barBackWidth:80,
//进度条长度
barXWidth:0,
//起点
startX:0,
//结束点
endFlag:0,
//进度条移动距离
barMove:0,
//进度条到达边界后的弹性距离
popWidth:0,
//记录进度条初始长度
barInitWidth:0,
//记录上一次移动过程的点,用于判断距离,
lastX:0
}
},
mounted()
{
//获取进度条长度
this.barXWidth=this.getBarWidth();
//获取进度条初始长度
this.barInitWidth=this.barXWidth;
//监听
this.bindEvent();
},
computed:{
//动态获取进度条宽度
getTheBarWidth()
{
return{
width:`${this.barXWidth}px`,
marginLeft:this.barMove+'px'
}
}
},
methods:{
//进度条长度
getBarWidth()
{
//进度条背景长度*(屏幕宽度/滚动区域),获取对应比例的进度条宽度
return this.barBackWidth*(this.screenWidth/this.scrollContentW);
},
//绑定事件
bindEvent()
{
//绑定触摸开始、触摸移动、触摸结束事件
this.$el.addEventListener('touchstart',this.touchStart,false);
this.$el.addEventListener('touchmove',this.touchMove,false);
this.$el.addEventListener('touchend',this.touchEnd,false);
},
touchStart(e)
{
//开始触摸,获得起始点
this.startX=e.touches[0].pageX;
},
touchMove(e)
{
//获取移动过程中的点,获取移动过程中的移动距离
let scrollMove=this.startX-e.touches[0].pageX;
//根据移动距离占滚动区域的总长度的比例和进度条移动距离占总进度条的背景长度相同
//换算进度条移动距离
this.barMove=this.endFlag+(scrollMove/this.scrollContentW)*this.barBackWidth;
//到达边界后的弹性长度距离
this.popWidth=this.endFlag+(scrollMove/this.scrollContentW)*this.barBackWidth;
//在边界继续拉伸后,往反方向拉伸时,让进度条逐渐恢复原本长度
//通过上一次坐标和当前坐标判断方向,如果进度条已经被压缩,并且此时进度条移动的距离小于进度条原本宽度,就进行恢复,即左边界向右恢复
if(this.lastX-e.touches[0].pageX>0&&(this.barXWidth<this.barInitWidth)&&this.barMove<this.barInitWidth)
{
this.barXWidth=this.barXWidth+this.barMove;
if(this.barXWidth>this.barInitWidth)
{
this.barXWidth=this.barInitWidth;
}
}//通过坐标判断方向,如果进度条已经被压缩,并且进度条的移动距离大于在进度条正常的情况下能移动的最大距离,即右边界向左拉恢复
else if(this.lastX-e.touches[0].pageX<0&&(this.barXWidth<this.barInitWidth)&&this.barMove>(this.barBackWidth-this.barInitWidth)){
console.log('向右');
this.barXWidth=this.barXWidth-((this.popWidth-(this.barBackWidth-this.barXWidth)));
if(Math.abs(this.barXWidth-this.barInitWidth)<3)
{
this.barXWidth=this.barInitWidth;
}
}
//边界值处理
//左边界
if(this.barMove<0)
{
this.barXWidth=this.barXWidth+(this.popWidth);
this.barMove=0;
}
//右边界
if(this.barMove>(this.barBackWidth-this.barXWidth))
{
this.barXWidth=this.barXWidth-((this.popWidth-(this.barBackWidth-this.barXWidth)));
this.barMove=this.barBackWidth-this.barXWidth;
//最大距离
if(this.barMove>this.barBackWidth-10)
{
this.barMove=this.barBackWidth-10;
}
}
//设置进度条最小宽度为10px
if(Math.abs(this.barXWidth)<10)
{
this.barXWidth=10;
}
//记录上一次坐标,用于和当前坐标判断方向
this.lastX=e.touches[0].pageX;
},
//用于记录下一次移动的位置
touchEnd(e)
{
//结束触摸记录结束时的进度条移动距离,避免再次点击移动位置从0开始
//this.barMove>0表示为到达右边界后记录位置
if(this.barInitWidth-this.barXWidth>2&&this.barMove>0)
{
this.barMove=this.barBackWidth-this.barInitWidth;
//记录结束位置
this.endFlag=this.barMove;
}else{
//记录结束位置
this.endFlag=this.barMove
}
this.barXWidth=this.barBackWidth*(this.screenWidth/this.scrollContentW);
}
}
}
</script>
<style scoped lang='less'>
.hot-nav{
height: 180px;
position:relative;
background-color: #fff;
padding-bottom: 10px;
.hot-bottom{
//进度条背景宽度
width: 80px;
height: 5px;
background-color:#eee ;
margin: 0 auto;
border-radius: 2px;
.hot-bar{
width:0px;
background-color: red;
height: 5px;
border-radius: 2px;
}
}
.hot-nav-cont::-webkit-scrollbar{
display: none;
}
.hot-nav-cont{
width: 100%;
overflow-x: scroll;
.nav-cont-inner{
//设置滚动内容区域宽度
width: 720px;
height: 180px;
display: flex;
flex-wrap:wrap;
.inner-item{
height: 90px;
//每个格子的宽度,通过改变宽度,设置每行数量
width: 90px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 14px;
color:#666666;
img{
width: 40%;
margin-bottom: 5px;
}
}
}
}
}
</style>