制作炫酷的專題頁面


    很多時候,我們需要一些炫酷的動畫效果,讓頁面更加吸引用戶的眼球,現有比較好用的JS動畫庫有:velocity和GSAP(支持falsh和js)。今天這里主要學習的是velocity配合css3動畫,快速打造屬於你的專題頁面。
    PS:發現各種炫酷的效果都是由這些簡單的動作通過組合實現的,發現最終效果和動畫的設計者有很大關系,鄙人就屬於那種不怎么懂設計的人,這里只是拋磚引玉。
 
    雖然我今天不准備詳細介紹GSAP這個動畫庫,但是還有有必要把相關資源的入口放在這里,供想要了解的 同學進行深入的 學習。
    最好的學習就是查看官方API文檔,其次結合場景才會出現的問題,可以交流一下應該就可以解決。
 
    廢話不多說了,進入今天的正題。
 
     基礎技能
 
     velocity功能    
    包含$.animate()所有功能,並且包含切換、轉換、循環、緩動、CSS切換、scroll功能,從效率角度來說,比CSS更高。
    
     兼容性
    支持IE8+,chrome、firefox、android、ios(可以配置mobileMA,提升手機訪問效果)
 
     默認配置
    可以使用$.Velocity.defaults進行查看管理。
 
    注:關於配置的使用說明,可以參考官方文檔說明。其中begin、complete監聽動畫狀態
   
     調用方式
    支持兩種書寫方式
  • 第一種:
   
 /**
  * @param {Object|String} 需要改變css屬性最終狀態值或者是注冊動畫
  * @param {Object} 動畫基本配置,可以查看默認配置
  */
$element.velocity(properties, options) 

  

    
  • 第二種
    
/**
 * @param {Object} 操作元素,可以是原生對象,也可以是包裝對象 
 * @param {Object|String} 需要改變css屬性最終狀態值或者是注冊動畫
 * @param {Object} 動畫基本配置,可以查看默認配置
 */
$.Velocity($element, properties, options);

  

 
    另:所有的屬性值都可以是函數,返回最終的值
 
     提升技能
    
     自定義動畫效果
    velocity提供了注冊自定義動畫的方法,方便使用者自定義,並進行方便多次使用
    
$.Velocity.RegisterEffect(name, {
	defaultDuration: duration,
	calls: [ 
		[ { property: value }, durationPercentage, { options } ],
		[ { property: value }, durationPercentage, { options } ]
	],
	reset: { property: value, property: value }

});

  

    來一個簡單的例子:
   
 $.Velocity.RegisterEffect("callout.pulse", {
	defaultDuration: 900,
	calls: [
		[ { scaleX: 1.1 }, 0.50 ],
		[ { scaleX: 1 }, 0.50 ]
	]
});

  

    注冊一個callout.pulse方法,如何進行使用呢?可以參照基礎技能中的調用方式,這里使用其中一種方式
    $elements.velocity('callout.pulse'); //相當於是properties參數值
 
     UI pack--動畫包
    官方提供一些動畫包,可以直接進行使用,也可以通過自定義注冊動畫,然后進行使用。
    現有的的動畫效果有:
    
callout.bounce,callout.shake,callout.flash,callout.pulse,callout.swing,callout.tada,transition.fadeIn,transition.fadeOut,transition.flipXIn,transition.flipXOut,transition.flipYIn,transition.flipYOut,transition.flipBounceXIn,transition.flipBounceXOut,transition.flipBounceYIn,transition.flipBounceYOut,transition.swoopIn,transition.swoopOut,transition.whirlIn,transition.whirlOut,transition.shrinkIn,transition.shrinkOut,transition.expandIn,transition.expandOut,transition.bounceIn,transition.bounceOut,transition.bounceUpIn,transition.bounceUpOut,transition.bounceDownIn,transition.bounceDownOut,transition.bounceLeftIn,transition.bounceLeftOut,transition.bounceRightIn,transition.bounceRightOut,transition.slideUpIn,transition.slideUpOut,transition.slideDownIn,transition.slideDownOut,transition.slideLeftIn,transition.slideLeftOut,transition.slideRightIn,transition.slideRightOut,transition.slideUpBigIn,transition.slideUpBigOut,transition.slideDownBigIn,transition.slideDownBigOut,transition.slideLeftBigIn,transition.slideLeftBigOut,transition.slideRightBigIn,transition.slideRightBigOut,transition.perspectiveUpIn,transition.perspectiveUpOut,transition.perspectiveDownIn,transition.perspectiveDownOut,transition.perspectiveLeftIn,transition.perspectiveLeftOut,transition.perspectiveRightIn,transition.perspectiveRightOut

  

    具體效果可以查看最下面的例子。
 
     自定義動畫隊列
    官方提供了執行動畫隊列的方法,$.Velocity.RunSequence(animationArr);其中animationArr是動畫數組,數組的每個元素是一個元素動畫效果,具體例子如下:
    
