gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

你了解 Transition 嗎?一起來深入了解下Transition!

你了解 Transition 嗎?你可能并不了解 Transition?下面本篇文章就來通過圖文結合的方式帶大家深入了解一下Transition,希望對大家有所幫助!

你了解 Transition 嗎?一起來深入了解下Transition!

這篇文章我們深入學習 Transition 動畫。沒錯,CSS3 Transition 動畫。你可能會問,不是很簡單嗎,這什么好講的?

確實,Transition 動畫使用起來非常容易。只需要給元素加上 transition-delay, transition-duration, transition-property, transition-timing-function 屬性就可以有過濾效果。更簡單的用法是直接使用簡寫的 transition 屬性:

transition: <property> <duration> <timing-function> <delay>;  // transition-delay 默認為 0 // transition-property 默認為 all // transition-timing-function 默認為 ease transition: 0.3s;

由于 transition 動畫用起來幾乎沒有成本,一直以來也沒有太深入學習,最近翻看源代碼和 MDN 文檔之后發現有些知識沒有理解到位,于是乎有了這篇文章,希望對讀者更深入了解 Transition 動畫有所幫助。(學習視頻分享:css視頻教程)

為了盡量降低閱讀理解成本,這篇文章會寫得稍微啰嗦一點點,大部分示例都會配圖 ——【多圖預警開始!】

什么是 Transition?

簡單的說就是過渡動畫,通常修改 DOM 節點的樣式都是立即更新在頁面上的,例如修改寬高,修改透明度,修改背景色等等。

例如當鼠標移動至按鈕上時,為了突出按鈕的可交互,會在 hover 時修改它的樣式,讓用戶注意到它。沒有加 transition 過渡動畫,給用戶的感覺會很僵很生硬。

