重點(diǎn)聚焦!卡片放大播放效果實(shí)現(xiàn)總結(jié),不同元素間的放大過(guò)渡效果如何實(shí)現(xiàn)?
發(fā)布時(shí)間:2023-01-11 10:59:18
文章來(lái)源:程序員客棧
背景最近一段時(shí)間做了幾個(gè)需求,其中涉及的素材列表展示,需要實(shí)現(xiàn)類(lèi)似下方圖片中的動(dòng)效,暫且稱(chēng)之為【卡片放大播放動(dòng)效】,具體細(xì)節(jié)如下:初
背景
最近一段時(shí)間做了幾個(gè)需求,其中涉及的素材列表展示,需要實(shí)現(xiàn)類(lèi)似下方圖片中的動(dòng)效,暫且稱(chēng)之為【卡片放大播放動(dòng)效】,具體細(xì)節(jié)如下:
(相關(guān)資料圖)
初始展示的是封面圖片,鼠標(biāo)經(jīng)過(guò)時(shí)是視頻放大的效果;下方文字內(nèi)容區(qū)域,在放大前后展示的內(nèi)容不同,而且兩者的字體大小是一致的,不是簡(jiǎn)單的放大實(shí)現(xiàn);四五個(gè)頁(yè)面都需要實(shí)現(xiàn)相同列表效果,列表的行數(shù)和列數(shù)是不一致的;
image遇到的四個(gè)問(wèn)題
在整個(gè)實(shí)現(xiàn)過(guò)程中,遇到以下四個(gè)問(wèn)題,后面的解析中會(huì)有對(duì)應(yīng)解答。
不同元素間的放大過(guò)渡效果如何實(shí)現(xiàn)?抽離為通用性組件時(shí),如何實(shí)現(xiàn)類(lèi)vue中的具名插槽效果,來(lái)替換下方文字信息區(qū)域?不同頁(yè)面中的列表區(qū)域?qū)挾炔煌械捻?yè)面列表還是彈性寬度,常用的flex布局無(wú)法滿(mǎn)足要求,如何實(shí)現(xiàn)呢?邊界卡片放大后,如何避免被父級(jí)列表容器overflow:hidden`隱藏掉?實(shí)現(xiàn)解析
這個(gè)動(dòng)效,在愛(ài)奇藝官網(wǎng)也有類(lèi)似效果,愛(ài)奇藝官網(wǎng)是通過(guò)生成初始狀態(tài)卡片列表和鼠標(biāo)放大卡片列表兩套列表,然后通過(guò)動(dòng)態(tài)計(jì)算放大卡片位置,相對(duì)于body進(jìn)行絕對(duì)定位展示的。
本實(shí)現(xiàn)方案通過(guò)將卡片初始狀態(tài)和放大狀態(tài),封裝到一個(gè)組件中,通過(guò)兩者間的相對(duì)關(guān)系,利用css自動(dòng)完成對(duì)應(yīng)關(guān)系,避免了大量的JS計(jì)算。
1. 放大效果實(shí)現(xiàn)
UI對(duì)該動(dòng)效的要求實(shí)際就是鼠標(biāo)視頻放大播放,如果卡片初始狀態(tài)也放置視頻video,通過(guò)transition對(duì)同一元素進(jìn)行scale放大也可以實(shí)現(xiàn),但是這是一個(gè)列表,用戶(hù)進(jìn)入頁(yè)面,就會(huì)同時(shí)加載多個(gè)視頻,用戶(hù)體驗(yàn)不是很好。
所以,實(shí)現(xiàn)方案就是卡片初始狀態(tài)放置poster圖片,鼠標(biāo)經(jīng)過(guò)時(shí),在poster上方展示視頻層(絕對(duì)定位),然后對(duì)視頻執(zhí)行animation動(dòng)畫(huà)來(lái)模擬放大效果。
卡片底部文字區(qū)域如何處理?
由于卡片初始狀態(tài)下,底部文字區(qū)域在列表布局中是占位的,所以在卡片初始狀態(tài)下,底部文字區(qū)域使用正常文檔流。
卡片鼠標(biāo)經(jīng)過(guò)狀態(tài)下,視頻層的放大效果是以poster中心點(diǎn)為放大原點(diǎn)的,所以底部文字區(qū)域使用absolute定位,相對(duì)于player進(jìn)行定位處理。
interfaceIItemData{src?:string;poster?:string;industry?:string;}interfaceIProps{posterClass:string;//poster區(qū)域?qū)捀遬layerClass:string;//放大后視頻寬高樣式itemData:IItemData;children:{[key:string]:any};}lett:NodeJS.Timeout;constVideoItem:FC=({posterClass,playerClass,itemData,children,})=>{const[isHover,setIsHover]=useState(false);constonMouseEnter=()=>{t=setTimeout(()=>{//避免快速移動(dòng)鼠標(biāo),造成視頻無(wú)法隱藏問(wèn)題setIsHover(true);},50);};constonMouseLeave=()=>{clearTimeout(t);setIsHover(false);};return(Top1 {isHover?(
{children?.playerBottom}