创建两个可以相互通信的 jQuery 插件
Create two jQuery plugins that can talk to each other
我的脑袋现在一团糟。我想创建两个 jQuery 插件:
- 一个选项卡插件
- 滑块插件。
此插件必须相互通信,例如,如果我单击一个选项卡,此选项卡将激活相关滑块中的正确索引。
如果我单击幻灯片,这也会激活正确的选项卡。
我开始为此创建事件侦听器和触发器,当我的选项卡被单击时,一个事件 tabChanged
被触发,并且在我的滑块插件中我正在收听它。
但问题是,我的滑块可以在我的选项卡之前加载,所以听众没有正确附加...
这次我尝试在文档上触发另一个事件,称为 tabsLoaded
并等待该响应,它有效但开始有点混乱。
我想知道是否有人对此有更好的解决方案?
选项卡和滑块也可以独立工作,可能只有选项卡没有关联的滑块。
这是我的标签插件:
(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>
这是我的监听标签的滑块插件:
(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 的建议,拆分了选项卡和滑块,效果很好:)
- 首先,我从插件文件中删除了我的插件初始化。
- 然后我将每个 init 放入另一个我称为 "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 获得正确的选项卡或滑块实例。
这是我的标签代码:
(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);
和滑块:
(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);
我的脑袋现在一团糟。我想创建两个 jQuery 插件:
- 一个选项卡插件
- 滑块插件。
此插件必须相互通信,例如,如果我单击一个选项卡,此选项卡将激活相关滑块中的正确索引。 如果我单击幻灯片,这也会激活正确的选项卡。
我开始为此创建事件侦听器和触发器,当我的选项卡被单击时,一个事件 tabChanged
被触发,并且在我的滑块插件中我正在收听它。
但问题是,我的滑块可以在我的选项卡之前加载,所以听众没有正确附加...
这次我尝试在文档上触发另一个事件,称为 tabsLoaded
并等待该响应,它有效但开始有点混乱。
我想知道是否有人对此有更好的解决方案? 选项卡和滑块也可以独立工作,可能只有选项卡没有关联的滑块。
这是我的标签插件:
(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>
这是我的监听标签的滑块插件:
(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 的建议,拆分了选项卡和滑块,效果很好:)
- 首先,我从插件文件中删除了我的插件初始化。
- 然后我将每个 init 放入另一个我称为 "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 获得正确的选项卡或滑块实例。
这是我的标签代码:
(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);
和滑块:
(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);