Template:USTC-Software/js/autoMenu

/*

* blogMenu plugin 1.0   2017-09-01 by cary
* 说明:自动根据标签(h3,h4)生成博客目录
*/

(function ($) {

   var Menu = (function () {
       /**
        * 插件实例化部分,初始化时调用的代码可以放这里
        * @param element 传入jq对象的选择器,如 $("#J_plugin").plugin() ,其中 $("#J_plugin") 即是 element
        * @param options 插件的一些参数神马的
        * @constructor
        */
       var Plugin = function(element, options) {
           //将dom jquery对象赋值给插件,方便后续调用
           this.$element = $(element);
           //将插件的默认参数及用户定义的参数合并到一个新的obj里
           this.settings = $.extend({}, $.fn.autoMenu.defaults, typeof options === 'object' && options)
           //如果将参数设置在dom的自定义属性里,也可以这样写
           //this.settings = $.extend({}, $.fn.plugin.defaults, this.$element.data(), options);
           this.init();
       }


       /**
        * 将插件所有函数放在prototype的大对象里
        * 插件的公共方法,相当于接口函数,用于给外部调用
        * @type {{}}
        */
       Plugin.prototype = {
           init: function () {
               var opts = this.settings;
               //console.log(opts)
               this.$element.html(this.createHtml());
               this.setActive();
               this.bindEvent();
               
           },
           createHtml: function(){
               var that = this;
               var opts = that.settings;
               var width = typeof opts.width === 'number' && opts.width;
               var height = typeof opts.height === 'number' && opts.height;
               var padding = typeof opts.padding === 'number' && opts.padding;
               that.$element.width(width+padding*2);
var html = '
    '; var num = 0; $('*').each(function(){ var _this = $(this); if(_this.get(0).tagName == opts.levelOne.toUpperCase()){ _this.attr('id',num); var nodetext = that.handleTxt(_this.html()); html += '
  • <a href="#'+ num +'">'+ nodetext +'</a>
  • ';
                           num++;
                       }else if(_this.get(0).tagName == opts.levelTwo.toUpperCase()){
                           _this.attr('id',num);
                           var nodetext = that.handleTxt(_this.html());
    
    html += '
  • <a href="#'+ num +'">'+ nodetext +'</a>
  • ';
                           num++;
                       }
                   })
    
    html += '
<a href="javascript:void(0);" class="btn-box">'
                           +''
                       +'</a>';
               return html;   
           },
           handleTxt: function(txt){
               //正则表达式去除HTML的标签
               return txt.replace(/<\/?[^>]+>/g,"").trim();
           },
           setActive: function(){
               var $el = this.$element,
                   opts = this.settings,
                   items = opts.levelOne + ',' + opts.levelTwo,
                   $items = $(items),
                   offTop = opts.offTop,
                   top = $(document).scrollTop(),
                   currentId;
               if($(document).scrollTop()==0){
                   //初始化active
                   $el.find('li').removeClass('active').eq(0).addClass('active');
                   return;
               }
               $items.each(function(){
                   var m = $(this),
                       itemTop = m.offset().top;
                   if(top > itemTop-offTop){
                       currentId = m.attr('id');
                   }else{
                       return false;
                   }
               })
               var currentLink = $el.find('.active');
               if(currentId && currentLink.attr('name')!= currentId){
                 currentLink.removeClass('active');
                 $el.find('[name='+currentId+']').addClass('active');
               }
               
           },
           bindEvent: function(){
               var _this = this;
               $(window).scroll(function(){
                   _this.setActive()
               });
               _this.$element.on('click','.btn-box',function(){
                   if($(this).find('span').hasClass('icon-minus-sign')){
                       $(this).find('span').removeClass('icon-minus-sign').addClass('icon-plus-sign');
                       _this.$element.find('ul').fadeOut();
                   }else{
                       $(this).find('span').removeClass('icon-plus-sign').addClass('icon-minus-sign');
                       _this.$element.find('ul').fadeIn();
                   }
                   
               })
           }
       };
       return Plugin;
   })();


   /**
    * 这里是将Plugin对象 转为jq插件的形式进行调用
    * 定义一个插件 plugin
    */
   $.fn.autoMenu = function (options) {
       return this.each(function () {
           var $el = $(this),
               menu = $el.data('autoMenu'),
               option = $.extend({}, $.fn.autoMenu.defaults, typeof options === 'object' && options);
           if (!menu) {
               //将实例化后的插件缓存在dom结构里(内存里)
               $el.data('autoMenu',new Menu(this, option));
           }
           /**
            * 如果插件的参数是一个字符串,则 调用 插件的 字符串方法。
            * 如 $('#id').plugin('doSomething') 则实际调用的是 $('#id).plugin.doSomething();
            */
           if ($.type(options) === 'string') menu[option]();
       });
   };
   /**
    * 插件的默认值
    */
   $.fn.autoMenu.defaults = {
       levelOne : 'h3', //一级标题
       levelTwo : 'h4',  //二级标题(暂不支持更多级)
       width : 170, //容器宽度
       height : 800, //容器高度
       padding: 20, //内部间距
       offTop : 100, //滚动切换导航时离顶部的距离
   };
   /**
    * 优雅处: 通过data-xxx 的方式 实例化插件。
    * 这样的话 在页面上就不需要显示调用了。
    * 可以查看bootstrap 里面的JS插件写法
    */
   $(function () {
       if($('[data-autoMenu]').length>0){
           if($(window).width() > 986){
               new Menu($('[data-autoMenu]'));
           }
       }
       
   });

})(jQuery);