javascript - 创建两个可以互相通信的 jQuery 插件

标签 javascript jquery plugins jquery-events extends

我现在脑子一片困惑。我想创建两个 jQuery 插件:

  1. 标签插件
  2. slider 插件。

该插件必须相互通信,例如,如果我单击一个选项卡,该选项卡将激活关联 slider 中的正确索引。 如果我单击幻灯片,这也会激活正确的选项卡。

我开始为此创建事件监听器和触发器,当单击我的选项卡时,会触发一个事件 tabChanged ,并且在我的 slider 插件中我正在监听它。 但问题是,我的 slider 可以在选项卡之前加载,因此监听器未正确附加...

这次我尝试在文档上触发另一个事件,称为 tabsLoaded 并等待该响应,它可以工作,但开始有点困惑。

我想知道是否有人对此有更好的解决方案? 选项卡和 slider 也可以独立工作,可能只有选项卡而不关联 slider 。

这是我的选项卡插件:

(function($) {
  let pluginName = 'Tabs';

  function Tabs(element, options) {
    let settings = {};

    this.element = element;
    this.$element = $(this.element);
    this.settings = $.extend({}, settings, options);

    this.children = null;
    this.activeTabIndex = 0;
    this.nbTabs = 0;

    this.init();
  }

  $.extend(Tabs.prototype, {

    init: function() {
      this.children = this.$element.children();
      this.nbTabs = this.children.length;

      // Listeners
      this.children.on('click', {
        tabs: this
      }, this.onTabChange); // Click on a tab
      $(this).on('tabChange', this.setActive);

      // On Init, active the first tab
      if (this.children && this.nbTabs > 0) {
        $(this).trigger({
          type: 'tabChange',
          tab: this.children.first().index(),
        });
      }

      $(document).trigger({
        type: 'tabLoaded',
        tabs: this,
      });
    },
    setActive: function(event) {
      this.activeTabIndex = event.tab;
      this.children.eq(this.activeTabIndex).addClass('is-active');
    },
    onTabChange: function(event) {
      event.preventDefault();
      const tabs = event.data.tabs;
      // Reset active classes
      tabs.children.removeClass('is-active');
      // Launch changeTab
      $(tabs).trigger({
        type: 'tabChange',
        tab: tabs.children.index(event.currentTarget),
      });
    }
  });

  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, pluginName)) {
        $.data(this, pluginName, new Tabs(this, options));
      }
    });
  };
})(jQuery);

jQuery(document).ready(function($) {
  $('.js-tabs').Tabs();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

这是我监听选项卡的 slider 插件:

(function($) {
  let pluginName = 'Slider';

  function Slider(element, options) {
    let settings = {};

    this.element = element;
    this.$element = $(this.element);
    this.settings = $.extend({}, settings, options);

    this.id = null;
    this.tabs = null;
    this.children = null;
    this.activeSlideIndex = 0;
    this.nbSlides = 0;

    this.init();
  }

  $.extend(Slider.prototype, {

    init: function() {
      this.id = this.$element.attr('id');
      this.children = this.$element.children();
      this.nbSlides = this.children.length;
      // Listeners
      // Click on slide
      this.children.on('click', {
        slider: this
      }, this.onSlideChange);
      // On slide change
      $(this).on('slideChange', {
        slider: this
      }, this.onSlideChange);
      $(this).on('change', this.update);

      // On Init, active the first tab
      if (this.children && this.nbSlides > 0) {
        $(this).trigger({
          type: 'slideChange',
          slide: this.children.first().index(),
        });
      }
      $(document).trigger({
        type: 'sliderLoaded',
        slider: this,
      });
    },
    update: function() {
      // if Slider has an associated Tabs
      if (this.tabs) {
        $(this.tabs).on('tabChange', {
          slider: this
        }, this.onTabChange);
      }
    },
    onSlideChange: function(event) {
      event.preventDefault();
      const slider = event.data.slider;
      const slide = event.slide;
      // Reset active classes
      slider.children.removeClass('is-active');
      slider.activeSlideIndex = slide ? slide : event.currentTarget;
      console.log(slider.activeSlideIndex);
      slider.children.eq(slider.activeSlideIndex).addClass('is-active');
    },
    // TABS
    onTabChange: function(event) {
      const slider = event.data.slider;
      const tabIndex = event.tab;
      if ($(slider.children).eq(tabIndex).length >= 0) {
        $(slider).trigger({
          type: 'slideChange',
          slide: tabIndex,
        });
      }
    }
  });

  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, pluginName)) {
        $.data(this, pluginName, new Slider(this, options));
      }
    });
  };
})(jQuery);

jQuery(document).ready(function($) {
  $('.js-slider').Slider();
});

