jQuery UI Tabs插件无法处理2层标签 [英] jQuery UI Tabs plugin can't handle 2 tiers of tabs

查看:92
本文介绍了jQuery UI Tabs插件无法处理2层标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个使用jQuery UI选项卡以结构化方式显示用户生成的数据的旧项目.该系统不限制用户可以创建的选项卡数量(但通常在第二层中大约有30个),而jQuery UI Tabs仅包装这些选项卡,这看起来非常不专业.

I'm working on a legacy project that uses jQuery UI tabs to display user generated data in a structured way. The system does not cap the number of tabs a user can create (but usually there are about 30 in the second tier) and jQuery UI Tabs just wraps the tabs, which looks very unprofessional.

我偶然发现了Paul Blundell的漂亮插件 OverflowTabs (来自他的JSFiddle: http://jsfiddle.net/o1wLbtj4/,),但很遗憾,我无法使其正常运行与我的2层标签.我正在使用jQuery 1.10.2和jQuery UI 1.10.4.

I stumbled over Paul Blundell's beautiful plugin OverflowTabs from 2014 (here is his JSFiddle: http://jsfiddle.net/o1wLbtj4/, ), but unfortunately I can't get it to work right with my 2 tiers of tabs. I'm using jQuery 1.10.2 and jQuery UI 1.10.4.

我做了一个简化的JSFiddle,它显示了我要执行的操作:打开一个对话框窗口,其中包含2层选项卡中的数据.当标签过多时,两个层次都应将溢出的标签推入菜单,单击该菜单可打开下拉菜单,但此刻(在具有名称的层次上)仅显示最后一个标签,并且下拉按钮不起作用并读取为0: http://jsfiddle.net/megahra/6s2xwgec/18/

I've made a simplified JSFiddle which shows what I'm trying to do: open a dialogue window that contains data in 2 tiers of tabs. When there are too many tabs, both tiers are supposed to push overflowing tabs into a menu that opens a dropdown when clicked, but at the moment (on the tier with names) only the last tab is displayed and the dropdown button doesn't work and reads 0: http://jsfiddle.net/megahra/6s2xwgec/18/

据我所知,该插件正确地从第一层中删除了选项卡,并将它们添加到溢出div(_hideTab函数)中,但是由于某些原因,后来被覆盖了.我怀疑该插件无法正确处理第二层,但是我不知道该在哪里修复.

As far as I can tell the plugin properly removes tabs from the first tier and adds them to the overflow div (_hideTab function), but for some reason later this is overwritten. I suspect that the plugin can't deal with the second tier properly, but I don't know where to fix that.

如果有人能指出我正确的方向,我将不胜感激!

I'd be really grateful if anyone could point me in the right direction!


多亏了Twisty的帮助,该插件现在可用于多个选项卡级别,并且我修复了一些错误.
这是正在工作的JSFiddle:: https://jsfiddle.net/megahra/uexr4qfw/289/
-已知错误:初始化时,此插件不适用于style="display: none"的div中的选项卡.


Thanks to Twisty's help the plugin now works for multiple tiers of tabs and I fixed a few bugs.
Here is a working JSFiddle: https://jsfiddle.net/megahra/uexr4qfw/289/
- Known bug: this plugin is not applied to tabs in divs with style="display: none" at time of initialization.

$.widget("ui.tabs", $.ui.tabs, {
  options: {
    overflowTabs: false,
    tabPadding: 25,
    containerPadding: 0,
    dropdownSize: 50
  },

  _create: function() {
    this._super("_create");
    this.tabsWidth = 0;
    this.containerWidth = 0;
    this.overflowTabsId = "id" + this._createUniqueId();

    $(this.element).addClass(this.overflowTabsId);

    if (!this.options.overflowTabs)
      return;

    // update the tabs
    this.updateOverflowTabs();

    // Detect a window resize and check the tabs again
    var that = this;
    var el = this.element;

    $(window).resize(function() {
      // Add a slight delay after resize, to fix Maximise issue.
      setTimeout(function() {
        that.updateOverflowTabs();
      }, 150);
    });

    // Detect dropdown click
    $(el).on("click", '> .overflow-selector', function(e) {
      $('> .ui-tabs-overflow', el).toggleClass('hide');

      $overflowTabs = $('.ui-tabs-overflow').not($('> .ui-tabs-overflow', el));

      //if there is more than the currently clicked one, close all others
      if($overflowTabs) {
        $overflowTabs.toggleClass('hide', true);
        }
    });

    //Detect tab click
    $('li a').on("click", function(e) {
        //close dropdown if open
        $('> .ui-tabs-overflow', el).toggleClass('hide', true);
        //ToDo: apply overflowTabs plugin to content of new tab (if it contains tabs)

    });
  },

  refresh: function() {
    this._super("refresh");
    this.updateOverflowTabs();
  },

  updateOverflowTabs: function() {
    var failsafe = 0;
    this._calculateWidths();
    var el = this.element;

    // Loop until tabsWidth is less than the containerWidth
    while (this.tabsWidth > this.containerWidth -10 && failsafe < 30) {
      this._hideTab();
      this._calculateWidths();
      failsafe++;
    }

    // Finish now if there are no tabs in the overflow list
    if ($('> .ui-tabs-overflow li', el).length === 0)
      return;

    // Reset
    failsafe = 0;

    // Get the first tab in the overflow list
    var next = this._nextTab();

    // Loop until we cannot fit any more tabs
    while (next.totalSize < this.containerWidth && $('> .ui-tabs-overflow li', el).length > 0 && failsafe < 30) {
      this._showTab(next.tab);
      this._calculateWidths();
      next = this._nextTab();
      failsafe++;
    }

    $('> .overflow-selector .total', el).html($('> .ui-tabs-overflow li', el).length);
  },

  _calculateWidths: function() {
    var width = 0;
    $(this.element).find('> .ui-tabs-nav > li').each(function() {
      width += $(this).outerWidth(true);
    });
    this.tabsWidth = width;
    this.containerWidth = $(this.element).parent().width() - this.options.containerPadding - this.options.dropdownSize;
  },
  _hideTab: function() {
    if (!$(this.element).find('> .ui-tabs-overflow').length) {
      $(this.element).find('> .ui-tabs-nav').after('<ul class="ui-tabs-overflow hide"></ul>');
      $(this.element).find('> .ui-tabs-overflow').after('<div class="overflow-selector">&#8595 <span class="total">0</span></div>');
      //calculate position of overflow-selector relativ to tab row (overflow-selector is 15px high)
      let topOffset = ($(this.element).find('> .ui-tabs-nav').innerHeight() * 0.48) - 12;
      $(this.element).find('> .overflow-selector').css('top', topOffset);
    }
    var lastTab = $('> .ui-tabs-nav li', this.element).last();
    lastTab.prependTo($('> .ui-tabs-overflow', this.element));
  },
  _showTab: function(tab) {
    tab.appendTo($('> .ui-tabs-nav', this.element));

    // Check to see if overflow list is now empty
    if ($(this.element).find('> .ui-tabs-overflow li').size() == 0) {
      $(this.element).find('> .ui-tabs-overflow').remove();
      $(this.element).find('> .overflow-selector').remove();
    }
  },
  _nextTab: function() {
    var result = {};
    var firstTab = $(this.element).find('> .ui-tabs-overflow li').first();
    result.tab = firstTab;
    result.totalSize = this.tabsWidth + this._textWidth(firstTab) + this.options.tabPadding;
    return result;
  },
  _textWidth: function(element) {
    var self = $(element),
      children = self.children(),
      calculator = $('<span style="display: inline-block;" />'),
      width;

    children.wrap(calculator);
    width = children.parent().width();
    children.unwrap();

    return width;
  },

  _createUniqueId: function() {
    // Math.random should be unique because of its seeding algorithm.
    // Convert it to base 36 (numbers + letters), and grab the first 9 characters
    // after the decimal.
    return '_' + Math.random().toString(36).substr(2, 9);
    }
});

推荐答案

找到了一些旧代码用法,只是做了一些小的清理.我发现了几个问题.

Found some legacy code usage and just did a bit of minor cleanup. I found a few issues.

工作示例: https://jsfiddle.net/Twisty/tbvasj1g/

  1. 点击事件非常贪婪,并且隐藏了不需要隐藏的列表项
  2. 添加/删除类是预切换方法.更新为使用.toggleClass()
  3. .size()已针对length

  1. Click Event was being greedy and was hiding list items that did not need to be hidden
  2. Add/Remove class is pre-toggle method. Updated to use .toggleClass()
  3. .size() is depreciated for length

注意:此方法已在jQuery 3.0中删除.请改用.length属性. .size()方法在功能上等效于.length属性.但是,.length属性是首选,因为它没有函数调用的开销.

Note: This method has been removed in jQuery 3.0. Use the .length property instead. The .size() method is functionally equivalent to the .length property; however, the .length property is preferred because it does not have the overhead of a function call.

  • $(this.element).find(selector)替换为速记$(selector, this.element).

  • $(this.element).find(selector) replaced with shorthand $(selector, this.element).

    小部件工厂

    $.widget("ui.tabs", $.ui.tabs, {
      options: {
        overflowTabs: false,
        tabPadding: 25,
        containerPadding: 0,
        dropdownSize: 50
      },
      _create: function() {
        this._super("_create");
        this.tabsWidth = 0;
        this.containerWidth = 0;
        if (!this.options.overflowTabs)
          return;
    
        // update the tabs
        this.updateOverflowTabs();
    
        // Detect a window resize and check the tabs again
        var that = this;
        var el = this.element;
    
        $(window).resize(function() {
          // Add a slight delay after resize, to fix Maximise issue.
          setTimeout(function() {
            that.updateOverflowTabs();
          }, 150);
        });
    
        // Detect dropdown click
        $(".tabStructure").on("click", ".overflow-selector", function(e) {
          $('.ui-tabs-overflow', el).toggleClass('hide');
        });
      },
    
      refresh: function() {
        this._super("refresh");
        this.updateOverflowTabs();
      },
    
      updateOverflowTabs: function() {
        var failsafe = 0;
        this._calculateWidths();
        var el = this.element;
        console.log("cWidth", this.containerWidth);
    
        // Loop until tabsWidth is less than the containerWidth
        while (this.tabsWidth > this.containerWidth && failsafe < 30) {
          //debugger;
          this._hideTab();
          this._calculateWidths();
          failsafe++;
        }
    
        // Finish now if there are no tabs in the overflow list
        if ($('.ui-tabs-overflow li', el).length === 0)
          return;
    
        // Reset
        failsafe = 0;
    
        // Get the first tab in the overflow list
        var next = this._nextTab();
    
        // Loop until we cannot fit any more tabs
        while (next.totalSize < this.containerWidth && $('.ui-tabs-overflow li', el).length > 0 && failsafe < 30) {
          this._showTab(next.tab);
          this._calculateWidths();
          next = this._nextTab();
          failsafe++;
        }
    
        $('.overflow-selector .total', el).html($('.ui-tabs-overflow li', el).length);
      },
    
      _calculateWidths: function() {
        var width = 0;
        $(this.element).find('.ui-tabs-nav > li').each(function() {
          width += $(this).outerWidth(true);
          //debugger;
        });
        this.tabsWidth = width;
        this.containerWidth = $(this.element).parent().width() - this.options.containerPadding - this.options.dropdownSize;
      },
      _hideTab: function() {
        if (!$('.ui-tabs-overflow').length) {
          $(this.element).find('.ui-tabs-nav').after('<ul class="ui-tabs-overflow hide"></ul>');
          $(this.element).find('.ui-tabs-overflow').after('<div class="overflow-selector">&#8595 <span class="total">0</span></div>');
        }
        var lastTab = $(this.element).find('.ui-tabs-nav li').last();
        lastTab.appendTo($(this.element).find('.ui-tabs-overflow'));
      },
      _showTab: function(tab) {
        tab.appendTo($(this.element).find('.ui-tabs-nav'));
    
        // Check to see if overflow list is now empty
        if ($(this.element).find('.ui-tabs-overflow li').size() == 0) {
          $(this.element).find('.ui-tabs-overflow').remove();
          $(this.element).find('.overflow-selector').remove();
        }
      },
      _nextTab: function() {
        var result = {};
        var firstTab = $(this.element).find('.ui-tabs-overflow li').first();
        result.tab = firstTab;
        result.totalSize = this.tabsWidth + this._textWidth(firstTab) + this.options.tabPadding;
        return result;
      },
      _textWidth: function(element) {
        var self = $(element),
          children = self.children(),
          calculator = $('<span style="display: inline-block;" />'),
          width;
    
        children.wrap(calculator);
        width = children.parent().width();
        children.unwrap();
    
        return width;
      }
    });
    
    $(function() {
      $("#rowDialog").dialog({
        title: 'Test modal',
        closeOnEscape: false,
        minHeight: 'auto',
        width: '600px',
        modal: true,
        resizable: true,
        buttons: [{
          // Close button
          text: 'Close',
          click: function() {
            $(this).dialog('close')
          },
        }]
      });
    
      $(".tabStructure").tabs({
        overflowTabs: true
      });
    });
    

    总体上不支持此解决方案.我建议分页.如果其他选项卡中没有内容或内容很多,则下拉列表将被剪切.另外,如果您从下拉菜单中选择一个选项卡,该选项卡将被隐藏,并且您也无法知道正在查看的选项卡,因为它们都不是可视指示器.

    Not a fan of this solution on a whole. I would advise pagination of the tabs. If there is no content in the other tabs or not a lot of content, the drop-down gets clipped. Also if you select a tab from the drop-down, it gets hidden and you have no good way to know which tab you're viewing, their is no visual indicator.

    这篇关于jQuery UI Tabs插件无法处理2层标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