/* * 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 = `
' + '' + ''; 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 + ',' + opts.levelThree, $items = $(items), // offTop = opts.offTop, currentId; if ($("#manual").scrollTop() == 0) { //初始化active $el.find('li').removeClass('active').eq(0).addClass('active'); return; } $items.each(function() { var m = $(this), itemTop = m.offset().top; if (itemTop < 1) { 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; $('#manual').scroll(function () { _this.$element.find('input').val('') _this.$element.find('li').show() _this.setActive() // scroll var actived = _this.$element.find('.active') if (actived.length != 0) { var top = actived.offset().top if (top < 0 || top > _this.settings.height) { actived.get(0).scrollIntoView({ behavior: "smooth", block: "center" }); } } }); _this.$element.off() _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(); _this.$element.find('input').focus() } }) // 目录搜索 _this.$element.on('input', 'input', function () { var keyword = $(this).val() _this.$element.find('li').each(function(){ if ($(this).find('a').text().toUpperCase().includes(keyword.toUpperCase())) { $(this).show() } else { $(this).hide() } }) }) } }; 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: 'h1', //一级标题 levelTwo: 'h2', //二级标题(暂不支持更多级) levelThree: 'h3', //二级标题(暂不支持更多级) width: 220, //容器宽度 height: 460, //容器高度 padding: 20, //内部间距 offTop: 100, //滚动切换导航时离顶部的距离 }; /** * 优雅处: 通过data-xxx 的方式 实例化插件。 * 这样的话 在页面上就不需要显示调用了。 * 可以查看bootstrap 里面的JS插件写法 */ $(function() { if ($('[data-autoMenu]').length > 0) { new Menu($('[data-autoMenu]')); } }); })(jQuery);