寫在前面 自己的一點想法
"解決一個問題,最重要的收獲並不是得到的答案。而是在尋找答案的過程中,學到的其它東西和見識的延伸。"
---《反正我從中學到不少東西》
”我敬你是條漢子!“
---《論如何回答女朋友問為什么對她那么好》
希望能夠把文章大致掃一遍,里面有一些有趣的demo哦......噠
效果見頁面頂部 或者如下:
//---------------初始化輪顯的方法----------------------- $("#modelSlider").slider({ imgs: [ //圖片的地址 "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_0f8738e9cfbb9485.png", "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_89e657a08f9f13f6.png", "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_884e69c2eb02316b.png", "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_462506e0ed7b0c25.png", "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_e5859ff3e6487575.png", "http://images.cnblogs.com/cnblogs_com/lianmin/713650/o_f07bd295f4cdbd7a.png" ], urls: [ //點擊圖片跳轉到的地址,也可以如下放一段js 'javascript:makeDialog("輪顯提示或者地址","第1個圖",function(){},3)', 'javascript:makeDialog("輪顯提示或者地址","第2個圖",function(){},3)', 'javascript:makeDialog("輪顯提示或者地址","第3個圖",function(){},3)', 'javascript:makeDialog("輪顯提示或者地址","第4個圖",function(){},3)', 'javascript:makeDialog("輪顯提示或者地址","第5個圖",function(){},3)', 'javascript:makeDialog("輪顯提示或者地址","第6個圖",function(){},3)' ], scale: 5 / 2, //圖片寬高比 border: false, //是否顯示分界線 showBar: true, //是否可以人工切換 x: 4, //橫向格子數 y: 3 //縱向格子數 }); //---------------控制輪顯的方法----------------------- $("#modelSlider").slider("begin"); //開始 執行某個方法 $("#modelSlider").slider("stop"); //停止 $("#modelSlider").slider("choseImg",3); //切換到索引為3的項 執行某個方法,傳參 $("#modelSlider").slider("resize",{border:true,showBar:false}); //對初始化的屬性進行修改 //-----------試試把上面這4行依次放到控制台執行一下?------
一、照着效果分析原理
最初是在一個叫《琉璃神社》的地方看到:http://hacg.club/。觀察了很多次,覺得重點在這里:格子內的效果切換
。
於是就扒開看看嘍...
總效果
=>格子特效 + 效果產生順序
格子
=>2個div + 通過背景圖切換
通過背景圖切換 || 效果產生順序
=>可以用jQuery的隊列處理Σ( ゚д゚))
具體的邏輯算法
=>邊寫邊想吧,寫完重構
- ......
二、搭建jQuery插件結構
我覺得應該寫成插件方式,畢竟要多處用。以下是我寫插件一般的格式,歡迎拍磚:
// jQuery 插件的一般寫法,自執行匿名方法 // 好處是這樣的:1.避免其它插件也用了$做關鍵字;2.避免插件內部方法污染全局 // 實際工作中我一個js文件也許會寫大幾十個function,,,沒辦法,需求是一點一點加 (function ($) { function Slider(option) { //深拷貝,修改每個對象的屬性只能通過對象實例,避免初始化時候外部引用對象的影響 this.opt = $.extend(true, {}, option); } $.fn.slider = function (option) { var defaults = { //默認設置 // 獨立寫出來,也許將來就用得到呢,也說不定... }; //最終配置 var opt = $.extend({}, defaults, option); //jQuery對象是一個偽數組對象,可能有多個元素 return $.each(this, function (index, ele) { // code... var slider = new Slider(opt); $(ele).data("slider", slider); }); }; })(jQuery);
總結:
- 最基本的面向對象思想,寫個類吧,在類中實現所有功能.
- 對jQuery.fn進行擴展,可以用 $.fn.method = function ,或者 $.fn.extend({}) .
- jQuery對象是一個偽數組對象,里面可能含有多個元素,需要針對每一個元素實例化一個對象進行緩存.
- 說到data方法,js對象的 $({}).data ,是把數據放到對象本身上,而元素的 data 方法,是把數據放到 $.cache 中 。所以如何跨框架使用easyui等報錯的解決方式,是需要用所屬iframe內的jQuery對象,否則取不到。
- 將所有代碼放到匿名自執行方法中.
三、對將要用到的幾個主要方法方法進行擴展
1.肯定要拼接html的,"<div id='"+theId+"' >....... 這種寫法簡直弱爆了,以前也經常這么寫,但是某天就突然擴展了,,,果然多讀讀別人的文章對自己有好處.
//擴展 string.format String.prototype.format = function () { var args = arguments; var reg = /\{(\d+)\}/g; return this.replace(reg, function (g0, g1) { return args[+g1]; }); }; //用法: "hello {0},your age is {1},so {0}'s age is {1}".format("tom",12); //"hello tom,your age is 12,so tom's age is 12"
說明:
- 對String原型進行擴展: String.prototype.methodName=function...
- 正則表達式: /\{(\d+)\}/g ;取"{0}"這種格式的占位符,並對里面的數字放入子組
- js 的 replace 方法有一種重載, string.format(regex , function(group0【匹配項】,group1【子組第一個】...){ //code... }) ;對於每次匹配到的一個占位符,都從參數相應的位置取得替換項。
2.圖片預加載
(function ($) { // 圖片預加載 $.preLoad = function (urlArr) { $.each(urlArr, function (index, url) { var img = document.createElement("img"); img.src = url; }); } })(jQuery); //上來就加載大量圖片會占用大量帶寬,影響用戶體驗 //但是如果輪顯這里不提前加載,只在顯示當前圖片的時候去下載當前圖片,對於一般網速的用戶來說,可能不太好看 //根據實際情況使用吧...噠?
3.jQuery隊列封裝
關於jQuery隊列的一點認識:
眾所周知,使用jQuery給元素添加一連串的動畫效果,元素並不會將動畫同時執行,而是按照添加的順序,依次在上一個動畫結束之后才開始下一個動畫。
我了解的情況就是,jQuery使用了一種叫做“隊列”(queue)的方式將動畫效果依次加進去,在上一個隊列中的動畫執行完畢,通過deferred通知下一個動畫執行。
var ele = $("#id"); //某個jQuery對象 //為jQuery對象的叫“queueName”的隊列上面添加處理事件 ele.queue("queueName", function (next) { //your code... do something next(); //next() 是執行下一個隊列中要處理的事件,如果沒有next隊列就無法依次處理 }); //延時 ele.delay(1000, "queueName"); //執行隊列 ele.dequeue("queueName");
這里要說一下的是,jQuery的動畫默認是把處理事件放在了叫“fx”的隊列中。因此,我進行了以下簡單的封裝:
$.fn.will = function (callback, type) { //這里的this,表示jQuery對象 this.queue(type || "fx", function (next) { // fx 表示默認的隊列 //這里的this,是原生的對象 callback && typeof callback == "function" && callback.call($(this)); //使用call,方便回調函數使用this next(); }); return this; //返回this,方便進行鏈式調用 } //試試在控制台這么用 var ele = $({}); for (var i = 0; i < 10; i++) { ele.will(function () { console.log(+new Date); }).delay(1000); }
使用隊列,可以直觀清晰,方便地將異步操作表示出來。就像 Thread.Sleep(1000)
那樣明了。
關於Deferred我就不贅述了,本文沒有直接使用到,自己也只是知其然而不知其所以然,僅僅會用。
隊列的作用,就是將輪顯中的格子,一個一個進行處理,避免了大量的setTimeout,使用callback的形式進行替換。
四、緩動
先看例子,沒有效果圖吸引不了人

更詳細的緩動介紹請參見:http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html
這里我介紹一下jQuery.animate的一種重載
jQuery的animate動畫,我以前不知道在哪里看到的:只能實現可以用數字表示的動畫。也就是說css3的transform是不行的。但是animate有一種重載!
常用的方式
:
$("html,body").animate({ scrollTop: "0px" }, 1000);
另一種重載
:
$({ num: 32 }).animate({ num: 64 }, { duration:1000, step: function () { console.log("當前的num是:" + this.num); }, complete: function () { console.log("結束了,num是:" + this.num); } });
看到上面的寫法,就應該大致了解了demo中動畫的原理:
【根據要改變的樣式定義一個對象,利用animate改變這個對象,監聽step和complete事件來拼接新的樣式賦值給你要執行動畫的元素!】
以下是【發射憤怒的小鳥】
的具體實現
jQuery.extend(jQuery.easing, { easeOutBounce: function (x, t, b, c, d) { if ((t /= d) < (1 / 2.75)) { return c * (7.5625 * t * t) + b; } else if (t < (2 / 2.75)) { return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b; } else if (t < (2.5 / 2.75)) { return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b; } else { return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b; } },easeOutCubic: function (x, t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; } }) function sendBirld() { var ele = $("#birld").stop(true, false); ele.css({ "left": "0", "top": "0", "transform": "rotateZ(0deg)" }); $({ left: 0, top: 0, tran: 0 }).animate({ left: 800, top: 180, tran: 360 }, { duration: 2500, specialEasing: { left: 'easeOutCubic', top: 'easeOutBounce' }, step: function () { ele.css({ "left": this.left + "px", "top": this.top + "px", "transform": "rotateZ(" + this.tran + "deg)" }); }, complete: function () { ele.css({ "left": "800px", "top": "180px", "transform": "rotateZ(360deg)" }); } }); }
五、對js異步編程的思考學習
我目前了解到3種js異步的方式:setTimeout,setInterval
,回調函數
,事件觸發
setTimeout和setInterval太丑陋了...雖然大部分誤差可以接受,但是總歸並不是賞心悅目。而且有些東西並不清楚會執行多久,所以舍棄。
事件觸發,讓我想到了 C# 中的事件與委托,確實不錯,但是一長串任務要定義多少事件?感覺沉重。 這一塊了解的不深,可能說的不正確。
我偏向於第二種回調。
function work(callback) { //do something... typeof callback == "function" && callback(); }
但是天啊,如果一長串方法需要依次執行,這回調要有多難看?
我們看看jQuery是怎么做的(只說用法,實現過程沒研究):
jQuery.Deferred()的一點了解
$.Deferred()是jQuery1.5開始加進去的,並重寫了 ajax和animate(基於queue,queue基於Deferred)
使用示例:
function work() { var dfd = $.Deferred(); setTimeout(function () { //do something... dfd.resolve(); },1000); return dfd; } work().done(function () { window.console && console.log("結束了"); });
使用方式:1.創建deferred對象;2.為該對象暴漏的事件綁定方法;3.對象執行動作,觸發綁定的方法
對應的動作和事件(我目前常用的):
- deferred.resolve() => deferred.done(callback) //完成
- deferred.reject() => deferred.fail(callback) //失敗
- deferred.then(cb1,cb2) //cb1完成,cb2失敗,當然有cb3,這個沒做具體了解
- deferred.always(callback) //無論完成或者失敗
- jQuery.when(dfd1,dfd2...)的用法:
//參數是若干個deferred或者promise對象 $.when(dfd1, dfd2, dfd3...).done(function () { //全都完成時候觸發 }).fail(function () { //有一個失敗則判定全部失敗 }).always(function () { //全都是完成或者失敗狀態時候觸發 });
- //注:動作中的參數,會自動帶入到事件回調的參數位置,如:
var dfd = $.Deferred(); dfd.done(function (str) { console.log(str); }); dfd.resolve("lalala"); //會打印出 "lalala"
- ......
類似於C#中的委托與事件:委托的發布者不應該將委托的操控權暴漏給訂閱者,最好用事件對委托進行安全的封裝。 直接返回deferred似乎也不太好,對deferred仍然可以操作,所以封裝一下:返回deferred.promise(),該對象只暴漏了事件的訂閱方法,而不能操作。
看看 jQuery.ajax
傳統的jQuery.ajax
$.ajax({ //... success: function () { //... }, error: function () { //... }, complete: function () { //... } });
ajax方法返回的仍然是一個promise對象,提供事件訂閱的方法:done,fail,then...為了與原方法名對應,看下圖,也額外提供了原來的名稱:
另一種用法
$.ajax({ //... }).success(function (data) { //原success 或使用 done }).error(function () { //原error 或使用 fail }).complete(function () { //原complete 或類似用使用 always });
這時候我想了想,我要在函數里面返回deferred對象么?有點麻煩...
突然想到jQuery的動畫添加進去就會依次執行。於是了解到動畫是基於隊列的:
六、總結,下載
總結:
本文很多地方介紹的可能都不是很詳細,畢竟我以一個“過來人”的思考方式,對於初次接觸人的想法不匹配,相信那些已經掌握的人來說就是:“對啊,就這樣子啊。”,初接觸:“啥?你到底想說啥?”
似乎有點倉促,但是我覺得了解以上內容就已經夠了。且不行,就當做目錄看,對於各個知識點再去找專門的文章進行深入學習。
按照最開始的分析,已經解決了:按順序依次延時處理(queue隊列,js異步),jQuery插件的寫法,格子切換時的緩動處理,其中間雜着一些在學習過程中的思考和擴展(我覺得在尋求答案中的擴展很重要)。 剩下的大概就是具體實現了...無非就是用絕對定位,在切換的時候使用緩動做特效,用queue來進行異步處理,需要一些想法,簡單的算法,html和css基礎。
下面附上下載地址:slider1.2.js ,slider.min.css
我在制作這個插件的過程中,鞏固和學習了不少知識,實現一個功能,重要的不僅僅是實現,更多的是在實現過程中的自我擴展和見識的延伸。
突然想到了一個廣告詞:人生就是一部旅行,重要的不是目的地,而是沿途的風景,以及看風景的心情。
下面是厚顏無恥的求贊時間
您有沒有對這篇文章感興趣呢?
.