.button {   // ...   background-color: #00a8ff; }  .button:hover {   background-color: #fbc531;   transform: scale(1.2); }

你了解 Transition 嗎?一起來深入了解下Transition!

加上 transition 一行代碼之后,變化就會比較順滑。

.button {   // ...   transition: 1s; } // ...

這個例子中我們修改了 background-colortransform,結合 transition 屬性,瀏覽器就會自動讓屬性值隨著時間變化,從舊值逐步過渡到過渡新值,視覺上就是動畫效果。

你了解 Transition 嗎?一起來深入了解下Transition!

區分于 AnimationTransition 動畫側重于表現一次過渡效果,從開始到結束的變化。而 Animation 不需要變化,可以循環播放 ▶️。

需要注意,并不是所有的屬性變化都會有過渡效果

  1. 有些 CSS 屬性只支持枚舉值,非黑即白,不存在中間狀態,例如 visibility: visible; 被修改成 visibility: hidden; 不會有動畫效果,因為不存在可見又不可見的中間狀態。在瀏覽器上的表現是 duration 到了之后元素立即突變為 hidden。

    .button:hover {   //...   visibility: hidden; }

    你了解 Transition 嗎?一起來深入了解下Transition!

  2. 有些屬性雖然是可計算數值,但天生注定不能有過渡效果,例如 transition-delaytransition-duration 都是立即生效,這里值得補一句由于 transition-* 屬性是即時生效,這行代碼如果是 hover 時才加上,那么效果會是 hover 時有動畫,移出時沒有動畫。
  3. 即使是可過渡的屬性變化,也可能因為無法計算中間狀態而失去過渡效果。例如 box-shadow 屬性雖然支持 transition 的動畫的,但如果從 "outset" 切換到 inset,也是突變的。

    .button {   // ...   box-shadow: 0 0 0 1px rgb(0 0 0 / 15%);   transition: 1s; }  .button:hover {   // ...   box-shadow: inset 0 0 0 10px rgb(0 0 0 / 15%); }

    你了解 Transition 嗎?一起來深入了解下Transition!
    從表現上看,box-shadow 的變化是 hover 上去立馬就生效了。

  4. 如果某個屬性值是連續可計算的數值,但是變化前后變成散列的枚舉值,那么過渡也不會生效。例如從 height: 100px => height: auto 是不會有動畫的。

以上的內容回顧了 Transition 的基本用法,下面我們來看一個在實際開發場景中會遇到的問題。

為什么 Transition 動畫沒有生效?

場景題:假設我們現在接到一個自定義下拉選擇器的動畫需求,設計師給到的效果圖如下:

你了解 Transition 嗎?一起來深入了解下Transition!

這是很常見的出現-消失動畫,在很多組件庫里面都會出現,點擊觸發器(按鈕)時才在頁面上渲染 Popup (下拉內容),并且 Popup 出現的同時需要有漸現和下滑的動畫;展開之后再次點擊按鈕,Popup 需要漸隱和上滑。

平時使用的時候并沒有過多注意它的實現,不妨現在讓我們動手試驗一下。

暫時忽略 popup 的內容,用了個 div 來占位模擬,HTML 結構很簡單。

<div class="wrapper">     <div id="button"></div>     <div id="popup"></div> </div>

在點擊按鈕的時候,讓 popup 顯示/隱藏,然后切換 popup.active 類名。

const btn = document.querySelector("#button"); const popup = document.querySelector("#popup");  if (!popup.classList.contains("active")) {     popup.style.display = "block";     popup.classList.add("active"); } else {     popup.style.display = "none";     popup.classList.remove("active"); }

編寫 CSS 樣式,在不 active 時透明度設置為 0,向上偏移,active 時則不偏移且透明度設置為 1。

#popup {   display: none;   opacity: 0;   transform: translateY(-8px);   transition: 1s;    &.active {     opacity: 1;     transform: translateY(0%);   } }

完整代碼 在這里,看起來代碼沒什么問題,點擊按鈕切換的時候,popup 應該會有動畫過渡效果。然而實際運行效果:

你了解 Transition 嗎?一起來深入了解下Transition!

硬邦邦地完全沒有過渡效果,這是為啥?明明已經設置了 transition,且 opacitytranslateY 都是可計算可過渡的數值,也產生了變化,瀏覽器為什么不認呢?

在查文檔之前,我們先嘗試使用萬精油 setTimeout

方案一:setTimeout 萬精油

修改 JS 代碼:

btn.addEventListener("click", () => {   if (!popup.classList.contains("active")) {     popup.style.display = "block";     setTimeout(() => {       popup.classList.add("active");     }, 0);   } else {     popup.classList.remove("active");     setTimeout(() => {       popup.style.display = "none";     }, 600);   } });

可以看到添加了 setTimeout 之后,transition 動畫就生效了。

你了解 Transition 嗎?一起來深入了解下Transition!

隱藏時的 setTimeout 600ms 對應 CSS 中設置的 transition: 0.6s,就是動畫完成之后才將 display 設置為 none

主要困惑的點在于為什么顯示的時候也需要加 setTimeout 呢?setTimeout 0 在這里起到的作用是什么?帶著問題去翻看規范文檔。

在規范文檔的 Starting of transitions 章節找到下面這段話:

When a style change event occurs, implementations must start transitions based on the computed values that changed in that event. If an element is not in the document during that style change event or was not in the document during the previous style change event, then transitions are not started for that element in that style change event.

翻譯一下,當樣式變更事件發生時,實現(瀏覽器)必須根據變更的屬性執行過渡動畫。但如果樣式變更事件發生時或上一次樣式變更事件期間,元素不在文檔中,則不會為該元素啟動過渡動畫。

結合瀏覽器構建 RenderTree 的過程,我們可以很清晰地定位到問題:當樣式變更時間發生時,display: none 的 DOM 元素并不會出現在 RenderTree 中(style.display='block' 不是同步生效的,要在下一次渲染的時候才會更新到 Render Tree),不滿足 Starting of transitions 的條件。

你了解 Transition 嗎?一起來深入了解下Transition!

所以 setTimeout 0 的作用是喚起一次 MacroTask,等到 EventLoop 執行回調函數時,瀏覽器已經完成了一次渲染,再加上 .active 類名,就有了執行過渡動畫的充分條件。

優化方案二:精準卡位 requestAnimationFrame

既然目的為了讓元素先出現到 RenderTree 中,和渲染相關,很容易想到可以將 setTimeout 替換成 requestAnimationFrame,這樣會更精準,因為 requestAnimation 執行時機和渲染有關。

if (!popup.classList.contains("active")) {     popup.style.display = "block";      requestAnimationFrame(() => {         popup.classList.add("active");     }); }

補充一個小插曲:在查找資料的過程中了解到 requestAnimationFrame 的規范是要求其回調函數在 Style/Layout 等階段之前執行,起初 Chrome 和 Firefox 是遵循規范來實現的。而 Safari 和 Edge 是在執行的時機是在之后。 從現在的表現上來看,Chrome 和 Firefox 也改成了在之后執行,翻看以前的文檔會說需要嵌套兩層 requestAnimationFrame,現在已經不需要了。Is requestAnimationFrame called at the right point?

優化方案三:Force Reflow

在規范文檔中,還留意到以下這句話:

Implementations typically have a style change event to correspond with their desired screen refresh rate, and when up-to-date computed style or layout information is needed for a script API that depends on it.

意思是說,瀏覽器通常還會在兩種情況下會產生樣式變更事件,一是滿足屏幕刷新頻率(不就是 requestAnimationFrame?),二是當 JS 腳本需要獲取最新的樣式布局信息時。

在 JS 代碼中,有些 API 被調用時,瀏覽器會同步地計算樣式和布局,頻繁調用這些 API(offset*/client*/getBoundingClientRect/scroll*/…等等)通常會成為性能瓶頸。

你了解 Transition 嗎?一起來深入了解下Transition!

然而在這個場景卻可以產生奇妙的化學反應:

if (!popup.classList.contains("active")) {   popup.style.display = "block";   popup.scrollWidth;   popup.classList.add("active"); }

注意看,我們只是 display 和 add class 之間讀取了一下 scrollWidth,甚至沒有賦值,過渡動畫就活過來了。

你了解 Transition 嗎?一起來深入了解下Transition!

原因是 scrollWidth 強制同步觸發了重排重繪,再下一行代碼時,popup 的 display 屬性已經更新到 Render Tree 上了。

優化方案四:過渡完了告訴我 onTransitionEnd

現在【出現】動畫已經搞明白了,在看開源庫的源碼中發現像 vue, bootstrap, react-transition-group 等庫都是使用了 force reflow 的方法,而 antd 所使用的 css-animte 庫則是通過設置 setTimeout。

【消失】動畫還不夠優雅,前面我們是直接寫死 setTimeout 600,讓元素在動畫結束時消失的。這樣編碼可復用性差,修改動畫時間還得改兩處地方(JS + CSS),有沒有更優雅的實現?

popup.classList.remove("active");setTimeout(() => {     popup.style.display = "none"; }, 600);

文檔中也提到了 Transition Events,包括 transitionruntransitionstarttransitionendtransitioncancel,看名字就知道事件代表什么意思,這里可以用 transitionend 進行代碼優化。

if (!popup.classList.contains("active")) {     popup.style.display = "block";     popup.scrollWidth;     popup.classList.add("active"); } else {     popup.classList.remove("active");     popup.addEventListener('transitionend', () => {         popup.style.display = "none";     }, { once: true }) }

需要注意 transition events 同樣也有冒泡、捕獲的特性,如果有嵌套 transition 時需要留意 event.target

到這里我們已經用原生 JS 完成了一個出現、消失的動畫實現,完整的代碼在這里。文章的最后,我們參照 vue-transition 來開發一個 React Transition 的單個元素動畫過渡的最小實現。

仿 v-transition 實現一個 React Transition 組件

你了解 Transition 嗎?一起來深入了解下Transition!

根據動畫過程拆分成幾個過程:

  • enter 階段渲染 DOM 節點,初始化動畫初始狀態(添加 *-enter 類名)
  • enter-active 階段執行 transition 過渡動畫(添加 *-enter-active 類名)
  • enter-active 過渡完成之后進入正常展示階段(移除 *-enter-active 類名)

enter-to 和 leave-to 暫時用不上,leave 階段和 enter 基本一致也不再贅述。

直接看代碼:

export const CSSTransition = (props: Props) => {   const { children, name, active } = props;   const nodeRef = useRef<HTMLElement | null>(null);   const [renderDOM, setRenderDOM] = useState(active);    useEffect(() => {     requestAnimationFrame(() => {       if (active) {         setRenderDOM(true);         nodeRef.current?.classList.add(`${name}-enter`);         // eslint-disable-next-line @typescript-eslint/no-unused-expressions         nodeRef.current?.scrollWidth;         nodeRef.current?.classList.remove(`${name}-enter`);         nodeRef.current?.classList.add(`${name}-enter-active`);          nodeRef.current?.addEventListener("transitionend", (event) => {           if (event.target === nodeRef.current) {             nodeRef.current?.classList.remove(`${name}-enter-active`);           }         });       } else {         nodeRef.current?.classList.add(`${name}-leave`);         // eslint-disable-next-line @typescript-eslint/no-unused-expressions         nodeRef.current?.scrollWidth;         nodeRef.current?.classList.remove(`${name}-leave`);         nodeRef.current?.classList.add(`${name}-leave-active`);          nodeRef.current?.addEventListener("transitionend", (event) => {           if (event.target === nodeRef.current) {             nodeRef.current?.classList.remove(`${name}-leave-active`);             setRenderDOM(false);           }         });       }     });   }, [active, name]);    if (!renderDOM) {     return null;   }    return cloneElement(Children.only(children), {     ref: nodeRef   }); };

這個組件接收三個 props,分別是

  • children 需要做過渡動畫的 ReactElement,只允許傳一個 Element
  • name 過渡動畫的 css 類名前綴
  • active 布爾值,用于區分是進場還是消失

使用方式:

<CSSTransition name="fade" active={active}>     // 一個需要做過渡動畫的 ReactElement </CssTransition>

借助 transition-delay,加一點技巧實現 stagger 效果:

你了解 Transition 嗎?一起來深入了解下Transition!

完整的示例代碼在這里,注意:這只是個快速實現用于演示的示例,有非常多的問題沒有考慮在內,僅可用于學習參考。

結語

原本以為非常基礎簡單的知識點,分分鐘可以寫完這篇文章。沒想到中途查文檔,看資料,制作演示 DEMO 還是花了不少時間。好在整理資料的過程中也理清了很多知識點。希望這篇文章對你熟悉 Transition 動畫有所幫助 。

贊(0)
分享到: 更多 (0)
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
亚洲77777| 亚洲精品久久久中文字幕| 国产精品视频中文字幕| 男女视频网站在线观看| 熟女视频一区二区三区| www.涩涩涩| 91精品无人成人www| 久久综合久久色| 免费观看日韩毛片| 欧美 日韩 激情| 国内自拍在线观看| 国产男女激情视频| www黄色在线| 欧美婷婷精品激情| 天美星空大象mv在线观看视频| 日韩a在线播放| 美女少妇一区二区| 午夜久久福利视频| 亚洲一级片免费观看| 少妇一晚三次一区二区三区| 91国在线高清视频| 成人黄色av片| www.xxx亚洲| www激情五月| 99热亚洲精品| 又色又爽又高潮免费视频国产| 欧美黄色性生活| 六月婷婷激情网| 国产九九九九九| 中文字幕永久有效| 欧美激情亚洲天堂| 国产xxxxx视频| wwwjizzjizzcom| 国内外免费激情视频| 青青草原播放器| av黄色在线网站| 午夜宅男在线视频| 丰满少妇大力进入| 拔插拔插华人永久免费| 成人区一区二区| 中文字幕 日韩 欧美| 99国产精品白浆在线观看免费| 欧美精品一区二区三区免费播放| 欧美日韩久久婷婷| 欧美日韩在线成人| 国产在线播放观看| 日韩视频在线观看一区二区三区| av一区二区三区免费观看| 蜜臀一区二区三区精品免费视频| 黄色片免费在线观看视频| 日本www.色| 久草资源站在线观看| 欧美乱做爰xxxⅹ久久久| 一级黄色高清视频| 日韩av手机版| 97国产精东麻豆人妻电影| 强伦女教师2:伦理在线观看| 色婷婷777777仙踪林| 国产一级片自拍| 久久久久久久片| 97xxxxx| a级黄色片免费| 久久国产精品免费观看| 久久精品影视大全| 日本成人黄色网| 亚洲乱码中文字幕久久孕妇黑人| av无码久久久久久不卡网站| 欧美三级午夜理伦三级老人| 中文字幕亚洲影院| 国产精品中文久久久久久| 小早川怜子一区二区三区| 亚洲一区二区蜜桃| 免费一级特黄录像| 亚洲 欧美 日韩系列| 色婷婷成人在线| 九九热视频免费| 400部精品国偷自产在线观看| 爱豆国产剧免费观看大全剧苏畅| jizzzz日本| 伊人色在线视频| 国产制服91一区二区三区制服| 韩国黄色一级大片| 欧美国产视频一区| 国产成人久久婷婷精品流白浆| 成人三级视频在线播放| www.色欧美| 男女视频在线观看网站| 路边理发店露脸熟妇泻火| 国产精品va在线观看无码| 麻豆tv在线播放| 天天影视综合色| 中文字幕av导航| 精品久久久久久久久久中文字幕 | 日韩精品免费播放| 亚洲国产精品三区| 日本成人在线不卡| 国产午夜福利视频在线观看| 国产野外作爱视频播放| 亚洲女人在线观看| 北条麻妃在线视频观看| 热久久久久久久久| 国产女大学生av| av磁力番号网| 欧美精品aaaa| 久久人人爽人人爽人人av| 激情视频综合网| www.日本三级| 亚洲 国产 图片| 免费在线观看日韩视频| 国内av免费观看| 簧片在线免费看| www.av毛片| 只有这里有精品| 激情 小说 亚洲 图片: 伦| 日韩亚洲欧美一区二区| 一起操在线视频| 免费黄色特级片| 9久久9毛片又大又硬又粗| www.国产视频.com| 久久精品网站视频| 97中文字幕在线| 路边理发店露脸熟妇泻火| 成人亚洲精品777777大片| 凹凸国产熟女精品视频| 18黄暴禁片在线观看| 亚洲 欧洲 日韩| 三日本三级少妇三级99| 8x8x最新地址| 国产午夜精品视频一区二区三区| 国产精品无码av无码| 国产一区二区在线视频播放| 亚洲精品天堂成人片av在线播放 | 91蝌蚪视频在线观看| 国产91对白刺激露脸在线观看| 国产又粗又猛又爽又黄的网站| 在线黄色免费观看| 99sesese| 天天干天天色天天干| 在线免费观看视频黄| 羞羞的视频在线| 婷婷免费在线观看| 污污的视频免费观看| 亚洲国产午夜精品| 国产成人精品免费看在线播放 | 成人污网站在线观看| 久久久久福利视频| 国产原创popny丨九色| 无码精品a∨在线观看中文| 无罩大乳的熟妇正在播放| 男女高潮又爽又黄又无遮挡| 久久午夜夜伦鲁鲁一区二区| 一级黄色在线播放| 中文字幕av久久| 久久久国内精品| 日韩欧美不卡在线| 成人羞羞国产免费网站| 日本www.色| 欧美一级特黄aaaaaa在线看片| 久久www视频| 男女视频一区二区三区| 国产免费色视频| 国产主播在线看| 欧美成人手机在线视频| 黄色激情在线视频| www.xxx亚洲| 乱子伦一区二区| 久久人妻精品白浆国产| 91看片淫黄大片91| 日本爱爱免费视频| 国产美女永久无遮挡| 在线免费av播放| 国产原创popny丨九色| 第一区免费在线观看| 国产日韩欧美精品在线观看| 久久久久久久久久久久久久久国产| 91成人综合网| 爱爱爱视频网站| 亚洲免费看av| 韩国日本在线视频| 激情五月六月婷婷| 97人人爽人人| 亚洲精品乱码久久久久久自慰| 国产又粗又长又爽视频| 嫩草av久久伊人妇女超级a| 黄色一级在线视频| 9色视频在线观看| 欧美激情第一区| 国产九九热视频| 一道本视频在线观看| 国内精品在线观看视频| 精品人妻人人做人人爽| 一区二区三区一级片| 久久久久久久高清| 性猛交ⅹ×××乱大交| 国产性生交xxxxx免费| 熟女性饥渴一区二区三区| 国产免费观看高清视频| 欧美在线一区视频| 国产原创中文在线观看| 久久久亚洲国产精品|