// On Tabs loaded, insert it into slider
jQuery(document).on('tabLoaded', function(event) {
  const tabs = event.tabs;
  const sliderId = jQuery(tabs.element).data('slider-id');
  if (jQuery('#' + sliderId).first().data('Slider')) {
    const slider = jQuery('#' + sliderId).first().data('Slider');
    slider.tabs = tabs;
    slider.update();
  }
});

最佳答案

我遵循了 @Anton 的建议,我拆分了选项卡和 slider ,效果很好:)

  • 首先,我从插件文件中删除了插件的 inits。
  • 然后我将每个 inits 放入另一个我称为“app.js”的文件

我的 App.js 看起来像这样:

jQuery(document).ready(function ($) {
    let $sliders = $('.js-slider').Slider();
    let $tabs = $('.js-tabs').Tabs();

    $sliders.on('slideChanged', function (event) {
        const sliderId = $(this).attr('id');
        const slide = event.slide;
        $tabs.filter('[data-slider-id=' + sliderId + ']').data('Tabs').select(slide);
    });

    $tabs.on('tabChanged', function (event) {
        const sliderId = $(this).data('slider-id');
        const tab = event.tab;
        $sliders.filter('#' + sliderId).data('Slider').select(tab);
    });
});

我正在监听发送的每个事件,例如“slideChanged”或“tabChanged”,然后我通过匹配的 ID 获取正确的选项卡或 slider 实例。

这是我的选项卡代码:

(function($) {
  let pluginName = 'Tabs';

  function Tabs(element, options) {
    let settings = {};

    this.element = element;
    this.$element = $(this.element);
    this.settings = $.extend({}, settings, options);

    this.children = null;
    this.activeTabIndex = 0;
    this.nbTabs = 0;

    this.init();
  }

  $.extend(Tabs.prototype, {

    init: function() {
      this.children = this.$element.children();
      this.nbTabs = this.children.length;

      // Listeners
      this.children.on('click', {
        tabs: this
      }, this.onTabClick); // Click on a tab
      $(this).on('tabChanged', this.onTabClick);

      // On Init, active the first tab
      if (this.children && this.nbTabs > 0) {
        this.children.first().click();
      }
    },
    select: function(tab) {
      // Reset active classes
      this.children.removeClass('is-active');
      this.activeTabIndex = tab;
      this.children.eq(tab).addClass('is-active');
    },
    onTabClick: function(event) {
      event.preventDefault();
      const tabs = event.data.tabs;
      const tab = tabs.children.index(event.currentTarget);
      tabs.select(tab);
      // Launch changeTab
      $(tabs.element).trigger({
        type: 'tabChanged',
        tab: tab,
      });
    }
  });

  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, pluginName)) {
        $.data(this, pluginName, new Tabs(this, options));
      }
    });
  };
})(jQuery);

和 slider :

(function($) {
  let pluginName = 'Slider';

  function Slider(element, options) {
    let settings = {};

    this.element = element;
    this.$element = $(this.element);
    this.settings = $.extend({}, settings, options);

    this.id = null;
    this.tabs = null;
    this.children = null;
    this.activeSlideIndex = 0;
    this.nbSlides = 0;

    this.init();
  }

  $.extend(Slider.prototype, {

    init: function() {
      this.id = this.$element.attr('id');
      this.children = this.$element.children();
      this.nbSlides = this.children.length;
      // Listeners
      // Click on slide
      this.children.on('click', {
        slider: this
      }, this.onSlideClick);
      // On slide change
      $(this).on('slideChanged', this.onSlideClick);

      // On Init, active the first tab
      if (this.children && this.nbSlides > 0) {
        this.children.first().click();
      }
    },
    select: function(slide) {
      // Reset active classes
      this.children.removeClass('is-active');
      this.activeSlideIndex = slide;
      this.children.eq(this.activeSlideIndex).addClass('is-active');
    },
    onSlideClick: function(event) {
      event.preventDefault();
      const slider = event.data.slider;
      const slide = slider.children.index(event.currentTarget);
      slider.select(slide);
      // Launch changeTab
      $(slider.element).trigger({
        type: 'slideChanged',
        slide: slide,
      });
    },
  });

  $.fn[pluginName] = function(options) {
    return this.each(function() {
      if (!$.data(this, pluginName)) {
        $.data(this, pluginName, new Slider(this, options));
      }
    });
  };
})(jQuery);

关于javascript - 创建两个可以互相通信的 jQuery 插件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49068041/

相关文章:

javascript - d3.js linechart 不同线的不同插值

javascript - 如何重新启动绘图/动画 Chartist-js?

jquery - 基于类序列化&lt;input&gt;

javascript - 当输入文件为空时验证它

javascript - 优化jquery代码

java - 如何获取java编辑器源代码?

java - Jenkins 无法启动并清空插件目录

javascript - 函数在 jQuery 每个循环中间返回不正确的值

javascript - 我如何学习 JavaScript 编码模式

java - 列出所有可用的 ResourceBundle 文件