var mySequence = [
	 { elements: $element1, properties: { translateX: 100 }, options: { duration: 1000 } },
	 { elements: $element2, properties: { translateX: 200 }, options: { duration: 1000, sequenceQueue: false },
	 { elements: $element3, properties: { translateX: 300 }, options: { duration: 1000?}
];
$.Velocity.RunSequence(mySequence);
//默認隊列動畫是按照順序執行的,可以通過設置sequenceQueue改變當前元素執行時機。默認是true,當為true時,指的是按照順序執行,如果設置成false指的是,可以和上一個元素動畫同時執行

  

    
     支持promise
    引入官方推薦的bluebird和when,即可采用如下使用方式:
   
 $element.velocity(properties, options).then(); //需要注意是的是無線循環和隊列不支持該形式

  

 
    終極技能
 
    配合css3動畫,達到最佳效果
 
 
     友情提示:
    velocity在進場和出場動畫方面優勢比較大,css3在循環動畫上優勢比較大。當然萬惡的IE兼容問題    
 
    基於上面所講到的,實現了一個基於jquery、velocity、animation.css實現的動畫,僅供參考
    
/**
 * 動畫處理
 * author: 黑MAO
 */
$(function() {
	'use strict';
	
	/****內部方法開始****/
	/**
	 * css動畫執行函數
	 * @param {Object} 目標元素
	 * @param {String} 初始class
	 * @param {String} 動畫類型
	 * @param {Number} 動畫時長
	 * @param {Number} 動畫延遲
	 * @param {Number} 循環次數
	 */
	var timer;
	function _cssRun(targetEl, className, animation, duration, delay, loop) {
		duration = duration*1 || 1000;
		delay = delay*1 || 0;
		loop = (loop || loop == 0) ? loop*1 : 1;
		
		if(loop < 1) {
			loop = 'infinite';
		}
		$(targetEl).removeClass();
		$(targetEl).addClass(className).addClass(animation);
		$(targetEl).css({
			'animation-duration': duration+'ms',
			'animation-delay': delay+'ms',
			'animation-iteration-count': loop+''
		});
		if(loop != 'infinite') {
			clearTimeout(timer);
			timer = setTimeout(function() {
				$(targetEl).removeClass(animation);
			}, duration*loop + delay);
		}
		
	}
	/**
	 * 監聽select變化方法
	 * @param {Object} 目標元素
	 * @param {Object} 操作元素集合
	 * @param {String} 初始class
	 * @param {String} 動畫類型 ["css", "js"]
	 */
	function _changeFunc(targetEl, opElementObj, className, animationType) {
		var animation = $(opElementObj.animationEl).val();
		var duration = $(opElementObj.durationEl).val();
		var delay = $(opElementObj.delayEl).val();
		var loop = $(opElementObj.loopEl).val();
		if(animationType == "css") {
			_cssRun(targetEl, className, animation, duration, delay, loop);
		}else {
			var ras = new Ras();
			if(animation) {
				ras.run(targetEl, 'stop');
				ras.run(targetEl, animation, {duration: duration, delay: delay, stagger: 200, drag: true});
			}
		}
	}
	/**
	 * 初始化動畫
	 * @param {Array} 動畫數組 
	 * @param {Object} 操作元素對象
	 * @param {Object} 目標元素
	 * @param {Number} 動畫延遲
	 * @param {String} 需要顯示的動畫類型 ["show", "hide", "normal", "all"]
	 * @param {String} 動畫類型 ["css", "js"]
	 */
	function _initAnimation(animationArr, opElementObj, targetEl, type, animationType) {
		var conf = opElementObj;
		var className = $(targetEl).attr("class");
		
		$(conf.animationEl).prepend('<option value="" diabled="disabled">選擇動畫類型</option>');
		$(animationArr).each(function(key, val) {
			var isShow = false;
			switch(type) {
				case "show":
					if(val.indexOf('In') > 0) {
						isShow = true;
					}
					break;
				case "hide":
					if(val.indexOf('Out') > 0) {
						isShow = true;
					}
					break;
				case "normal":
					if(val.indexOf('Out') == -1 && val.indexOf('In') == -1) {
						isShow = true;
					}
					break;
				default:
					isShow = true;
					break;
			}
			isShow && $(conf.animationEl).append('<option value="'+val+'">'+val+'</option>');
		});
		$(conf.animationEl).on('change', function() {
			_changeFunc(targetEl, conf, className, animationType);
		});
		$(conf.durationEl).on('change', function() {
			_changeFunc(targetEl, conf, className, animationType);
		});
		$(conf.delayEl).on('change', function() {
			_changeFunc(targetEl, conf, className, animationType);
		});
		$(conf.loopEl).on('change', function() {
			_changeFunc(targetEl, conf, className, animationType);
		});
	}
	
	/****內部方法結束****/

	function Ras(opts) {
		var conf = {
			beforeIndex : 0, //上一頁序列號
			currentIndex : 0, //當前頁序列號
			playing : true, //是否在運行
			downward : true, //是否向下滾動
			imgList: [], //頁面內圖片列表
			quenes: { 
				show: [], //頁面顯示列表
				hide: [] //頁面隱藏列表
			},
			navFunc: null, //導航回調函數
			cssAnimationExtra: [], //css動畫擴展
			jsAnimationExtra: [] //js動畫擴展
		};
		
		this.conf = $.extend(conf, opts);
	}
	//對外暴漏
	window.Ras = Ras;
	
	$.extend(Ras.prototype, {
		init: function() {
			var self = this;
			var conf = this.conf;
			//綁定鍵盤和鼠標事件
			var quenes = conf.quenes;
			var showList = conf.quenes.show;
			var hideList = conf.quenes.hide;
			var senceNum = showList.length;
			$(document).on('mousewheel keyup',function(e){
				if( !conf.playing ){
					conf.playing = true;
					if( e.keyCode && (e.keyCode==39||e.keyCode==40)){
						conf.downward = true;
					}
					if( e.keyCode && (e.keyCode==37||e.keyCode==38) ){
						conf.downward = false;
					}
					if( e.deltaY){
						conf.downward = e.deltaY<0?true:false;
					}
					if( e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40 || e.deltaY ){
						conf.beforeIndex = conf.currentIndex;
						conf.currentIndex = conf.downward ?conf.currentIndex + 1:conf.currentIndex - 1;
						conf.currentIndex = conf.currentIndex>=senceNum?0:conf.currentIndex;
						conf.currentIndex = conf.currentIndex<0?senceNum-1:conf.currentIndex;
						conf.navFunc && conf.navFunc(conf.currentIndex);
						self.show(hideList[conf.beforeIndex], showList[conf.currentIndex], function() {
							conf.playing = false;
						});
					}
				}
				return false;
			});
			
			//處理圖片預加載
			var imgList = conf.imgList;
			imgList.length && self.imgLoader(imgList);
			
			//默認顯示第一屏
			self.show(null, showList[0], function() {
				conf.playing = false;
			});
		},
		/**
		 * 初始化CSS動畫
		 * @param {Object} 聯動元素集合
		 * @param {Object} 目標元素
		 * @param {String} 選項類型 ["show", "hide", "normal", "all"]
		 */
		initCssAnimation: function(opElementObj, targetEl, type) {
			var conf = this.conf;
			var animationStr = 'bounce,pulse,rubberBand,shake,swing,tada,bounceIn,bounceInDown,bounceInLeft,bounceInRight,bounceInUp,bounceOut,bounceOutDown,bounceOutLeft,bounceOutRight,bounceOutUp,fadeIn,fadeInDown,fadeInDownBig,fadeInLeft,fadeInLeftBig,fadeInRight,fadeInRightBig,fadeInUp,fadeInUpBig,fadeOut,fadeOutDown,fadeOutDownBig,fadeOutLeft,fadeOutLeftBig,fadeOutRight,fadeOutRightBig,fadeOutUp,fadeOutUpBig,flip,flipInX,flipInY,flipOutX,flipOutY,lightSpeedOut,rotateIn,rotateInDownLeft,rotateInDownRight,rotateInUpLeft,rotateInUpRight,rotateOut,rotateOutDownLeft,rotateOutDownRight,rotateOutUpLeft,rotateOutUpRight,hinge,rollIn,rollOut,zoomIn,zoomInDown,zoomInLeft,zoomInRight,zoomInUp,zoomOut,zoomOutDown,zoomOutLeft,zoomOutRight,zoomOutUp,slideInDown,slideInLeft,slideInRight,slideInUp,slideOutDown,slideOutLeft,slideOutRight,slideOutUp,magic,openDownLeft,openDownRight,openUpLeft,openUpRight,openDownLeftRetourn,openDownRightRetourn,openUpLeftRetourn,openUpRightRetourn,openDownLeftOut,openDownRightOut,openUpLeftOut,openUpRightOut,perspectiveDown,perspectiveLeft,perspectiveRight,perspectiveUp,perspectiveDownRetourn,perspectiveLeftRetourn,perspectiveRightRetourn,perspectiveUpRetourn,puffIn,puffOut,rotateDown,rotateLeft,rotateRight,rotateUp,slideDown,slideLeft,slideRight,slideUp,slideDownRetourn,slideLeftRetourn,slideRightRetourn,slideUpRetourn,swap,twisterInDown,twisterInUp,vanishIn,vanishOut,swashOut,swashIn,foolishOut,holeOut,tinRightOut,tinLeftOut,tinUpOut,tinDownOut,tinRightIn,tinUpIn,tinDownIn,bombRightOut,bombLeftOut,boingInUp,boingOutDown,spaceOutUp,spaceOutRight,spaceOutLeft,spaceInUp,spaceInRight,spaceInDown,spaceInLeft,boomIn,circleRotate';
			var animationArr = animationStr.split(',');
			var arr = [];
			$.merge(arr, animationArr, conf.cssAnimationExtra);
			arr = $.unique(arr);
			_initAnimation(arr, opElementObj, targetEl, type, 'css');
		},
		/**
		 * 初始化JS動畫
		 * @param {Object} 聯動元素集合
		 * @param {Object} 目標元素
		 * @param {String} 選項類型 ["show", "hide", "normal", "all"]
		 */
		initJsAnimation: function(opElementObj, targetEl, type) {
			var conf = this.conf;
			var animationStr = 'callout.bounce,callout.shake,callout.flash,callout.pulse,callout.swing,callout.tada,transition.fadeIn,transition.fadeOut,transition.flipXIn,transition.flipXOut,transition.flipYIn,transition.flipYOut,transition.flipBounceXIn,transition.flipBounceXOut,transition.flipBounceYIn,transition.flipBounceYOut,transition.swoopIn,transition.swoopOut,transition.whirlIn,transition.whirlOut,transition.shrinkIn,transition.shrinkOut,transition.expandIn,transition.expandOut,transition.bounceIn,transition.bounceOut,transition.bounceUpIn,transition.bounceUpOut,transition.bounceDownIn,transition.bounceDownOut,transition.bounceLeftIn,transition.bounceLeftOut,transition.bounceRightIn,transition.bounceRightOut,transition.slideUpIn,transition.slideUpOut,transition.slideDownIn,transition.slideDownOut,transition.slideLeftIn,transition.slideLeftOut,transition.slideRightIn,transition.slideRightOut,transition.slideUpBigIn,transition.slideUpBigOut,transition.slideDownBigIn,transition.slideDownBigOut,transition.slideLeftBigIn,transition.slideLeftBigOut,transition.slideRightBigIn,transition.slideRightBigOut,transition.perspectiveUpIn,transition.perspectiveUpOut,transition.perspectiveDownIn,transition.perspectiveDownOut,transition.perspectiveLeftIn,transition.perspectiveLeftOut,transition.perspectiveRightIn,transition.perspectiveRightOut';
			var animationArr = animationStr.split(',');
			var arr = [];
			$.merge(arr, animationArr, conf.cssAnimationExtra);
			arr = $.unique(arr);
			_initAnimation(arr, opElementObj, targetEl, type, 'js');
		},
		/**
		 * 入場動畫
		 * @param {Array} 出場隊列
		 * @param {Array} 入場隊列
		 * @param {Function} 入場完成回調
		 */
		show: function(beforeQuene, currentQuene, callback) {
			var self = this;
			self.hide(beforeQuene);
			currentQuene && self.run(currentQuene).then(function() {
				callback && callback();
			});
		},
		/**
		 * 出場動畫
		 * @param {Array} 出場隊列
		 * @param {Function} 出場完成回調
		 */
		hide: function(quene, callback) {
			var self = this;
			callback && callback();
			quene && self.run(quene);
		},
		/**
		 * 圖片懶加載
		 * @param {Array} 圖片列表
		 * @param {Function} 圖片加載回調
		 */
		imgLoader: function(imgList, callback) {
			var count = imgList.length,
                i = 0,
                success = 0,
                failed = 0,
                failList = [];
			for ( ; i < count ; i++ ) {
				var img = new Image();
				(function(i){
					img.onload = function () {
						success++;
						if( (success + failed) == count ) {
							callback&&callback.call( imgList , failed, failList);
						}
					};
					img.onerror = function () {
						failed++;
						failList.push(imgList[i]);
						if( (success + failed) == count ) {
							callback&&callback.call( imgList , failed, failList );
						}
					};
					img.src = imgList[i];
				})(i);
			}
		},
		/**
		 * 注冊自定義動畫
		 */
		register: function() {
			var self = this;
			var args = [].slice.apply(arguments);
			$.Velocity.RegisterEffect.apply(self, args);
		},
		/**
		 * 封裝velocity方法,統一管理隊列和單個動畫
		 * @return {Object} promise對象
		 */
		run: function() {
			var deferred = $.Deferred();
			var self = this;
			var args = [].slice.call(arguments);
			var len = args[0].length;
			
			if($.isArray(args[0])) {
				if(!args[0][len-1].options){
					args[0][len-1].options = {};
				}
				args[0][len-1].options.complete = function() {
					deferred.resolve();
				};
				$.Velocity.RunSequence.call(self, args[0]);
				return deferred.promise();
			}else {
				return $.Velocity.animate.apply(self, args);
			}
			
		},
		/**
		 * 啟動CSS動畫
		 * @param {Object} 操作元素
		 * @param {String} 初始class
		 * @param {String} css動畫
		 * @param {Number} 動畫時長
		 * @param {Number} 動畫延遲
		 * @return {Object} promise對象
		 */
		cssAnimationRun: function(targetEl, className, animation, duration, delay, loop) {
			loop = (loop === true) ? 0 : loop;
			_cssRun(targetEl, className, animation, duration, delay, loop);
		},
		/**
		 * 啟動JS動畫
		 * @param {Object} 操作元素
		 * @param {String} css動畫
		 * @param {Number} 動畫時長
		 * @param {Number} 動畫延遲
		 * @return {Object} promise對象
		 */
		jsAnimationRun: function(targetEl, animation, options) {
			var opts = {
				stagger: 200, 
				drag: true
			};
			opts = $.extend(opts, options);
			if(animation) {
				this.run(targetEl, 'stop');
				this.run(targetEl, animation, opts);
			}
		}
	});
});

  

    使用方式:
    
var ras = new Ras({
	cssAnimationExtra: ['bounce'],
	jsAnimationExtra: ['callout.bounce']
});
ras.init();
//調用相關方法

  

  測試效果地址

 
    附錄(資源地址):
 
    <link rel="stylesheet"  href=" http://s1.qhimg.com/!efd6dff2/animation.css">
    <script src=" http://s0.qhimg.com/lib/jquery/191.js" ></script> 

    <script src="http://s3.qhimg.com/!44713922/bluebird.js" ></script>
    <script src="http://s6.qhimg.com/!7c8590ec/jquery.mousewheel.min.js"></script>
    <script src="http://s6.qhimg.com/!ccefcc09/velocity.min.js"></script>
    <script src="http://s5.qhimg.com/!d0b08d4d/velocity.ui.min.js"></script>

 
    參考資料:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM