bootstrap源碼學習與樣本:bootstrap-dropdown

來源:互聯網
上載者:User

bootstrap-dropdown組件是個爛東西,我讀後的整體感覺。

一個下拉開菜單的設計:

                  <ul class="nav pull-right">                        <li id="fat-menu" class="dropdown">                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">下拉 <b class="caret"></b></a>                            <ul class="dropdown-menu">                                <li><a href="#">動作</a></li>                                <li><a href="#">另一個動作</a></li>                                <li><a href="#">其他</a></li>                                <li class="divider"></li>                                <li><a href="#">另一個連結</a></li>                            </ul>                        </li>                    </ul>

首先下拉開菜單其中就是當中第二層的UL元素,類名為dropdown-menu。下拉式功能表通常處於隱藏狀態。我們可以在它的父元素上加個open類名,讓它顯示出來。它的父元素通常帶個dropdown類名,其實是提供了一個相對定位的包含塊。當然除了dropdown外,你還可以選擇用dropup。dropdown是讓下拉式功能表向下顯示,dropup是向上展示。要開啟下拉式功能表,通常我們要點擊某處讓它顯示出來。我們稱之為觸發器。這個觸發器帶一個data-toggle=dropdown的自訂屬性。通過前面的學習,你們應該隱約察覺到,data-toggle在bootstrap有特殊意義,是讓目標對象表現某一類控制項,什麼data-toggle=button,data-toggle=buttons-checked,data-toggle=radio……不過它還有專門的類名dropdown-toggle。觸發器可以通過data-target自訂屬性指定目標下拉框開啟,也可以通過href屬性開啟。不過bootstrap的下拉框有嚴重的排它性,一個頁面只能開啟一個下拉框,也無法通過套嵌組建多級下拉框。

下面是它的源碼,我們發現它是支援鍵盤切換的,但寫得很爛,乃至多數情況下失敗。

