這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 最近有一個頁面改版的需求,在UI走查階段,設計師說原來的輪播組件和新版頁面UI整體風格不搭,所以要換掉。 這裡就涉及到兩種輪播組件,一種是傳統的輪播組件,一種是設計師要的那種。 傳統的輪播組件,大家都見過,原理也清楚,就是把要輪播的 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
背景
最近有一個頁面改版的需求,在UI走查階段,設計師說原來的輪播組件和新版頁面UI整體風格不搭,所以要換掉。
這裡就涉及到兩種輪播組件,一種是傳統的輪播組件,一種是設計師要的那種。
傳統的輪播組件,大家都見過,原理也清楚,就是把要輪播的圖片橫向排成一個隊列,把他們當成一個整體,每次輪換,其實是把這個隊列整體往左平移X像素,這裡的X通常就是一個圖片的寬度。 這種效果可以參見vant組件庫里的swipe組件
而我們設計師要的輪播效果是另外一種,因為我利用端午假期已經做好了一個雛形,所以大家可以直接看Demo。
當然你也可以直接打開 騰訊視頻APP 首頁,頂部的輪播,就是我們設計師要的效果。
需求分析
新式輪播,涉及要兩個知識點:
- 圖片層疊
- 揭開效果
與傳統輪播效果一個最明顯的不同是,新的輪播效果需要把N張待輪播的圖片在Z軸上重疊放置,每次揭開其中的一張,下一張是自然漏出來的。這裡的實現方式也有多種,但最先想到的還是用zindex的方案。
第二個問題是如何實現揭開的效果。這裡就要使用到css3的新屬性mask。 mask是一系列css的簡化屬性。包括mask-image, mask-position等。 因為mask的系列屬性還有一定的相容性,所以一部分瀏覽器需要帶上-webkit-首碼才能生效。
還有少數瀏覽器不支持mask屬性,退化的情況是輪播必須有效,但是沒有輪換的動效。
實現
有了以上的分析,就可以把效果做出來了。核心代碼如下:
<script setup lang="ts"> import { ref, onMounted, watch } from "vue"; // 定義屬性 const props = defineProps([ 'imgList', 'duration', 'transitionDuration', 'maskPositionFrom', 'maskPositionTo', 'maskImageUrl' ]); // 定義響應式變數 const currentIndex = ref(0); const oldCurrentIndex = ref(0); const imgList = ref([...props.imgList, props.imgList[0]]); const getInitZindex = () => { const arr = [1]; for (let i = imgList.value.length - 1; i >= 1; i--) { arr.unshift(arr[0] + 1); } return arr; } const zIndexArr = ref([...getInitZindex()]); const maskPosition = ref(props.maskPositionFrom || 'left'); const transition = ref(`all ${props.transitionDuration || 1}s`); // 設置動畫參數 const transitionDuration = props.transitionDuration || 1000; const duration = props.duration || 3000; // 監聽currentIndex變化 watch(currentIndex, () => { if (currentIndex.value === 0) { zIndexArr.value = [...getInitZindex()]; } maskPosition.value = props.maskPositionFrom || 'left'; transition.value = 'none'; }) // 執行動畫 const execAnimation = () => { transition.value = `all ${props.transitionDuration || 1}s`; maskPosition.value = props.maskPositionFrom || 'left'; maskPosition.value = props.maskPositionTo || 'right'; oldCurrentIndex.value = (currentIndex.value + 1) % (imgList.value.length - 1); setTimeout(() => { zIndexArr.value[currentIndex.value] = 1; currentIndex.value = (currentIndex.value + 1) % (imgList.value.length - 1); }, 1000) } // 掛載時執行動畫 onMounted(() => { const firstDelay = duration - transitionDuration; function animate() { execAnimation(); setTimeout(animate, duration); } setTimeout(animate, firstDelay); }) </script> <template> <div class="fly-swipe-container"> <div class="swipe-item" :class="{'swipe-item-mask': index === currentIndex}" v-for="(url, index) in imgList" :key="index" :style="{ zIndex: zIndexArr[index], 'transition': index === currentIndex ? transition : 'none', 'mask-image': index === currentIndex ? `url(${maskImageUrl})` : '', '-webkit-mask-image': index === currentIndex ? `url(${maskImageUrl})`: '', 'mask-position': index === currentIndex ? maskPosition: '', '-webkit-mask-position': index === currentIndex ? maskPosition: '' }"> <img :src="url" alt=""> </div> <div class="fly-indicator"> <div class="fly-indicator-item" :class="{'fly-indicator-item-active': index === oldCurrentIndex}" v-for="(_, index) in imgList.slice(0, imgList.length - 1)" :key="index"></div> </div> </div> </template> <style lang="less" scoped> .fly-swipe-container { position: relative; overflow: hidden; width: 100%; height: inherit; .swipe-item:first-child { position: relative; } .swipe-item { position: absolute; width: 100%; top: 0; left: 0; img { display: block; width: 100%; object-fit: cover; } } .swipe-item-mask { mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: cover; -webkit-mask-size: cover; } .fly-indicator { display: flex; justify-content: center; align-items: center; z-index: 666; position: relative; top: -20px; .fly-indicator-item { margin: 0 5px; width: 10px; height: 10px; border-radius: 50%; background: gray; } .fly-indicator-item-active { background: #fff; } } } </style>
這是一個使用 Vue 3 構建的圖片輪播組件。在這個組件中,我們可以通過傳入一組圖片列表、切換動畫的持續時間、過渡動畫的持續時間、遮罩層的起始位置、遮罩層的結束位置以及遮罩層的圖片 URL 來自定義輪播效果。
組件首先通過 defineProps
定義了一系列的屬性,並使用 ref
創建了一些響應式變數,如 currentIndex
、 oldCurrentIndex
、 imgList
、 zIndexArr
等。
在 onMounted
鉤子函數中,我們設置了一個定時器,用於每隔一段時間執行一次輪播動畫。 在模板部分,我們使用了一個 v-for
指令來遍歷圖片列表,並根據當前圖片的索引值為每個圖片元素設置相應的樣式。同時,我們還為每個圖片元素添加了遮罩層,以實現輪播動畫的效果。
在樣式部分,我們定義了一些基本的樣式,如輪播容器的大小、圖片元素的位置等。此外,我們還為遮罩層設置了一些樣式,包括遮罩圖片的 URL、遮罩層的位置等。
總之,這是一個功能豐富的圖片輪播組件,可以根據傳入的參數自定義輪播效果。
後續
因為mask可以做的效果還有很多,後續該組件可以封裝更多輪播效果,比如從多個方向的揭開效果,各種漸變方式揭開效果。歡迎使用和提建議。