不知道大家有沒有遇到這樣的需求或說看到類似的效果,就是清單進去詳情看輪播圖的時候,當手指滾動輪播圖時輪播的高度容器會自適應,這樣下面的內容就向上擠,滑動的過程會計算高度,釋放的時候也會滾到下一張,也會計算對應圖片的高度,然後做一個緩動的動畫效果。就像下面這張圖的樣子。
可以看到上面的圖片內容文字,隨著輪播的滑動高度也在改變。費話不多說直接上代碼。
實作方法
可以透過監聽滑鼠mounse
或手指的滑動touch
事件來控制圖片,這裡本文只說一下輪播的功能實現思路,重點說的是怎麼實現高度的自適應。
直接開始正文,先看 html 程式碼結構。
html 結構
<div> <div> <div> <div> <img alt="實例詳解如何給輪播圖做自適應的高度" > </div> <div> <img alt="實例詳解如何給輪播圖做自適應的高度" > </div> <div> <img alt="實例詳解如何給輪播圖做自適應的高度" > </div> </div> </div> <div>这是一段内容</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
,如果沒加上的話,就會出現兩個子集有空隙出現,加上之後空隙就會去掉。 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
所以再滚动到下一张是就直接通过数据获取就可以了。
以上是實例詳解如何給輪播圖做自適應的高度的詳細內容。更多資訊請關注PHP中文網其他相關文章!