自作jquery版LightBoxの書き換え

美しいjqueryプラグインのメソッドパターンを見てから一週間。自作のLightBoxコードの書き換えを少しずつ行ってきましたので、とりあえず公開してみます。

コンストラクタ

//PlugIn Constructor
var LightBox = function(elem, options){
    var self = this;
    self.elem = elem;
    self.$elem = $(elem);
    self.options = options;
    self.metadata = self.$elem.data('lightBox-options');
    //リンク検索
    self.$links = self.$elem.find('a');
};

まずは、コンストラクタ内にプロパティを設定。thisをselfに入れていいかどうかは今のところ不明。勉強不足。

prototypeに各メソッドを定義

//Plugin prototype
LightBox.prototype = {
    init: function(){
        //init内は初回のみ実行
        var self = this;
        //リンクの数
        self.linkLength = self.$links.length;
        //リンクそれぞれに対して実行
        self.$links.each(function(i){
            $(this).on('click.lightBox', function(e){
                self.open(e, i);
            });
        });
        //オプション設定
        self.options = $.extend({}, self.defaults, self.options, self.metadata);
        return self;
    },

記事にあったjQuery.proxy()を使わず、ひとまず初歩的な書き方でクリックイベント『open』を発生させてます。

open

    //Plugin methods
    open: function(e, index){
        var
        self = this,
        $eTarget = $(e.currentTarget);
        if(!e.isDefaultPrevented()){
            e.preventDefault();
        }
        self.currentIndex = index;
        self.setup($eTarget);
        self.$window.on('resize.lightBox', function(){
            self.centering(self.$lightBox);
        });
        self.load(self.$backDrop, self.$lightBox, self.$navBtn);
        self.$navBtn.each(function(){
            $(this).on('click.lightBox', function(e){
                self.nav(e, self.currentIndex);
            });
        });
        self.$backDrop.on('click.lightBox', $.proxy(self.close, this));
    },

setup

    setup: function(eTarget){
        var self = this;
        self.$closeBtn = $('<div class="close">close</div>');
        self.$backDrop = $('<div id="backdrop"></div>').append(self.$closeBtn);
        self.$backDrop.appendTo('body');
        self.$lightBox = self.createLightBox(eTarget);
        self.$lightBox.appendTo('body');
        self.centering(self.$lightBox, 'first');
        self.$img.load(function(){
            $(this).appendTo(self.$imgContainer).hide();
            self.boxWidth = $(this).width();
            self.boxHeight = $(this).height();
            self.centering(self.$lightBox, 'image');
        });
    },

<div id=”backdrop”></div>は<div id=”backdrop” />で書けます(SyntaxHighlighterがこの書き方に未対応のため書き換えてます)。

nav

    nav: function(e, index){
        var
        self = this,
        navFlag = $(e.currentTarget).attr('data-href');
        if(navFlag == 'next'){
            if(self.currentIndex+1 < self.linkLength){
                self.currentIndex++;
            }else{
                self.currentIndex = 0;
            }
        }else{
            if(self.currentIndex > 0){
                self.currentIndex--;
            }else{
                self.currentIndex = self.linkLength-1;
            }
        }
        self.$img
        .hide()
        .attr({src : self.$links.filter(':eq('+ self.currentIndex + ')')
        .attr('href')})
        .fadeIn();
    },

load

    load: function(backDrop, lightBox, navBtn){
        var lArray = [
                backDrop,
                lightBox,
                navBtn
            ];
        backDrop.stop().animate({'opacity' : 0.8}, 300, 'linear').css({'z-index' : '60'});
        lightBox.stop().animate({'opacity' : 1}, 300, 'linear').css({'position' : 'absolute', 'z-index' : '61'});
        navBtn.stop().animate({'opacity' : 1}, 300, 'linear').css({'position' : 'absolute', 'z-index' : '61'});
        for(var i = 0; i < lArray.length; i++) lArray[i].css({'visibility':'visible'});
    },

このロードイベントは可能なら連想配列に書き換えたいです。

close

    close: function(e){
        var
        self = this,
        cArray = [self.$backDrop, self.$lightBox, self.$navBtn];
        for(var i = 0; i < cArray.length; i++) cArray[i].fadeOut(400, function() {
            $(this).unbind().remove();
        });
    },

createLightBox

    createLightBox: function(eTarget){
        var self = this;
        self.$box = $('<div id="box"></div>');
        self.$imgContainer = $('<div class="image"></div>');
        self.$img = $('<img src="'+ eTarget.attr('href') +'" alt="" />');
        self.$prevBtn = $('<div class="nav prev" data-href="prev">prev</div>');
        self.$nextBtn = $('<div class="nav next" data-href="next">next</div>');
        self.$navBtn = self.$prevBtn.add(self.$nextBtn).hide();
        self.boxWidth = 1;
        self.boxHeight = 1;
        return self.$box.append(self.$imgContainer).append(self.$navBtn);
    },

centering

    centering: function(lightBox, timing) {
        var
        self = this,
        win = self.winPara(),
        flag = timing === undefined ? 'none' : timing;//参考 http://qiita.com/VoQn/items/3a4a8c0ad11e45c64907
        if(flag == 'first'){
            self.top = (win.height-self.boxHeight)/2 + win.scrollTop + 'px';
            self.left = (win.width-self.boxWidth)/2 + 'px';
            lightBox.css({'width' : self.boxWidth, 'height' : self.boxHeight, 'left' : self.left , 'top' : self.top});
        }else if(flag == 'image'){
            self.$navBtn.hide();
            self.top = (win.height-self.boxHeight)/2 + win.scrollTop + 'px';
            self.left = (win.width-self.boxWidth)/2 + 'px';
            lightBox.animate({'width' : self.boxWidth, 'height' : self.boxHeight, 'left' : self.left , 'top' : self.top}, 300, function(){
                self.$img.fadeIn(400,function(){
                    self.$navBtn.delay(100).fadeIn();
                });
            });
        }else{//resize
            self.top = (win.height-lightBox.height())/2 + win.scrollTop + 'px';
            self.left = (win.width-lightBox.width())/2 + 'px';
            lightBox.css({'width' : self.boxWidth, 'height' : self.boxHeight, 'left' : self.left , 'top' : self.top});
        }
    },

winPara

    winPara : function() {
        var self = this;
        self.$window = $(window);
        return {
            height : self.$window.height(),
            width : self.$window.width(),
            scrollTop : self.$window.scrollTop()
        };
    },

defaults

    defaults: {
        test: 1000//未設定
    }

オプション設定とオブジェクト生成

};
LightBox.defaults = LightBox.prototype.defaults;
$.fn.lightBox = function(options) {
    return this.each(function() {
        new LightBox(this, options).init(); 
    });
};

修正次第で追記するつもりです。

Author

  • Shinichi Kuroda - 黒田晋一
  • 香川県高松市 - Takamatsu-shi, Kagawa, Japan.
  • Mail - info@studiobusstop.com