Javascript类实例化

时间:2018-02-16 17:11:16

标签: javascript ecmascript-6 es6-class

我创建了一个简单的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
          }
        }]
    });
   }
}

3 个答案:

答案 0 :(得分:2)

使用一个类似乎对我来说太过分了。您永远不会在以后访问创建的对象,因为您没有保留对它们的引用,因此它们的唯一目的似乎是执行一个立即操作:将slick应用于具有某些预定义配置的元素。他们建造后立即变得无用。

其次,当之后仍然有一个参数证明是必需的时,使用参数的默认值并不是很有用。因此,交换breakpointvariableWidth的参数位置。

作为替代方案,我建议为此创建一个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文件,以及它实例化多个实例的方式。这种方法是最好的吗?

有几个尼特可以选择:

  1. 您正在使用map创建一个用undefined填充的数组,但从不使用。如果您不使用返回的数组,请不要使用map;使用several other ways to loop over arrays and array-like structures中任意一项的forEach

  2. 不需要if;类似getElementsByClassName的方法总是返回NodeListHTMLCollection(取决于方法),即使它是空的。

  3.   

    另外,它是否可以在一个大型项目中进行扩展,那里会有多个类,这个文件会变得非常难以理解?

    我没有看到任何理由让它变得不可读。如果你想坚持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 })
);