实例详解如何给轮播图做自适应的高度
不知道大家有没有遇到这样的需求或者说看到类似的效果,就是列表进去详情看轮播图的时候,当手指滚动轮播图时轮播的高度容器会自适应,这样下面的内容就向上挤,滑动的过程会计算高度,释放的时候也会滚到下一张,也会计算对应图片的高度,然后做一个缓动的动画效果。就像下面这张图的样子。
可以看到上面的图片内容文字,随着轮播的滑动高度也在变化。费话不多说直接上代码。
实现方法
可以通过监听鼠标mounse
或者手指的滑动 touch
事件来控制图片,这里本文只说一下轮播的功能实现思路,重点说的是怎么实现高度的自适应。
直接开始正文,先看 html 代码结构。
html 结构
<div class="container">
<div class="wrapper">
<div class="swiper">
<div class="item">
<img class="lazy" data-src="https://ci.xiaohongshu.com/776d1cc7-ff36-5881-ad8f-12a5cd1c3ab3?imageView2/2/w/1080/format/jpg" alt="">
</div>
<div class="item">
<img class="lazy" data-src="https://ci.xiaohongshu.com/b8e16620-66a0-79a5-8a4b-5bfee1028554?imageView2/2/w/1080/format/jpg" alt="">
</div>
<div class="item">
<img class="lazy" data-src="https://ci.xiaohongshu.com/e12013c2-3c46-a2cc-7fda-1e0b20b36f3d?imageView2/2/w/1080/format/jpg" alt="">
</div>
</div>
</div>
<div class="content">这是一段内容</div>
</div>
css 样式
.container {
width: 100%;
overflow: hidden;
}.wrapper {
width: 100%;
}.swiper {
font-size: 0;
white-space: nowrap;
}.item {
display: inline-block;
width: 100%;
vertical-align: top; // 一定要使用顶部对齐,不然会出现错位的情况
}.item img {
width: 100%;
height: auto;
display: block;
}.content {
position: relative;
z-index: 9;
font-size: 14px;
text-align: center;
padding-top: 20px;
background-color: #fff;
height: 200px;
}
值得注意的地方有几点;
- 在使用父级
white-space
时,子集元素设置display: inline-block
会出现高度不同的排列错位,解决办法就是加上一句vertical-align: top
,具体什么原因我也不细讲了。 - 另外父级还要设置
font-size: 0
,如果没加上的话,就会出现两个子集有空隙出现,加上之后空隙就会去掉。 - img 图片最好设置成高度自适应,宽度
100%
还要加上display: block
,没有的话底部就会出现间隙。
写好上面的 html
容器部分和 样式,下面就看一下 js
上是怎么处理的。
Js 实现
开始之前我们先思考一下去怎么实现这个轮播以及高度的自适应问题,分为几步操作;
- 鼠标按下时,需要记录当前的位置和一些其他初始化的信息,并且给当前的父元素添加相应的鼠标事件。
- 鼠标移动时,需要通过当前实时移动时点位和按下时点位的相减,得到移动的距离位置,然后再赋值给父元素设置其样式
transform
位置,中间还做其他的边界处理,当然还有高度的变化。 - 鼠标释放是,通过移动时记录的距离信息判断是左滑还是右滑,拿到其对应的索引,通过索引就可以计算到滚动下一张的距离,释放之后设置
transition
过渡动画即可。
按照我们试想的思路,开始正文;
初始化数据
const data = {
ele: null,
width: 0,
len: 0,
proportion: .3,
type: false,
heights: [500, 250, 375],
currentIndex: 0,
startOffset: 0,
clientX: 0,
distanceX: 0,
duration: 30,
touching: false
}
const wrapper = data.ele = document.querySelector('.wrapper')
const items = document.querySelectorAll('.item')
data.width = wrapper.offsetWidth
data.len = items.length - 1
wrapper.addEventListener('touchstart', onStart)
wrapper.addEventListener('mousedown', onStart)
注意,这里在做高度之前,我们需要等图片加载完成之后才能拿到每一个元素的高度,我这里为了省懒就没写具体代码,上面的 heights
对应的是每个图片在渲染之后的高度,一般情况下最好让后端传回来带宽高,这样就不需要用 onload
再去处理这个。
鼠标按下时
function onStart(event) {
if (event.type === 'mousedown' && event.which !== 1) return
if (event.type === 'touchstart' && event.touches.length > 1) return
data.type = event.type === 'touchstart'
const events = data.type ? event.touches[0] || event : event
data.touching = true
data.clientX = events.clientX
data.startOffset = data.currentIndex * -data.width
data.ele.style.transition = `none`
window.addEventListener(data.type ? 'touchmove' : 'mousemove', onMove, { passive: false })
window.addEventListener(data.type ? 'touchend' : 'mouseup', onEnd, false)
}
上面的代码里面我做了PC和移动端的兼容,跟计划的一样,保存一下 clientX
坐标和一个初始的坐标 startOffset
这个由当前索引和父级宽度计算得到,场景是当从第二张图片滚动到第三张图片时,会把之前的第一张图片的距离也要加上去,不然就计算错误,看下面滑动时的代码。
另外在做监听移动的时候加上了 passive: false
是为了在移动端兼容处理。
鼠标移动时
function onMove(event) {
event.preventDefault()
if (!data.touching) return
const events = data.type ? event.touches[0] || event : event
data.distanceX = events.clientX - data.clientX
let translatex = data.startOffset + data.distanceX
if (translatex > 0) {
translatex = translatex > 30 ? 30 : translatex
} else {
const d = -(data.len * data.width + 30)
translatex = translatex < d ? d : translatex
}
data.ele.style.transform = `translate3d(${translatex}px, 0, 0)`
data.ele.style.webkitTransform = `translate3d(${translatex}px, 0, 0)`
}
做了一个边界处理的,超了 30 的距离就不让继续滑动了,加上之前保存的 startOffset
的值,得到的就是具体移动的距离了。
鼠标释放时
function onEnd() {
if (!data.touching) return
data.touching = false
// 通过计算 proportion 滑动的阈值拿到释放后的索引
if (Math.abs(data.distanceX) > data.width * data.proportion) {
data.currentIndex -= data.distanceX / Math.abs(data.distanceX)
}
if (data.currentIndex < 0) {
data.currentIndex = 0
} else if (data.currentIndex > data.len) {
data.currentIndex = data.len
}
const translatex = data.currentIndex * -data.width
data.ele.style.transition = 'all .3s ease'
data.ele.style.transform = `translate3d(${translatex}px, 0, 0)`
data.ele.style.webkitTransform = `translate3d(${translatex}px, 0, 0)`
window.removeEventListener(data.type ? 'touchmove' : 'mousemove', onMove, { passive: false })
window.removeEventListener(data.type ? 'touchend' : 'mouseup', onEnd, false)
}
通过计算 proportion
滑动的阈值拿到释放后的索引,也就是超过父级宽度的三分之一时释放就会滚动到下一张,拿到索引之后就可以设置需要移动的最终距离,记得加上 transition
做一个缓动效果,最后也别忘记移除事件的监听。
至此上面的简单的轮播效果就大功告成了,但是还缺少一点东西,就是本篇需要讲的自适应高度,为了方便理解就单独拿出来说一下。
高度自适应
在移动时就可以在里面做相关的代码整理了, onMove
函数里加上以下代码,来获取实时的高度。
const index = data.currentIndex
const currentHeight = data.heights[index]
// 判断手指滑动的方向拿到下一张图片的高度
let nextHeight = data.distanceX > 0 ? data.heights[index - 1] : data.heights[index + 1]
let diffHeight = Math.abs((nextHeight - currentHeight) * (data.distanceX / data.width))
let realHeight = currentHeight + (nextHeight - currentHeight > 0 ? diffHeight : -diffHeight)
data.ele.style.height = `${realHeight}px`
这里是移动时的高度变化,另外还需要在释放时也要处理, onEnd
函数里加上以下代码。
// ... 因为上面已经拿到了下一张的索引 currentIndex
const currentHeight = data.heights[data.currentIndex]
data.ele.style.height = `${currentHeight}px`
因为上面已经拿到了下一张的索引 currentIndex
所以再滚动到下一张是就直接通过数据获取就可以了。
以上就是实例详解如何给轮播图做自适应的高度的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341