摘要:上面這段結構經過腳本處理之后,會被替換成下面的結構腳本分析我們利用了這個插件對上面的圖片進行處理,來實現傾斜效果。
原文來自:
http://tympanus.net/codrops/2015/05/28/image-tilt-effect/
所謂的傾斜效果,我也不知如何用語言描述,那就直接看Demo啦,下面我們會對這個效果的實現原理逐步分析:
http://codepen.io/CodingMonkeyzh/pen/jPYNyr
對一個圖片添加該效果,首先,我們需要一個具有寬高的容器。DOM 結構非常簡單。
上面這段結構經過腳本處理之后,會被替換成下面的結構:
腳本分析
我們利用了filtfx.js這個插件對上面的圖片進行處理, 來實現傾斜效果。我在原來的代碼中加入了一些注釋,來幫助我們理解。下面我們對該插件的核心代碼進行分析。
function TiltFx(el, options) { this.el = el; this.options = extend({}, this.options); extend(this.options, options); this._init(); this._initEvents(); }
這是構造函數,如果我們的文檔中,加入了上面的插件,那么插件會遍歷文檔中具有tilt-effet的img元素,來調用構造函數TiltFx():
function init() { // 遍歷所有擁有‘title-effect’類的img元素 [].slice.call(document.querySelectorAll("img.tilt-effect")).forEach(function(img) { new TiltFx(img, JSON.parse(img.getAttribute("data-tilt-options"))); }); }
TiltFx()具有一個原型屬性,兩個原型方法。原型屬性配置了一些默認的參數用于調用:
/** * 默認參數 */ TiltFx.prototype.options = { extraImgs: 2, // 額外的輔助圖片數量 opacity: 0.7, bgfixed: true, // 底圖是否固定 movement: { // 這是一些用于移動的參數 perspective: 1000, translateX: -10, translateY: -10, translateZ: 20, rotateX: 2, rotateY: 2, rotateZ: 0 } }
第一個原型方法是_init(),用于初始化DOM結點,生成我們的目標DOM結點:
TiltFx.prototype._init = function() { this.tiltWrapper = document.createElement("div"); this.tiltWrapper.className = "tilt"; // main image element. this.tiltImgBack = document.createElement("div"); this.tiltImgBack.className = "tilt__back"; this.tiltImgBack.style.backgroundImage = "url(" + this.el.src + ")"; this.tiltWrapper.appendChild(this.tiltImgBack); // image elements limit. if (this.options.extraImgs < 1) { this.options.extraImgs = 1; } else if (this.options.extraImgs > 5) { this.options.extraImgs = 5; } if (!this.options.movement.perspective) { this.options.movement.perspective = 0; } // add the extra image elements. this.imgElems = []; for (var i = 0; i < this.options.extraImgs; ++i) { var el = document.createElement("div"); el.className = "tilt__front"; el.style.backgroundImage = "url(" + this.el.src + ")"; el.style.opacity = this.options.opacity; this.tiltWrapper.appendChild(el); this.imgElems.push(el); } if (!this.options.bgfixed) { this.imgElems.push(this.tiltImgBack); ++this.options.extraImgs; } // add it to the DOM and remove original img element. this.el.parentNode.insertBefore(this.tiltWrapper, this.el); this.el.parentNode.removeChild(this.el); // tiltWrapper properties: width/height/left/top this.view = { width: this.tiltWrapper.offsetWidth, height: this.tiltWrapper.offsetHeight }; };
另外一個原型方式是用于監聽鼠標事件之類的:
TiltFx.prototype._initEvents = function() { var self = this, moveOpts = self.options.movement; // mousemove event.. this.tiltWrapper.addEventListener("mousemove", function(ev) { requestAnimationFrame(function() { // mouse position relative to the document. var mousepos = getMousePos(ev), // document scrolls. docScrolls = { left: document.body.scrollLeft + document.documentElement.scrollLeft, top: document.body.scrollTop + document.documentElement.scrollTop }, bounds = self.tiltWrapper.getBoundingClientRect(), // mouse position relative to the main element (tiltWrapper). relmousepos = { x: mousepos.x - bounds.left - docScrolls.left, y: mousepos.y - bounds.top - docScrolls.top }; // configure the movement for each image element. for (var i = 0, len = self.imgElems.length; i < len; ++i) { var el = self.imgElems[i], rotX = moveOpts.rotateX ? 2 * ((i + 1) * moveOpts.rotateX / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.rotateX / self.options.extraImgs) : 0, rotY = moveOpts.rotateY ? 2 * ((i + 1) * moveOpts.rotateY / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateY / self.options.extraImgs) : 0, rotZ = moveOpts.rotateZ ? 2 * ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) : 0, transX = moveOpts.translateX ? 2 * ((i + 1) * moveOpts.translateX / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.translateX / self.options.extraImgs) : 0, transY = moveOpts.translateY ? 2 * ((i + 1) * moveOpts.translateY / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateY / self.options.extraImgs) : 0, transZ = moveOpts.translateZ ? 2 * ((i + 1) * moveOpts.translateZ / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateZ / self.options.extraImgs) : 0; el.style.WebkitTransform = "perspective(" + moveOpts.perspective + "px) translate3d(" + transX + "px," + transY + "px," + transZ + "px) rotate3d(1,0,0," + rotX + "deg) rotate3d(0,1,0," + rotY + "deg) rotate3d(0,0,1," + rotZ + "deg)"; el.style.transform = "perspective(" + moveOpts.perspective + "px) translate3d(" + transX + "px," + transY + "px," + transZ + "px) rotate3d(1,0,0," + rotX + "deg) rotate3d(0,1,0," + rotY + "deg) rotate3d(0,0,1," + rotZ + "deg)"; } }); }); // reset all when mouse leaves the main wrapper. this.tiltWrapper.addEventListener("mouseleave", function(ev) { setTimeout(function() { for (var i = 0, len = self.imgElems.length; i < len; ++i) { var el = self.imgElems[i]; el.style.WebkitTransform = "perspective(" + moveOpts.perspective + "px) translate3d(0,0,0) rotate3d(1,1,1,0deg)"; el.style.transform = "perspective(" + moveOpts.perspective + "px) translate3d(0,0,0) rotate3d(1,1,1,0deg)"; } }, 60); }); // window resize window.addEventListener("resize", throttle(function(ev) { // recalculate tiltWrapper properties: width/height/left/top self.view = { width: self.tiltWrapper.offsetWidth, height: self.tiltWrapper.offsetHeight }; }, 50)); };
我們可以看到,監聽mousemove的事件處理函數中的計算比較復雜,關鍵的部分就是在這里:
var el = self.imgElems[i], rotX = moveOpts.rotateX ? 2 * ((i + 1) * moveOpts.rotateX / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.rotateX / self.options.extraImgs) : 0, rotY = moveOpts.rotateY ? 2 * ((i + 1) * moveOpts.rotateY / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateY / self.options.extraImgs) : 0, rotZ = moveOpts.rotateZ ? 2 * ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) : 0, transX = moveOpts.translateX ? 2 * ((i + 1) * moveOpts.translateX / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.translateX / self.options.extraImgs) : 0, transY = moveOpts.translateY ? 2 * ((i + 1) * moveOpts.translateY / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateY / self.options.extraImgs) : 0, transZ = moveOpts.translateZ ? 2 * ((i + 1) * moveOpts.translateZ / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateZ / self.options.extraImgs) : 0; el.style.WebkitTransform = "perspective(" + moveOpts.perspective + "px) translate3d(" + transX + "px," + transY + "px," + transZ + "px) rotate3d(1,0,0," + rotX + "deg) rotate3d(0,1,0," + rotY + "deg) rotate3d(0,0,1," + rotZ + "deg)"; el.style.transform = "perspective(" + moveOpts.perspective + "px) translate3d(" + transX + "px," + transY + "px," + transZ + "px) rotate3d(1,0,0," + rotX + "deg) rotate3d(0,1,0," + rotY + "deg) rotate3d(0,0,1," + rotZ + "deg)";
這里我們根據鼠標的位置,計算出了各個圖層對應的偏移量和旋轉角度,然后對它們進行變換即可。
最后mouseleave之后,我們再把個個圖層恢復到初始位置就行了。
Demo:http://codepen.io/CodingMonkeyzh/pen/jPYNyr
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85778.html
摘要:非常的龐大,而且它是完全為設計而生的動效庫。它運行于純粹的之上,是目前最強健的動畫資源庫之一。可能是創建滾動特效最好用的工具,它支持大量的瀏覽器,只要它們支持和特性。可以通過安裝吊炸天了,接近現實生活中的物理運動碰撞慣性動畫庫。 收集日期為2019-02-28,★代表當時的該項目在github的star數量 Animate.css 56401 ★ 一個跨瀏覽器的動效基礎庫,是許多基礎動...
摘要:標簽大集合語義化標簽頁面內錨點我跳跳到這里來可用于回到頂部功能。表格中表示行,和表示列。當超出時會自動換行。屬性清除浮動通用方案實際上是添加了一個看不見的點號。 1. 里的 一定要放在第一行 ,如果放在了下面可能會有問題。 2.標簽大集合 showImg(https://segmentfault.com/img/bVMaUw?w=1366&h=767); 3.HTML5語義化標簽...
摘要:標簽大集合語義化標簽頁面內錨點我跳跳到這里來可用于回到頂部功能。表格中表示行,和表示列。當超出時會自動換行。屬性清除浮動通用方案實際上是添加了一個看不見的點號。 1. 里的 一定要放在第一行 ,如果放在了下面可能會有問題。 2.標簽大集合 showImg(https://segmentfault.com/img/bVMaUw?w=1366&h=767); 3.HTML5語義化標簽...
閱讀 1716·2021-10-28 09:32
閱讀 616·2021-09-24 09:47
閱讀 2939·2021-09-02 15:11
閱讀 2743·2021-08-09 13:46
閱讀 2894·2019-08-30 15:55
閱讀 1079·2019-08-30 15:54
閱讀 3314·2019-08-29 14:12
閱讀 818·2019-08-26 13:40