使用JavaScript練習(xí)動畫最好的方式封面過渡
引言
首先讓我們來看一個鏡頭,這個鏡頭展示了幾個過渡效果,其中之一就是我所說的 "封面過渡",一個黑色的封面以動畫形式隱藏了一些內(nèi)容,然后新的內(nèi)容在封面上顯現(xiàn)出來(其顏色與之前的不同)。

我喜歡我們可以在網(wǎng)頁中使用大量不同的動畫來展示新內(nèi)容的內(nèi)容。所以我們今天將在一個簡短的教程中看一下他的結(jié)構(gòu)和動畫的一些亮點。
我會使用GreenSock的GSAP作為效果的動畫庫。
標記和樣式
我會以下面這個網(wǎng)站來實現(xiàn)這個效果

首先,我們的整個頁面將是一個網(wǎng)格布局
html代碼
<div class="content"> <div class="item"> <span class="item__meta">2020</span> <h3 class="item__title">Alex Moulder</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/1.jpg)"></div></div> <p class="item__desc">I am only waiting for love to give myself up at last into his hands. That is why it is so late and why I have been guilty of such omissions.</p> <a class="item__link">view</a> </div> <div class="item"> <span class="item__meta">2021</span> <h3 class="item__title">Aria Bennett</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/2.jpg)"></div></div> <p class="item__desc">They come with their laws and their codes to bind me fast; but I evade them ever, for I am only waiting for love to give myself up at last into his hands.</p> <a class="item__link">view</a> </div> <div class="item"> <span class="item__meta">2022</span> <h3 class="item__title">Jimmy Hughes</h3> <div class="item__img"><div class="item__img-inner" style="background-image:url(img/3.jpg)"></div></div> <p class="item__desc">Clouds heap upon clouds and it darkens. Ah, love, why dost thou let me wait outside at the door all alone?</p> <a class="item__link">view</a> </div> </div>
CSS代碼
main {
padding: 1.5rem 2.5rem 3rem;
height: 100vh;
display: grid;
grid-template-columns: 100%;
grid-template-areas: 'frame' 'content';
grid-template-rows: min-content 1fr;
grid-row-gap: 8vh;
}
內(nèi)容劃分將有以下風(fēng)格,以顯示網(wǎng)格中的項目
.content {
grid-area: content;
max-width: 400px;
}
@media screen and (min-width: 53em) {
.content {
max-width: none;
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows: 100%;
grid-column-gap: 5vw;
}
}
我們只想在大屏幕上并排顯示項目。所以我們添加了一個媒體查詢。
對于項目的內(nèi)部元素,我們將具有以下樣式:
.item {
margin-bottom: 5rem;
display: grid;
grid-template-columns: 100%;
grid-template-rows: 1rem auto auto 1fr auto;
}
.item__title {
font-family: kudryashev-d-excontrast-sans, sans-serif;
font-weight: 300;
font-size: 2rem;
margin-bottom: 0.5rem;
}
.item__img {
position: relative;
overflow: hidden;
width: 100%;
aspect-ratio: 500/333;
}
.item__img-inner {
background-position: 50% 45%;
background-size: cover;
width: 100%;
height: 100%;
}
.item__desc {
margin-top: 2.5rem;
line-height: 1.1;
}
.item__link {
cursor: pointer;
text-transform: lowercase;
width: 100%;
padding: 1rem;
color: var(--color-text);
border: 1px solid var(--color-border);
border-radius: 2rem;
text-align: center;
}
.item__link:hover {
background: var(--color-text);
border-color: var(--color-text);
color: var(--color-text-alt);
}
@media screen and (min-width: 53em) {
.item {
margin-bottom: 0;
}
.item__title {
font-size: clamp(1.25rem,3vw,2rem);
}
}
圖像元素有一個嵌套結(jié)構(gòu),可以讓我們做出一點縮放效果。這里有一個有趣的地方是寬高比屬性,它允許我們在使用背景圖像屬性時根據(jù)其實際大小設(shè)置響應(yīng)式圖像尺寸。
當(dāng)我們單擊項目按鈕時,我們將顯示一個封面動畫。這將是動畫其比例變換以覆蓋整個頁面的兩個元素:
<div class="overlay"> <div class="overlay__row"></div> <div class="overlay__row"></div> </div>
讓我們添加以下樣式:
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 100%;
pointer-events: none;
grid-template-rows: repeat(2,1fr);
}
.overlay__row {
background: var(--color-overlay);
transform: scaleY(0);
will-change: transform;
}
.overlay__row:first-child {
transform-origin: 50% 0%;
}
.overlay__row:last-child {
transform-origin: 50% 100%;
}
為每一“行”設(shè)置正確的變換原點將確保它們上下動畫,“關(guān)閉”當(dāng)前視圖并隱藏它。
接下來,讓我們看一下我們將看到的視圖。此部分將稱為“預(yù)覽”,我們將添加以下內(nèi)容:
<section class="previews"> <div class="preview"> <div class="preview__img"><div class="preview__img-inner" style="background-image:url(img/1_big.jpg)"></div></div> <h3 class="preview__title oh"><span class="oh__inner">Moulder</span></h3> <div class="preview__column preview__column--start"> <span class="preview__column-title preview__column-title--main oh"><span class="oh__inner">Alex Moulder</span></span> <span class="oh"><span class="oh__inner">2020</span></span> </div> <div class="preview__column"> <h4 class="preview__column-title oh"><span class="oh__inner">Location</span></h4> <p>And if it rains, a closed car at four. And we shall play a game of chess, pressing lidless eyes and waiting for a knock upon the door.</p> </div> <div class="preview__column"> <h4 class="preview__column-title oh"><span class="oh__inner">Material</span></h4> <p>At the violet hour, when the eyes and back, turn upward from the desk, when the human engine waits.</p> </div> <button class="unbutton preview__back"><svg width="100px" height="18px" viewBox="0 0 50 9"><path vector-effect="non-scaling-stroke" d="m0 4.5 5-3m-5 3 5 3m45-3h-77"></path></svg></button> </div> <!-- preview --> <!-- preview --> </section>

