ここで私がインターネット上でまとめた知識の一部を皆さんに共有しますので、皆さんのお役に立てれば幸いです。
背景
最近、ページの改訂が必要になりました。UI のウォークスルー中に、デザイナーは、元のカルーセル コンポーネントが新しいページ UI の全体的なスタイルと一致しないため、置き換える必要があると言いました。
ここには 2 種類のカルーセル コンポーネントが関係しています。1 つは従来のカルーセル コンポーネントで、もう 1 つはデザイナーが必要とするものです。
従来のカルーセル コンポーネントは誰もが見たことがありますが、原理は明らかです。水平方向に回転する画像をキューに配置し、それらを全体として扱うことです。実際に回転するたびに、キュー全体が左にシフトされます。 X ピクセル単位。ここでの X は通常、画像の幅です。この効果は、vant コンポーネント ライブラリのスワイプ コンポーネントで確認できます。
私たちのデザイナーが望んでいるメリーゴーランド効果は別のものです。端午節の休暇中にすでにプロトタイプを作成しているので、デモを直接見ることができます。
もちろん、Tencent Video APP のホームページを直接開くこともできます。上部のカルーセルはデザイナーが望む効果です。
需要分析
新しいカルーセルには 2 つのナレッジ ポイントが含まれます。
- 画像のカスケード
- 効果を明らかにする
従来のカルーセル効果との最も明白な違いの 1 つは、新しいカルーセル効果では、Z 軸上で回転する N 枚の画像を重ねて配置する必要があり、そのうちの 1 枚が露出されるたびに、次の画像が自然に漏れ出すことです。これを実現する方法もたくさんありますが、最初に思い浮かぶのは、zindex を使用する解決策です。
2番目の質問は、明らかにする効果をどのように達成するかです。ここではcss3の新しい属性マスクを使用します。マスクは CSS の一連の簡略化されたプロパティです。マスク画像、マスク位置などが含まれます。マスク シリーズの属性には一定の互換性があるため、一部のブラウザでは -webkit- プレフィックスを有効にする必要があります。
また、マスク属性をサポートしていないブラウザもいくつかあり、回転が有効である必要があるのに回転効果がないという縮退した状況が発生します。
成し遂げる
上記の分析により、効果が得られます。コアコードは次のとおりです。
<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、マスク レイヤーの位置など、マスク レイヤーのいくつかのスタイルも設定します。
つまり、これは機能が豊富な画像カルーセル コンポーネントであり、渡されたパラメーターに従ってカルーセル効果をカスタマイズできます。
フォローアップ
マスクで実行できるエフェクトは多数あるため、このコンポーネントは、将来的には、複数の方向からエフェクトを表示したり、さまざまなグラデーション方法でエフェクトを表示したりするなど、より多くのカルーセル エフェクトをカプセル化することができます。使用や提案は大歓迎です。
倉庫のアドレス: github.com/cunzaizhuyi…