Je ne sais pas si vous avez rencontré un tel besoin ou vu un effet similaire, c'est-à-dire que lorsque vous entrez dans la liste et visualisez l'image du carrousel en détail, la hauteur du conteneur du carrousel s'adaptera lorsque votre doigt fera défiler l'image du carrousel , de sorte que le contenu suivant soit simplement pressé vers le haut, la hauteur sera calculée pendant le processus de glissement, et il défilera jusqu'à l'image suivante une fois libéré. Il calculera également la hauteur de l'image correspondante, puis créera un effet d'animation lent. Tout comme l'image ci-dessous.
Vous pouvez voir le contenu de l'image et le texte ci-dessus, et la hauteur du carrousel change à mesure que le carrousel glisse. Sans plus tarder, passons directement au code.
Méthode d'implémentation
Vous pouvez contrôler les images en écoutant les événementsmounse
de la souris ou en glissant le doigttouch
Ici, cet article ne parlera que de l'idée de. mise en œuvre de la fonction carrousel. Les points clés Il s’agit de savoir comment atteindre un haut degré d’adaptabilité.mounse
或者手指的滑动touch
事件来控制图片,这里本文只说一下轮播的功能实现思路,重点说的是怎么实现高度的自适应。
直接开始正文,先看 html 代码结构。
html 结构
这是一段内容
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
,如果没加上的话,就会出现两个子集有空隙出现,加上之后空隙就会去掉。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`
// ... 因为上面已经拿到了下一张的索引 currentIndex const currentHeight = data.heights[data.currentIndex] data.ele.style.height = `${currentHeight}px`
espace blanc
parent, les éléments de sous-ensemble Setting < code>display: inline-blockprovoquera un désalignement avec différentes hauteurs. La solution est d'ajoutervertical-align: top
. Je n'entrerai pas dans les détails sur les raisons spécifiques.font-size : 0
. S'il n'est pas ajouté, il y aura un écart entre les deux sous-ensembles. Après l'avoir ajouté, l'écart sera créé. sera supprimé.100%
et ledisplay: block
ajoutés. Sinon, il y aura. il y a un espace en bas.html
ci-dessus, examinons comment
js
est traité. Implémentation de JsAvant de commencer, réfléchissons d'abord à la manière d'implémenter ce problème de carrousel et d'adaptation en hauteur, qui se divise en plusieurs étapes
transform
, d'autres traitements de limites sont également effectués au milieu, et bien sûr, il y a des changements de hauteur.hauteurs
ci-dessus correspond à la hauteur de chaque image après le rendu. en général, c'est le meilleur. Cela permet au backend de renvoyer une bande passante élevée, il n'est donc pas nécessaire d'utiliser
onload
pour traiter cela.
clientX Coordonnées et une coordonnée initiale startOffset
Ceci est calculé à partir de l'index actuel et de la largeur parent Le scénario est que lors du défilement de la deuxième image à la troisième image, la première image précédente sera La distance doit. également être ajouté, sinon le calcul sera erroné Voir le code coulissant ci-dessous. De plus,
passive: false
est ajouté lors de la surveillance des mouvements dans un but de compatibilité côté mobile.
Lorsque la souris bouge
rrreee a effectué un traitement de limite et ne permettra pas de glisser davantage au-delà de la distance de 30, plus le
startOffset précédemment enregistré
La valeur obtenue est la distance spécifique parcourue.
Lorsque la souris est relâchée
rrreeeEn calculant le seuil glissant de
proportion
, on obtient l'indice après relâchement, qui est trois fois plus que la largeur du parent. Une fois relâché, il défilera jusqu'à la suivante. Après avoir obtenu l'index, vous pouvez définir la distance finale à déplacer. N'oubliez pas d'ajouter une
transition
pour créer un effet d'assouplissement. oublier de supprimer l'événement à la fin de la surveillance. À ce stade, le simple effet carrousel ci-dessus est terminé, mais il manque encore une chose, à savoir la hauteur adaptative dont nous devons parler dans cet article. Pour faciliter la compréhension, j'en parlerai séparément. Adaptatif à la hauteurVous pouvez y organiser le code pertinent lors du déplacement. Ajoutez le code suivant à la fonction
onMove
pour obtenir la hauteur en temps réel.
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`
Copier après la connexion
Copier après la connexion
这里是移动时的高度变化,另外还需要在释放时也要处理,onEnd
函数里加上以下代码。
// ... 因为上面已经拿到了下一张的索引 currentIndex const currentHeight = data.heights[data.currentIndex] data.ele.style.height = `${currentHeight}px`
Copier après la connexion
Copier après la connexion
因为上面已经拿到了下一张的索引currentIndex
所以再滚动到下一张是就直接通过数据获取就可以了。
推荐学习:《
web前端开发视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!