Bootstrap插件之 下拉菜单 源码分析~~

前言

前前后后写了大概有四十多篇文章了……阅读量 一直都是 3~5的酱紫。评论倒是很稳定 一直都是零。。这怎么行。于是我痛定思痛。分析了一下自己博客的优缺点。

缺点 1 界面丑

  2 干货少

  3 语言不生动

优点

  没有……

接下来要努力把以上三点做好~今天算是开端。。。!!因为今天研究了bootstrap下拉菜单一天吧差不多,而且网上好像没有看到分析bootstrap插件源码的,所以这篇文章质量应该是比以前的要好点的~

废话结束~~

正文

本文知识点

1 jquery的时间命名空间

2jquery插件写法

好了直接上代码 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="../lib/bootstrap-2.3.2/dist/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">菜鸟教程</a>
        </div>
        <div>
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">iOS</a></li>
                <li><a href="#">SVN</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                        Java
                        <b class="caret"></b>
                    </a>
                    <ul class="dropdown-menu">
                        <li><a href="#">jmeter</a></li>
                        <li><a href="#">EJB</a></li>
                        <li><a href="#">Jasper Report</a></li>
                        <li class="divider"></li>
                        <li><a href="#">分离的链接</a></li>
                        <li class="divider"></li>
                        <li><a href="#">另一个分离的链接</a></li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
</nav>

<button id="btn1">点我</button>

</body>


<script src="../lib/jquery-1.11.1.js"></script>
<script>
    +function ($) {
        'use strict';
        // DROPDOWN CLASS DEFINITION
        // =========================
        var backdrop = '.dropdown-backdrop'
        var toggle = '[data-toggle="dropdown"]'//用于绑定事件,相当于一个钩子~ 链接组件内外
        var Dropdown = function (element) {//这里很巧妙,刚看到这里的时候 我还以为是在这里绑定的事件,其实不是,这里就是一个对象,有开关下拉列表的方法,不会暴露出去
            $(element).on('click.bs.dropdown', this.toggle)
        }

        Dropdown.VERSION = '3.3.0'
        Dropdown.prototype.toggle = function (e) {//对象方法--切换状态
            var $this = $(this)

            if ($this.is('.disabled, :disabled')) return

            var $parent = getParent($this)
            var isActive = $parent.hasClass('open')

            clearMenus()

            if (!isActive) {
                if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
                    // if mobile we use a backdrop because click events don't delegate
                    $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
                }

                var relatedTarget = {relatedTarget: this}
                $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))

                if (e.isDefaultPrevented()) return

                $this
                        .trigger('focus')
                        .attr('aria-expanded', 'true')

                $parent
                        .toggleClass('open')
                        .trigger('shown.bs.dropdown', relatedTarget)
            }

            return false
        }

        Dropdown.prototype.keydown = function (e) {//对象方法--
            if (!/(38|40|27|32)/.test(e.which)) return

            var $this = $(this)

            e.preventDefault()
            e.stopPropagation()

            if ($this.is('.disabled, :disabled')) return

            var $parent = getParent($this)
            var isActive = $parent.hasClass('open')

            if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
                if (e.which == 27) $parent.find(toggle).trigger('focus')
                return $this.trigger('click')
            }

            var desc = ' li:not(.divider):visible a'
            var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)

            if (!$items.length) return

            var index = $items.index(e.target)

            if (e.which == 38 && index > 0)                 index--                        // up
            if (e.which == 40 && index < $items.length - 1) index++                        // down
            if (!~index)                                      index = 0

            $items.eq(index).trigger('focus')
        }

        function clearMenus(e) {//对象方法--
            if (e && e.which === 3) return
            $(backdrop).remove()
            $(toggle).each(function () {
                var $this = $(this)
                var $parent = getParent($this)
                var relatedTarget = {relatedTarget: this}

                if (!$parent.hasClass('open')) return

                $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

                if (e.isDefaultPrevented()) return

                $this.attr('aria-expanded', 'false')
                $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
            })
        }

        function getParent($this) {//内部方法
            var selector = $this.attr('data-target')

            if (!selector) {
                selector = $this.attr('href')
                selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^s]*$)/, '') // strip for ie7
            }

            var $parent = selector && $(selector)

            return $parent && $parent.length ? $parent : $this.parent()
        }


        // DROPDOWN PLUGIN DEFINITION
        // ==========================

        function Plugin(option) {//这里很关键,
            //debugger;
            //console.log(this);这里this是jquery对象
            return this.each(function () {//在本例中 也就是 遍历$(".dropdown-toggle")对应的dom对象  //这里的this是dom对象!!!
               // console.log(this);
               // debugger;
                var $this = $(this)//包装成jquery对象
                var data = $this.data('bs.dropdown')//第一次肯定没有

                if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))//此处真正的 实例化了Dropdown();
                if (typeof option == 'string') data[option].call($this)//调用Dropdown实例对象toggole对应的方法!
            })
        }


        var old = $.fn.dropdown

        $.fn.dropdown = Plugin//将方法 暴露出去,外界通过$(".dropdown-toggle").dropdown('toggle');来主动 开关下拉列表
        $.fn.dropdown.Constructor = Dropdown


        // DROPDOWN NO CONFLICT
        // ====================

        $.fn.dropdown.noConflict = function () {
            $.fn.dropdown = old
            return this
        }


        // APPLY TO STANDARD DROPDOWN ELEMENTS
        // ===================================

        $(document)
                .on('click.bs.dropdown.data-api', clearMenus)
                .on('click.bs.dropdown.data-api', '.dropdown form', function (e) {
                    e.stopPropagation()
                })
                .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)//再此处绑定的下拉按钮的点击事件  ps:click.bs.dropdown.data-api 这是什么鬼?请搜索“事件命名空间”
                .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
                .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
                .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)

    }(jQuery);

</script>
<script>


    $(function () {
        // 默认显示
        //$(".dropdown-toggle").dropdown('toggle');

        $('#btn1').click(

            function (e) {
                //console.log(this); // ps补充一下 这里this 指向谁?是jquery对象 还是 原生dom的button对象?? 放开注释看一下就知道了~~
                $(".dropdown-toggle").dropdown('toggle');
                stopBubble(e);
            }
        );
    });

    function stopBubble(e){
        //一般用在鼠标或键盘事件上
        if(e && e.stopPropagation){
            //W3C取消冒泡事件
            e.stopPropagation();
        }else{
            //IE取消冒泡事件
            window.event.cancelBubble = true;
        }
    };
</script>
</html>
View Code

注释都写得很详细了~如果您有任何疑惑或者发现问题 欢迎随时留言哦~~

原文地址:https://www.cnblogs.com/WhiteHorseIsNotHorse/p/6271282.html