!function ($) {    "use strict"; // jshint ;_;    /* DROPDOWN CLASS DEFINITION  * ========================= */    var toggle = '[data-toggle=dropdown]'    , Dropdown = function (element) {        var $el = $(element).on('click.dropdown.data-api', this.toggle)        $('html').on('click.dropdown.data-api', function () {            $el.parent().removeClass('open')        })    }    Dropdown.prototype = {        constructor: Dropdown  ,         toggle: function (e) {            var $this = $(this)            , $parent            , isActive            if ($this.is('.disabled, :disabled')) return            //分別通過以下三個途徑:            //1 data-target自訂屬性             //2 href的屬性中的hash(也是ID選取器),             //3這個按鈕的直屬父節點            $parent = getParent($this)            isActive = $parent.hasClass('open')            //每次頁面只能有一個菜單被開啟,這是個失敗的設計            clearMenus()            //如果沒有開啟,則開啟它            if (!isActive) {                $parent.toggleClass('open')            }            //讓當前功能表項目獲得焦點            $this.focus()            return false        } ,         keydown: function (e) {            var $this            , $items            , $parent            , isActive            , index            //如果不是上下方向鍵或斷行符號鍵,返回            if (!/(38|40|27)/.test(e.keyCode)) return            $this = $(this)            e.preventDefault()            e.stopPropagation()            //如果標識為禁止狀態            if ($this.is('.disabled, :disabled')) return            //取得控制項的容器            $parent = getParent($this)            //如果處於啟用狀態            isActive = $parent.hasClass('open')            //如果沒有啟用或激話了+斷行符號,就觸發其點擊事件            if (!isActive || (isActive && e.keyCode == 27)) return $this.click()            //如果是功能表項目(不能是作為分隔線的LI)下的A元素            $items = $('[role=menu] li:not(.divider):visible a', $parent)            if (!$items.length) return            //那麼我們取得當前獲得焦點的元素作為基準,通過它上下移動            index = $items.index($items.filter(':focus'))            if (e.keyCode == 38 && index > 0) index--                                        // up            if (e.keyCode == 40 && index  <!DOCTYPE html><html>    <head>        <title>bootstrap學習 by 司徒正美</title>        <meta http-equiv="Content-type" content="text/html; charset=utf-8">        <link rel="stylesheet" href="http://files.cnblogs.com/rubylouvre/bootstrap.css"/>         <script src="http://files.cnblogs.com/rubylouvre/jquery1.83.js" > </script>        <script src="http://files.cnblogs.com/rubylouvre/bootstrap-transition.js"></script>        <script src="http://files.cnblogs.com/rubylouvre/bootstrap-dropdown.js"></script>        <script>            $(function(){                //注意:事件要綁定在UI容器上,而不是關閉按鈕中                $('.dropdown-toggle').dropdown()            })                     </script>    </head>    <body>        <div id="navbar-example" class="navbar navbar-static">            <div class="navbar-inner">                <div class="container" style="width: auto;">                    <a class="brand" href="#">項目名稱</a>                    <ul class="nav">                        <li class="dropdown">                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">下拉 <b class="caret"></b></a>                            <ul class="dropdown-menu">                                <li><a href="#">動作</a></li>                                <li><a href="#">另一個動作</a></li>                                <li><a href="#">其他</a></li>                                <li class="divider"></li>                                <li><a href="#">另一個連結</a></li>                            </ul>                        </li>                        <li class="dropdown open">                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">下拉 <b class="caret"></b></a>                            <ul class="dropdown-menu">                                <li><a href="#">動作</a></li>                                <li><a href="#">另一個動作</a></li>                                <li><a href="#">其他</a></li>                                <li class="divider"></li>                                <li><a href="#">另一個連結</a></li>                            </ul>                        </li>                    </ul>                    <ul class="nav pull-right">                        <li id="fat-menu" class="dropdown">                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">下拉 <b class="caret"></b></a>                            <ul class="dropdown-menu">                                <li><a href="#">動作</a></li>                                <li><a href="#">另一個動作</a></li>                                <li><a href="#">其他</a></li>                                <li class="divider"></li>                                <li><a href="#">另一個連結</a></li>                            </ul>                        </li>                    </ul>                </div>            </div>        </div>        <br/>        <br/>        <br/>        <br/>        <br/>        <ul class="nav nav-pills">            <li><a href="#">規則的連結</a></li>            <li class="dropup" id="menutest1">                <a class="dropdown-toggle" data-toggle="dropdown" href="#menutest1">下拉項                    <b class="caret"></b>                </a>                <ul class="dropdown-menu">                    <li><a href="#">動作</a></li>                    <li><a href="#">另一個動作</a></li>                    <li><a href="#">其他</a></li>                    <li class="divider"></li>                    <li><a href="#">被間隔的連結</a></li>                </ul>            </li>            <li class="active">                <a data-toggle="dropdown" href="#menutest1">點擊我看看                </a>            </li>        </ul>    </body></html>

運行代碼

以下是它對應的less。

//// Dropdown menus// --------------------------------------------------// Use the .menu class on any 
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns
    .dropup,
    .dropdown {
    position: relative;
    }
    .dropdown-toggle {
    // The caret makes the toggle a bit too tall in IE7
    *margin-bottom: -3px;
    }
    .dropdown-toggle:active,
    .open .dropdown-toggle {
    outline: 0;
    }

    // Dropdown arrow/caret
    // --------------------
    .caret {
    display: inline-block;
    width: 0;
    height: 0;
    vertical-align: top;
    border-top: 4px solid @black;
    border-right: 4px solid transparent;
    border-left: 4px solid transparent;
    content: "";
    }

    // Place the caret
    .dropdown .caret {
    margin-top: 8px;
    margin-left: 2px;
    }

    // The dropdown menu (ul)
    // ----------------------
    .dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: @zindexDropdown;
    display: none; // none by default, but block on "open" of the menu
    float: left;
    min-width: 160px;
    padding: 5px 0;
    margin: 2px 0 0; // override default ul
    list-style: none;
    background-color: @dropdownBackground;
    border: 1px solid #ccc; // Fallback for IE7-8
    border: 1px solid @dropdownBorder;
    *border-right-width: 2px;
    *border-bottom-width: 2px;
    .border-radius(6px);
    .box-shadow(0 5px 10px rgba(0,0,0,.2));
    -webkit-background-clip: padding-box;
    -moz-background-clip: padding;
    background-clip: padding-box;

    // Aligns the dropdown menu to right
    &.pull-right {
    right: 0;
    left: auto;
    }

    // Dividers (basically an hr) within the dropdown
    .divider {
    .nav-divider(@dropdownDividerTop, @dropdownDividerBottom);
    }

    // Links within the dropdown menu
    li > a {
    display: block;
    padding: 3px 20px;
    clear: both;
    font-weight: normal;
    line-height: @baseLineHeight;
    color: @dropdownLinkColor;
    white-space: nowrap;
    }
    }

    // Hover state
    // -----------
    .dropdown-menu li > a:hover,
    .dropdown-menu li > a:focus,
    .dropdown-submenu:hover > a {
    text-decoration: none;
    color: @dropdownLinkColorHover;
    #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%));
    }

    // Active state
    // ------------
    .dropdown-menu .active > a,
    .dropdown-menu .active > a:hover {
    color: @dropdownLinkColorActive;
    text-decoration: none;
    outline: 0;
    #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%));
    }

    // Disabled state
    // --------------
    // Gray out text and ensure the hover state remains gray
    .dropdown-menu .disabled > a,
    .dropdown-menu .disabled > a:hover {
    color: @grayLight;
    }
    // Nuke hover effects
    .dropdown-menu .disabled > a:hover {
    text-decoration: none;
    background-color: transparent;
    background-image: none; // Remove CSS gradient
    .reset-filter();
    cursor: default;
    }

    // Open state for the dropdown
    // ---------------------------
    .open {
    // IE7's z-index only goes to the nearest positioned ancestor, which would
    // make the menu appear below buttons that appeared later on the page
    *z-index: @zindexDropdown;

    & > .dropdown-menu {
    display: block;
    }
    }

    // Right aligned dropdowns
    // ---------------------------
    .pull-right > .dropdown-menu {
    right: 0;
    left: auto;
    }

    // Allow for dropdowns to go bottom up (aka, dropup-menu)
    // ------------------------------------------------------
    // Just add .dropup after the standard .dropdown class and you're set, bro.
    // TODO: abstract this so that the navbar fixed styles are not placed here?
    .dropup,
    .navbar-fixed-bottom .dropdown {
    // Reverse the caret
    .caret {
    border-top: 0;
    border-bottom: 4px solid @black;
    content: "";
    }
    // Different positioning for bottom up menu
    .dropdown-menu {
    top: auto;
    bottom: 100%;
    margin-bottom: 1px;
    }
    }

    // Sub menus
    // ---------------------------
    .dropdown-submenu {
    position: relative;
    }
    // Default dropdowns
    .dropdown-submenu > .dropdown-menu {
    top: 0;
    left: 100%;
    margin-top: -6px;
    margin-left: -1px;
    .border-radius(0 6px 6px 6px);
    }
    .dropdown-submenu:hover > .dropdown-menu {
    display: block;
    }

    // Dropups
    .dropup .dropdown-submenu > .dropdown-menu {
    top: auto;
    bottom: 0;
    margin-top: 0;
    margin-bottom: -2px;
    .border-radius(5px 5px 5px 0);
    }

    // Caret to indicate there is a submenu
    .dropdown-submenu > a:after {
    display: block;
    content: " ";
    float: right;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    border-width: 5px 0 5px 5px;
    border-left-color: darken(@dropdownBackground, 20%);
    margin-top: 5px;
    margin-right: -10px;
    }
    .dropdown-submenu:hover > a:after {
    border-left-color: @dropdownLinkColorHover;
    }

    // Left aligned submenus
    .dropdown-submenu.pull-left {
    // Undo the float
    // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere.
    float: none;

    // Positioning the submenu
    > .dropdown-menu {
    left: -100%;
    margin-left: 10px;
    .border-radius(6px 0 6px 6px);
    }
    }

    // Tweak nav headers
    // -----------------
    // Increase padding from 15px to 20px on sides
    .dropdown .dropdown-menu .nav-header {
    padding-left: 20px;
    padding-right: 20px;
    }

    // Typeahead
    // ---------
    .typeahead {
    z-index: 1051;
    margin-top: 2px; // give it some space to breathe
    .border-radius(@baseBorderRadius);
    }

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.