我创建了一个简单的javascript类来包装slick carousel。
实例化此类的多个实例的最佳方法是什么?
我目前得到了以下内容,它搜索DOM并创建组件的新类实例(如果找到)。我怀疑我的项目会增长一点,而且这个根本就是'文件可能因为有点臃肿/混乱。有没有更好的方法来组织它?
我将为其他功能添加其他类,因此请尽早找到最佳方法。
main.js
import Carousel from '../app/assets/javascripts/carousel/Carousel';
var carouselElements = Array.from(document.getElementsByClassName('slick-media'));
if (carouselElements) {
carouselElements.map(function (element) {
new Carousel(element, true, {xs: 6, md: 6, lg: 6 });
});
}
Carousel.js
export default class Carousel {
constructor(element, variableWidth = false, breakpoint) {
this.element = element;
this.variableWidth = variableWidth;
this.breakpoint = breakpoint
this._init(element);
/* Bind methods */
this._init = this._init.bind(this);
}
_init() {
this._instantiateSlick(this.element);
}
_instantiateSlick(element) {
$(element).slick({
lazyLoad: 'ondemand',
slidesToScroll: 1,
adaptiveHeight: true,
useTransform: true,
/* Default over lg breakpoint */
slidesToShow: this.breakpoint.lg,
/* Allow slick to calculate widths */
variableWidth: this.variableWidth,
responsive: [
{
breakpoint: 1199,
settings: {
slidesToShow: this.breakpoint.lg,
slidesToScroll: 1,
infinite: true
}
},
{
breakpoint: 991,
settings: {
slidesToShow: this.breakpoint.md,
slidesToScroll: 1,
infinite: true
}
},
{
breakpoint: 480,
settings: {
slidesToShow: this.breakpoint.xs,
slidesToScroll: 1,
infinite: true
}
}]
});
}
}
答案 0 :(得分:2)
使用一个类似乎对我来说太过分了。您永远不会在以后访问创建的对象,因为您没有保留对它们的引用,因此它们的唯一目的似乎是执行一个立即操作:将slick
应用于具有某些预定义配置的元素。他们建造后立即变得无用。
其次,当在之后仍然有一个参数证明是必需的时,使用参数的默认值并不是很有用。因此,交换breakpoint
和variableWidth
的参数位置。
作为替代方案,我建议为此创建一个jQuery插件:
$.fn.simpleSlick = function (breakpoint, variableWidth = false) {
this.slick({
lazyLoad: 'ondemand',
slidesToScroll: 1,
adaptiveHeight: true,
useTransform: true,
/* Default over lg breakpoint */
slidesToShow: breakpoint.lg,
/* Allow slick to calculate widths */
variableWidth,
responsive: [{
breakpoint: 1199,
settings: {
slidesToShow: breakpoint.lg,
slidesToScroll: 1,
infinite: true
}
}, {
breakpoint: 991,
settings: {
slidesToShow: breakpoint.md,
slidesToScroll: 1,
infinite: true
}
}, {
breakpoint: 480,
settings: {
slidesToShow: breakpoint.xs,
slidesToScroll: 1,
infinite: true
}
}]
});
return this; // to allow chaining
};
假设slick
插件根据规则播放(即允许jQuery对象匹配多个元素),您实际使用它变得如此简单:
$('.slick-media').simpleSlick({xs: 6, md: 6, lg: 6 }, true);
如果一个类的使用应该作为给定,那么你仍然可以使用jQuery方式通过它们的class
属性来选择元素(因为你已经在slick
插件中使用了jQuery ):
$('.slick-media').each(function () {
new Carousel(this, true, {xs: 6, md: 6, lg: 6 });
});
(但同样,在不使用生成的对象的情况下应用new
会显示错误的设计)
如果您想稍后通过DOM元素访问这些Carousel对象,那么您可以考虑使用data
方法:
$('.slick-media').each(function () {
$(this).data('carousel', new Carousel(this, true, {xs: 6, md: 6, lg: 6 }));
});
对于给定的elem
元素,您可以按如下方式访问相应的Carousel
实例:
var carousel = $(elem).data('carousel'); // Get the Carousel instance
答案 1 :(得分:2)
您已经澄清了您的问题是关于您如何使用您的课程(例如main.js
中的代码):
它关于main.js文件,以及它实例化多个实例的方式。这种方法是最好的吗?
有几个尼特可以选择:
您正在使用map
创建一个用undefined
填充的数组,但从不使用。如果您不使用返回的数组,请不要使用map
;使用several other ways to loop over arrays and array-like structures中任意一项的forEach
。
不需要if
;类似getElementsByClassName
的方法总是返回NodeList
或HTMLCollection
(取决于方法),即使它是空的。
另外,它是否可以在一个大型项目中进行扩展,那里会有多个类,这个文件会变得非常难以理解?
我没有看到任何理由让它变得不可读。如果你想坚持getElementsByClassName
(因为它可以惊人地快;请注意它在IE8等过时的浏览器上不存在):
import Carousel from '../app/assets/javascripts/carousel/Carousel';
const forEach = Function.call.bind(Array.prototype.forEach);
const hookUpClass = className => {
forEach(document.getElementsByClassName(className), element => {
new Carousel(element, true, {xs: 6, md: 6, lg: 6 });
});
};
hookUpClass('slick-media');
hookUpClass('another-class');
hookUpClass('some-further-class');
请注意使用Array.prototype.forEach
为我们执行循环,因为它可以处理任何类似数组的事情。这适用于任何现代浏览器和IE9-IE11。
如果您不介意非常非常非常的一小部分开销,您可以使用querySelectorAll
(即使在IE8上也存在)来获取与所有你的课程,而不是分别处理每个班级:
import Carousel from '../app/assets/javascripts/carousel/Carousel';
document.querySelectorAll('.slick-media, .another-class, .some-further-class').forEach(element => {
new Carousel(element, true, {xs: 6, md: 6, lg: 6 });
});
我没有在Array.prototype.forEach
使用NodeList
,因为forEach
有自己的if (typeof NodeList !== "undefined" &&
NodeList.prototype &&
!NodeList.prototype.forEach) {
// Surprisingly, the standard `NodeList.prototype.forEach` is enumerable (as well as
// writable and configurable) so we can just assign rather than using `defineProperty`
NodeList.prototype.forEach = Array.prototype.forEach;
}
做同样的事情。如果你需要支持IE9-IE11,你会想要填充,这是微不足道的:
Array.prototype.forEach
当然,如果您愿意,可以像使用getElementsByClassName
一样使用import Carousel from '../app/assets/javascripts/carousel/Carousel';
for (const element of document.querySelectorAll('.slick-media, .another-class, .some-further-class')) {
new Carousel(element, true, {xs: 6, md: 6, lg: 6 });
}
。
在最新的Chrome和Firefox等尖端环境中,您可以这样做:
NodeList
...依赖于NodeList
可迭代。我上面没有做到这一点,因为在forEach
上填充迭代器比填充{{1}}更难,而不知道你正在使用什么转换器(如果你正在使用它)。 / p>
答案 2 :(得分:1)
您实际上可以将其缩短为:
Array.from(
document.getElementsByClassName('slick-media'),
node => new Carousel(node, true, {xs: 6, md: 6, lg: 6 })
);