一個輪顯插件的嘗試、思考和擴展


"解決一個問題,最重要的收獲並不是得到的答案。而是在尋找答案的過程中,學到的其它東西和見識的延伸。"

---《反正我從中學到不少東西》


”我敬你是條漢子!“

---《論如何回答女朋友問為什么對她那么好》


希望能夠把文章大致掃一遍,里面有一些有趣的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

我在制作這個插件的過程中,鞏固和學習了不少知識,實現一個功能,重要的不僅僅是實現,更多的是在實現過程中的自我擴展和見識的延伸。

突然想到了一個廣告詞:人生就是一部旅行,重要的不是目的地,而是沿途的風景,以及看風景的心情。

下面是厚顏無恥的求贊時間

您有沒有對這篇文章感興趣呢?









.


免責聲明!

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



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