1. 程式人生 > >js中簡易選項卡的實現(3種方法實現樣式的封裝)

js中簡易選項卡的實現(3種方法實現樣式的封裝)

清除浮動的三種方式

1.overflow: hidden; 清除子元素的浮動對父元素的影響
2.clear: both; 清除哥哥元素的浮動對弟弟元素的影響
3.:after{ display: block; content: “”; clear: both; }

基本樣式程式碼
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>選項卡</title>
    <style type="text/css"
>
* { margin: 0px; padding: 0px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; -webkit-user-select: none; } ul, li { list-style: none; } .box { width
: 500px
; margin: 10px auto; }
.box ul { /*overflow: hidden; !*清除子元素的浮動對父元素的影響*!*/ position: relative; top: 1px; } .box ul:after { display: block; content: ""; clear: both; } .box
ul li { float: left; margin-right: 15px; width: 100px; height: 30px; border: 1px solid #337ab7; line-height: 30px; text-align: center; cursor: pointer; } .box ul li.select { background: #5bc0de; border-bottom-color: #5bc0de; } .box div { display: none; height: 150px; text-align: center; line-height: 150px; background: #5bc0de; border: 1px solid #9783b9; /*clear: both; 清除哥哥元素的浮動對弟弟元素的影響*!*/ } .box div.select { display: block; }
</style> </head> <div class="box" id="tabFir"> <ul> <li class="select">頁卡一</li> <li>頁卡二</li> <li>頁卡三</li> </ul> <div class="select">內容一</div> <div>內容二</div> <div>內容三</div> </div> <script type="text/javascript"></script> </body> </html>

預覽圖:
這裡寫圖片描述

js程式碼——點選事件

獲取元素:

var tabFir = document.getElementById("tabFir"),
    oLis = tabFir.getElementsByTagName("li"),
    oDivs = tabFir.getElementsByTagName("div");

在操作點選事件時,容易把程式碼寫成下面這種情況:

for (var i = 0; i < oLis.length; i++) {
    oLis[i].onclick = function () {
        changeTab(i);
    }
}

但是這樣是不對的,原因有三點:
1、js中所有的事件繫結都是非同步程式設計的,開始只是給元素的點選胸圍綁定了一個方法,但是需要手動點選才會執行這個方法,在此期間,不會幹等著,繼續下一次迴圈,當點選的時候迴圈早已經結束
2、在給元素繫結事件的時候,繫結的這個方法還只是定義的部分,此時方法中儲存的都是字串,我們看到的i只是一個字元
3、當點選的時候,執行對應的繫結方法,形成一個私有的作用域,在A中會使用到變數i,而i不是自己私有的,是上級作用域window下的i,此時windoew下的i已經變為oLis.length
解決此問題可以有兩種方式:使用自定義屬性的方式和閉包
自定義屬性方式程式碼:

for (var i = 0; i < oLis.length; i++) {
    oLis[i].index = i; //給物件增加一個屬性名index
    oLis[i].onclick = function () {
        changeTab(this.index);
    }
}

閉包方式程式碼:

//第一種:
for (var i = 0; i < oLis.length; i++) {
    ~function (i) {
        oLis[i].onclick = function () {
            changeTab(i);
        }
    }(i);
}

//第二種:
for (var i = 0; i < oLis.length; i++) {
    oLis[i].onclick = (function (i) {
        return function () {
            changeTab(i);
        }
    })(i);
}
<div class="box" id="tabFir">
    <ul id="tabOptions">
        <li class="select">頁卡一</li>
        <li>頁卡二</li>
        <li>頁卡三</li>
    </ul>
    <div class="select">
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
    </div>
    <div>內容二</div>
    <div>內容三</div>
</div>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript">
    var tabFir = document.getElementById("tabFir"),
        tabFirst = utils.firstChild(tabFir),  //ul
        oLis = utils.children(tabFirst);  //三個li
    for (var i = 0; i < oLis.length; i++) {
        oLis[i].onclick = function () {
            //首先把兄弟元素的選中樣式都移除掉
            var curSiblings = utils.siblings(this); //this是當前事件,即當前繫結的li,siblings獲取所有的兄弟元素節點
            for (var i = 0; i < curSiblings.length; i++) {
                utils.removeClass(curSiblings[i], "select"); //removeClass刪除樣式類名
            }
            //再讓當前點選這個元素有選中的樣式
            utils.addClass(this, "select"); //addClass:給元素增加樣式類名
            //再讓當前點選這個li父親元素的所有的弟弟元素中(三個div)中和當前點選的這個li索引相同的有選中的樣式,其餘的移除選中樣式
            var index = utils.index(this); //index:獲取當前元素的索引
            var divList = utils.nextAll(this.parentNode); //nextAll:獲取所有的弟弟元素節點
            for (var i = 0; i < divList.length; i++) {
                i === index ? utils.addClass(divList[i], "select") : utils.removeClass(divList[i], "select");
            }
        }
    }
</script>

預覽圖:
這裡寫圖片描述

但是該段程式碼只適合一個選項卡的情況,如果選項卡較多的話,最好寫成一個外掛來封裝
這裡寫圖片描述

樣式封裝——一個一個繫結

單獨建立一個“封裝.js” 檔案:

//實現一個選項卡的封裝,只要多個選項卡的主體結構一樣,那麼每一個實現的思想都是一模一樣的,唯一不一樣的就是最外層的盒子不一樣
~function () {
    /*
     * tabChange封裝一個選項卡外掛,只要大結構保持統一,即可實現選項卡功能
     * 引數:container:當前要實現選項卡的這個容器
     * defaultIndex:預設選中項的索引
     */
    function tabChange(container, defaultIndex) {
        var tabFirst = utils.firstChild(container),  //ul
            oLis = utils.children(tabFirst),  //三個li
            divList = utils.children(container, "div"); //得到div的元素標籤
        //讓defaultIndex對應的頁卡選中的樣式
        defaultIndex = defaultIndex || 0;
        utils.addClass(oLis[defaultIndex], "select");
        utils.addClass(divList[defaultIndex], "select");
        //實現具體的切換功能
        for (var i = 0; i < oLis.length; i++) {
            oLis[i].onclick = function () {
                var curSiblings = utils.siblings(this);
                for (var i = 0; i < curSiblings.length; i++) {
                    utils.removeClass(curSiblings[i], "select");
                }
                utils.addClass(this, "select");
                var index = utils.index(this);
                for (var i = 0; i < divList.length; i++) {
                    i === index ? utils.addClass(divList[i], "select") : utils.removeClass(divList[i], "select");
                }
            }
        }
    }

    //在閉包裡面,如果想讓外部使用,可以暴露一個介面selectTab
    window.selectTab = tabChange;
}();

html檔案中的js程式碼為:

<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="封裝.js"></script>
<script type="text/javascript">
    var boxList = utils.getElementsByClass("box"); //getElementsByClass:通過元素的樣式類名獲取一組元素集合(相容所有瀏覽器)
    for (var i = 0; i < boxList.length; i++) {
        selectTab(boxList[i]);
    }
</script>

可實現選項卡效果。

樣式封裝——事件委託

“封裝.js” 程式碼:

//實現一個選項卡的封裝,只要多個選項卡的主體結構一樣,那麼每一個實現的思想都是一模一樣的,唯一不一樣的就是最外層的盒子不一樣
~function () {
    /*
     * tabChange封裝一個選項卡外掛,只要大結構保持統一,即可實現選項卡功能
     * 引數:container:當前要實現選項卡的這個容器
     * defaultIndex:預設選中項的索引
     */
    function tabChange(container, defaultIndex) {
        var tabFirst = utils.firstChild(container),  //ul
            oLis = utils.children(tabFirst),  //三個li
            divList = utils.children(container, "div"); //得到div的元素標籤
        //使用時間委託來優化點選操作
        tabFirst.onclick = function (e) {
            e = e || window.event;
            e.target = e.target || e.srcElement;
            if (e.target.tagName.toLowerCase() === "li") { //說明當前點選的是li標籤
                detailFn.call(e.target, oLis, divList);
            }
        };
        //讓defaultIndex對應的頁卡選中的樣式
        defaultIndex = defaultIndex || 0;
        utils.addClass(oLis[defaultIndex], "select");
        utils.addClass(divList[defaultIndex], "select");
    }
    function detailFn(oLis, divList) {
        //保證this是當前點選的li
        var index = utils.index(this);
        utils.addClass(this, "select");
        for (var i = 0; i < divList.length; i++) {
            i === index ? utils.addClass(divList[i], "select") : (utils.removeClass(divList[i], "select"), utils.removeClass(oLis[i], "select"));
        }
    }
    //在閉包裡面,如果想讓外部使用,可以暴露一個介面selectTab
    window.selectTab = tabChange;
}();

HTML中js程式碼:

<script type="text/javascript">
    var boxList = utils.getElementsByClass("box"); //getElementsByClass:通過元素的樣式類名獲取一組元素集合(相容所有瀏覽器)
    for (var i = 0; i < boxList.length; i++) {
        selectTab(boxList[i]);
    }
</script>
樣式封裝——建構函式面向物件

“封裝.js” 程式碼:

//實現一個選項卡的封裝,只要多個選項卡的主體結構一樣,那麼每一個實現的思想都是一模一樣的,唯一不一樣的就是最外層的盒子不一樣
~function () {
    function TabChange(container, defaultIndex) {
        return this.init(container, defaultIndex);
    }

    TabChange.prototype = {
        constructor: TabChange,
        //按照索引來設定預設選中的頁卡
        defaultIndexEven: function () {
            utils.addClass(this.oLis[this.defaultIndex], "select");
            utils.addClass(this.divList[this.defaultIndex], "select");
        },
        //事件委託實現繫結切換
        liveClick: function () {
            var _this = this;
            this.tabFirst.onclick = function (e) {
                e = e || window.event;
                e.target = e.target || e.srcElement;
                if (e.target.tagName.toLowerCase() === "li") {
                    _this.detailFn(e.target);
                }
            };
        },
        detailFn: function (curEle) {
            var index = utils.index(curEle);
            utils.addClass(curEle, "select");
            for (var i = 0; i < this.divList.length; i++) {
                i === index ? utils.addClass(this.divList[i], "select") : (utils.removeClass(this.divList[i], "select"), utils.removeClass(this.oLis[i], "select"));
            }
        },
        //初始化效果,也是當前外掛的唯一入口
        init: function (container, defaultIndex) {
            this.container = container || null;
            this.defaultIndex = defaultIndex || 0;
            this.tabFirst = utils.firstChild(this.container);
            this.oLis = utils.children(this.tabFirst);
            this.divList = utils.children(this.container, "div");
            this.defaultIndexEven();
            this.liveClick();
            return this;
        }
    };
    window.selectTab = TabChange;
}();

HTML中js程式碼:

<script type="text/javascript">
    var boxList = utils.getElementsByClass("box"); //getElementsByClass:通過元素的樣式類名獲取一組元素集合(相容所有瀏覽器)
    var box1 = new selectTab(boxList[0],0);
    var box1 = new selectTab(boxList[1],1);
    var box1 = new selectTab(boxList[2],2);
</script>