全新版FRIDA與安卓 應用安全與逆向?qū)崙?zhàn)寶典(原版)
全新版FRIDA與安卓 應用安全與逆向?qū)崙?zhàn)寶典(原版)
download:https://www.zxit666.com/6432/
卡片的 3D 旋轉(zhuǎn)跟隨效果
OK,接下來,如何完成 3D 卡片效果呢?
這個交互效果主要有兩個中心:
借助了 CSS 3D 的才能
元素的旋轉(zhuǎn)需求和鼠標的挪動相分離
這里,我們其實有兩個中心元素:
鼠標活動區(qū)域
旋轉(zhuǎn)物體自身
鼠標在鼠標活動區(qū)域內(nèi)的挪動,會影響旋轉(zhuǎn)物體自身的 3D 旋轉(zhuǎn),而旋轉(zhuǎn)的方向其實能夠被合成為 X 軸方向與 Y 軸方向。
我們來看一下,假定我們的 HTML 構(gòu)造如下:
<body> ? ?<div id="element"></div></body>
這里,body
?的范圍就是整個鼠標可活動區(qū)域,也是我們添加鼠標的?mousemove
?事情的宿主 target,而?#element
?就是需求跟隨鼠標一同轉(zhuǎn)動的旋轉(zhuǎn)物體自身。
由于整個效果是需求基于 CSS 3D 的,我們首先加上簡單的 CSS 3D 效果:
body { ? ?width: 100vw; ? ?height: 100vh; ? ?transform-style: preserve-3d; ? ?perspective: 500px; }div { ? ?width: 200px; ? ?height: 200px; ? ?background: #000; ? ?transform-style: preserve-3d; }
沒有什么不一樣。這是由于還沒有添加任何的 3D 變換,我們給元素添加 X、Y 兩個方向的?rotate()
?試一下(留意,這里默許的旋轉(zhuǎn)圓心即是元素中心):
div { ? ? transform: rotateX(15deg) rotateY(30deg); }
效果如下,是有那么點意義了
好,接下來,我們的目的就是經(jīng)過分離 mouseover 事情,讓元素動起來。
控制 X 方向的挪動
當然,為了愈加容易了解,我們把動畫拆分為 X、Y 兩個方向上的挪動。首先看 X 方向上的挪動:
這里,我們需求以元素的中心為界:
當鼠標在中心右側(cè)連續(xù)挪動,元素繞 Y 軸挪動,并且值從 0 開端,越來越大,范圍為(0, +∞)deg
反之,當鼠標在中心左側(cè)連續(xù)挪動,元素繞 Y 軸挪動,并且值從 0 開端,越來越小,范圍為(-∞, 0)deg
這樣,我們能夠得到這樣一個公式:
rotateY = (鼠標 x 坐標 - 元素左上角 x 坐標 - 元素寬度的一半)deg
經(jīng)過綁定 onmousemove 事情,我們嘗試一下:
const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { ?let box = element.getBoundingClientRect(); ?let calcY = e.clientX - box.x - (box.width / 2); ? ? ?element.style.transform ?= "rotateY(" + calcY + "deg) "; }
好吧,旋轉(zhuǎn)的太夸大了,因而,我們需求加一個倍數(shù)停止控制:
const multiple = 20;const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { ?let box = element.getBoundingClientRect(); ?let calcY = (e.clientX - box.x - (box.width / 2)) / multiple; ? ? ?element.style.transform ?= "rotateY(" + calcY + "deg) "; }
經(jīng)過一個倍數(shù)約束后,效果好了不少
控制 Y 方向的挪動
同理,我們應用上述的方式,同樣能夠控制 Y 方向上的挪動:
const multiple = 20;const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { ?let box = element.getBoundingClientRect(); ?let calcX = (e.clientY - box.y - (box.height / 2)) / multiple; ? ? ?element.style.transform ?= "rotateX(" + calcX + "deg) "; };
當然,在這里,我們會發(fā)現(xiàn)方向是元素運動的方向是反的,所以需求做一下取反處置,修正下?calcX
?的值,乘以一個?-1
?即可:
let calcX = (e.clientY - box.y - (box.height / 2)) / multiple * -1;
分離 X、Y 方向的挪動
OK,到這里,我們只需求把上述的結(jié)果兼并一下即可,同時,上面我們運用的是?onmousemove
?觸發(fā)每一次動畫挪動?,F(xiàn)代 Web 動畫中,我們更傾向于運用?requestAnimationFrame
?去優(yōu)化我們的動畫,確保每一幀渲染一次動畫即可。
完好的改造后的代碼如下:
const multiple = 20;const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element");function transformElement(x, y) { ?let box = element.getBoundingClientRect(); ?let calcX = -(y - box.y - (box.height / 2)) / multiple; ?let calcY = (x - box.x - (box.width / 2)) / multiple; ? ?element.style.transform ?= "rotateX("+ calcX +"deg) " ? ? ? ? ? ? ? ? ? ? ? ?+ "rotateY("+ calcY +"deg)"; } mouseOverContainer.addEventListener('mousemove', (e) => { ?window.requestAnimationFrame(function(){ ? ?transformElement(e.clientX, e.clientY); ?}); });
至此,我們就能簡單的完成題圖所示的鼠標跟隨 3D 旋轉(zhuǎn)動效:
設(shè)置平滑出入
如今,還有最后一個問題,就是當我們的鼠標分開活動區(qū)域時,元素的 transform 將停留在最后一幀,正確的表現(xiàn)應該是恢復到原狀。因而,我們還需求添加一些事情監(jiān)聽做到元素的平滑復位。
經(jīng)過一個?mouseleave
?事情配合元素的?transition
?即可。
div { ? ?// 與上述堅持分歧... ? ?transition: all .2s; }mouseOverContainer.addEventListener('mouseleave', (e) => { ?window.requestAnimationFrame(function(){ ? ?element.style.transform = "rotateX(0) rotateY(0)"; ?}); });
至此,我們就能夠圓滿的完成平滑出入,
基于上述的鋪墊,我們改造一下我們的 DEMO,只是把上述 DEMO 中中心的黑塊,交換成我們的毛玻璃元素,將背景交換成圖片。
完好的代碼:
<div id="element"></div>
CSS 代碼:
body { ? ?width: 100vw; ? ?height: 100vh; ? ?transform-style: preserve-3d; ? ?background: url(https://picsum.photos/id/242/1920/1080); }div { ? ?width: 600px; ? ?height: 300px; ? ?transform-style: preserve-3d; ? ?backdrop-filter: blur(15px); ? ?background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.5)); ? ?transition: all 0.3s; }
Javascript 代碼:
const multiple = 25;const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element");function transformElement(x, y) { ?const box = element.getBoundingClientRect(); ?const calcX = -(y - box.y - (box.height / 2)) / multiple; ?const calcY = (x - box.x - (box.width / 2)) / multiple; ?let angle = Math.floor(getMouseAngle((y - box.y - (box.height / 2)), (x - box.x - (box.width / 2)))); ?element.style.transform ?= "rotateX("+ calcX +"deg) " + "rotateY("+ calcY +"deg)"; } mouseOverContainer.addEventListener('mousemove', (e) => { ?window.requestAnimationFrame(function(){ ? ?transformElement(e.clientX, e.clientY); ?}); }); mouseOverContainer.addEventListener('mouseleave', (e) => { ?window.requestAnimationFrame(function(){ ? ?element.style.transform = "rotateX(0) rotateY(0)"; ?}); });
這樣,我們的當前的整個 DEMO 效果就變成了這樣
透明度變化
OK,最后,剩下最關(guān)鍵一步。我們需求讓整個卡片的磨砂感和透明度不一樣,隨著整體鼠標的 Hover 位置而實時發(fā)作變化。
這里我們會用到兩個中心是技術(shù):
mask 遮罩,改動 background 的透明度
應用 CSS @property 完成 mask 和 background 的突變角度變換動畫效果
這里是整個效果最為復雜的中央。
我們一個一個來了解。
首先,基于?background
?透明度完成的毛玻璃效果,我們能夠應用 mask 讓整個毛玻璃效果的透明度不平均分歧。
什么意義呢?看看這張圖
應用 mask,我們就能讓毛玻璃效果不均與。上述比照圖中,圖 2 和 圖 3 的?mask
?的角度分別是?90deg、270deg。
那么,我們只需求在 HOVER 的過程中,動態(tài)的算出當前鼠標的位置相關(guān)于元素中心的角度值,賦值給 mask 即可!
像是這樣:mask: linear-gradient(var(--angle), rgba(255, 255, 255, .5), #fff);
,其中?--angle
?的值,由 JavaScript 計算,實時傳給 mask 即可。
并且,由于,突變是不支持過渡動畫的,因而,我們需求 CSS @property 來完成 mask 角度變化的動畫效果。
這里中心的代碼如下:
div { ? ?width: 600px; ? ?height: 300px; ? ?backdrop-filter: blur(15px); ? ?background: linear-gradient(var(--angle), rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.5)); ? ?mask: linear-gradient(var(--angle), rgba(255, 255, 255, .5), #fff); ? ?transition: all 0.3s, --angle 0.3s; }const multiple = 25;const mouseOverContainer = document.getElementsByTagName("body")[0];const element = document.getElementById("element");function transformElement(x, y) { ?const box = element.getBoundingClientRect(); ?const calcX = -(y - box.y - (box.height / 2)) / multiple; ?const calcY = (x - box.x - (box.width / 2)) / multiple; ?let angle = Math.floor(getMouseAngle((y - box.y - (box.height / 2)), (x - box.x - (box.width / 2)))); ?element.style.transform ?= "rotateX("+ calcX +"deg) " + "rotateY("+ calcY +"deg)"; ?element.style.setProperty("--angle", `${-angle}deg`); }function getMouseAngle(x, y) { ?const radians = Math.atan2(y, x); ?let angle = radians * (180 / Math.PI); ? ?if (angle < 0) { ? ?angle += 360; ?} ? ?return angle; } mouseOverContainer.addEventListener('mousemove', (e) => { ?window.requestAnimationFrame(function(){ ? ?transformElement(e.clientX, e.clientY); ?}); }); mouseOverContainer.addEventListener('mouseleave', (e) => { ?window.requestAnimationFrame(function(){ ? ?element.style.transform = "rotateX(0) rotateY(0)"; ?}); });
上面的代碼,有兩點需求再解釋一下:
getMouseAngle()
?·用于計算當前鼠標位置相關(guān)于元素中心點的角度值我們同時將角度變化設(shè)置給了?
background
?突變背景,這樣會讓背景的突變角度也跟隨變化,可以讓整體效果更好
如此一下,我們的整體效果就變成了這樣
圓滿!整體動畫連接,hover 時不卡頓,而且效果絲滑了不少。