大圖像將使用本教程中詳細解釋的顯示/取消顯示動畫進行動畫處理。這就是我們使用嵌套結(jié)構(gòu)的原因,就像在項目圖像上一樣。對于我們想要通過轉(zhuǎn)變(并被父級截斷)來顯示的文本,我們將使用 .oh > .oh__inner 結(jié)構(gòu)。這背后的想法是轉(zhuǎn)變oh__inner 元素以隱藏它。對于多行文本,我們將使用 JavaScript 動態(tài)添加此結(jié)構(gòu)。我們 preview__column 分區(qū)中的段落將使用SplitType分成幾行。
讓我們添加以下樣式以使線條魔術(shù)起作用:
.oh {
position: relative;
overflow: hidden;
}
.oh__inner {
will-change: transform;
display: inline-block;
}
.line {
transform-origin: 0 50%;
white-space: nowrap;
will-change: transform;
}
現(xiàn)在,讓我們把這個寶貝做成動畫
The JavaScript
讓我們先定義和實例化一些東西
import { gsap } from 'gsap';
import { Item } from './item';
import { Preview } from './preview';
// body element
const body = document.body;
// .content element
const contentEl = document.querySelector('.content');
// frame element
const frameEl = document.querySelector('.frame');
// 頂部和底部疊加的疊加元素
const overlayRows = [...document.querySelectorAll('.overlay__row')];
const previews = [];
[...document.querySelectorAll('.preview')].forEach(preview => previews.push(new Preview(preview)));
//項目實例列表
const items = [];
[...document.querySelectorAll('.item')].forEach((item, pos) => items.push(new Item(item, previews[pos])));
現(xiàn)在,當(dāng)我們打開一個項目時,我們首先要把我們的內(nèi)容設(shè)置為不能再點擊。用一個類來完成。
然后,我們在顯示預(yù)覽內(nèi)容后,隱藏所有那些我們想要動畫化的線條和元素。preview-visible類幫助我們設(shè)置一些顏色和指針事件。我們還用它來隱藏我們在頁面頂部的小框架,這樣,一旦封面隱藏了初始視圖,我們就可以用動畫再次顯示它。
通過將圖像元素向一個方向平移,將內(nèi)部元素(實際上包含了背景圖像)向相反的方向平移,圖像就不會被顯示出來。
我們也最終顯示了所有的線條和oh__inner元素。
const openItem = item => {
gsap.timeline({
defaults: {
duration: 1,
ease: 'power3.inOut'
}
})
.add(() => {
// 指針事件沒有指向內(nèi)容
contentEl.classList.add('content--hidden');
}, 'start')
.addLabel('start', 0)
.set([item.preview.DOM.innerElements, item.preview.DOM.backCtrl], {
opacity: 0
}, 'start')
.to(overlayRows, {
scaleY: 1
}, 'start')
.addLabel('content', 'start+=0.6')
.add(() => {
body.classList.add('preview-visible');
gsap.set(frameEl, {
opacity: 0
}, 'start')
item.preview.DOM.el.classList.add('preview--current');
}, 'content')
// Image animation (reveal animation)
.to([item.preview.DOM.image, item.preview.DOM.imageInner], {
startAt: {y: pos => pos ? '101%' : '-101%'},
y: '0%'
}, 'content')
.add(() => {
for (const line of item.preview.multiLines) {
line.in();
}
gsap.set(item.preview.DOM.multiLineWrap, {
opacity: 1,
delay:0.1
})
}, 'content')
// 動畫框架元素
.to(frameEl, {
ease: 'expo',
startAt: {y: '-100%', opacity: 0},
opacity: 1,
y: '0%'
}, 'content+=0.3')
.to(item.preview.DOM.innerElements, {
ease: 'expo',
startAt: {yPercent: 101},
yPercent: 0,
opacity: 1
}, 'content+=0.3')
.to(item.preview.DOM.backCtrl, {
opacity: 1
}, 'content')
};
當(dāng)我們關(guān)閉預(yù)覽時,我們需要做一些反向動畫
const closeItem = item => {
gsap.timeline({
defaults: {
duration: 1,
ease: 'power3.inOut'
}
})
.addLabel('start', 0)
.to(item.preview.DOM.innerElements, {
yPercent: -101,
opacity: 0,
}, 'start')
.add(() => {
for (const line of item.preview.multiLines) {
line.out();
}
}, 'start')
.to(item.preview.DOM.backCtrl, {
opacity: 0
}, 'start')
.to(item.preview.DOM.image, {
y: '101%'
}, 'start')
.to(item.preview.DOM.imageInner, {
y: '-101%'
}, 'start')
// 動畫框架元素
.to(frameEl, {
opacity: 0,
y: '-100%',
onComplete: () => {
body.classList.remove('preview-visible');
gsap.set(frameEl, {
opacity: 1,
y: '0%'
})
}
}, 'start')
.addLabel('grid', 'start+=0.6')
.to(overlayRows, {
//ease: 'expo',
scaleY: 0,
onComplete: () => {
item.preview.DOM.el.classList.remove('preview--current');
contentEl.classList.remove('content--hidden');
}
}, 'grid')
};
不要忘記事件監(jiān)聽器
for (const item of items) {
// 打開項目預(yù)覽
item.DOM.link.addEventListener('click', () => openItem(item));
// 關(guān)閉項目預(yù)覽
item.preview.DOM.backCtrl.addEventListener('click', () => closeItem(item));
}
這就是這一切的結(jié)果

在動畫進入時要有流暢的轉(zhuǎn)場動畫,并做一個快速的關(guān)閉動畫,這樣用戶就不必等待很長時間來恢復(fù)最初的視圖了。探索代碼并嘗試做一些其他的動畫、計時和緩和,給它另一種感覺,看看哪些是有效的,哪些是無效的!
以上就是使用JavaScript練習(xí)動畫最好的方式封面過渡的詳細內(nèi)容,更多關(guān)于JavaScript動畫封面過渡的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
LoadRunner調(diào)用JS加密后登錄實現(xiàn)
這篇文章主要為大家介紹了LoadRunner調(diào)用JS加密后登錄實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06

