LESS:如何将一个 mixin 作为参数传递给另一个 mixin?

LESS: How can I pass a mixin as an argument to another mixin?

我有一些基本的 mixin,它们使用媒体查询应用一些规则

.on-small(@rules) {
  @media (@minWidthSmall) { @rules(); }
}

.on-medium(@rules) {
  @media (@minWidthMedium) { @rules(); }
}

// and .on-large, .on-x-large and so on

我正在尝试构建一个非常简单的基于 flex 的网格系统,我正在尝试将提到的 mixin 作为参数传递,这样我就可以拥有一个通用的 .make-column mixin。如下:

.make-col(@break-point-mixin, @span, @size) {
  flex: 1;
  box-sizing: border-box;


  /***********************************************************
  Is the following line possible in LESS somehow?
  ***********************************************************/
  @break-point-mixin({
    width: percentage(@span/@size);
    min-width: percentage(@span/@size);
  });
}

.grid-col-on-small(@span: 1, @size: 1) {
  .make-col(@break-point-mixin: .on-small, @span, @size);
}

.grid-col-on-medium(@span: 1, @size: 1) {
  .make-col(@break-point-mixin: .on-medium, @span, @size);
}

但不幸的是,将 @break-point-mixin 作为参数传递并从 .make-col 内部调用它会崩溃:

Unrecognised input. Possibly missing opening '('

不,您不能将 mixin 名称作为参数发送并以这种方式使用它。

相反,您可以执行类似下面的操作,其中直接从包装器混合中调用媒体查询混合,而不是 .make-col 混合。由于包装器 mixin 知道媒体查询 mixin 需要的变量,所以这不会导致任何问题。

.grid-col-on-small(@span: 1, @size: 1) {
  .make-col(@span, @size);
  .on-small({
    width: percentage(@span / @size);
    min-width: percentage(@span / @size);
  });
}

.grid-col-on-medium(@span: 1, @size: 1) {
  .make-col(@span, @size);
  .on-medium({
    width: percentage(@span / @size);
    min-width: percentage(@span / @size);
  });  
}

如果您担心重写上述 mixins 中的规则,那么您可以将它们设置为如下规则集并使用它。

@colRules: {
             width: percentage(@span / @size);
             min-width: percentage(@span / @size);
           };

.grid-col-on-small(@span: 1, @size: 1) {
  .make-col(@span, @size);
  .on-small(@colRules);
}

.grid-col-on-medium(@span: 1, @size: 1) {
  .make-col(@span, @size);
  .on-medium(@colRules);  
}

或者,您可以将 mixin 名称作为参数发送,并像下面这样使用守卫。由于我们在这里处理 break-points 并且应该不会有很多,这种方法应该会有所帮助并且可能会得到我的投票。

@colRules: {
             width: percentage(@span / @size);
             min-width: percentage(@span / @size);
           };

.make-col(@breakpoint, @span, @size) {
  flex: 1;
  box-sizing: border-box;
  & when (@breakpoint = s) {
    .on-small(@colRules); /* or you could replace this with that mixin's content also */
  }
  & when (@breakpoint = m) {
    .on-medium(@colRules);
  }
  /* and so on for the rest */
}

.grid-col-on-small(@span: 1, @size: 1) {
  .make-col(s, @span, @size);
}

.grid-col-on-medium(@span: 1, @size: 1) {
  .make-col(m, @span, @size);
}

在这种特殊情况下(与具有任意混合名称的一般情况不同)我会说你错过了 .on-small/.on-medium 这些 smallmedium 东西也不过是参数,因此不应该成为混合名称的一部分。考虑到这一点,您的示例变为:

.on(small, @rules) {
  @media (@minWidthSmall) {@rules();}
}

.on(medium, @rules) {
  @media (@minWidthMedium) {@rules();}
}

.make-col(@device, @span, @size) {
  flex: 1;
  box-sizing: border-box;
  .on(@device, {
    width: percentage(@span/@size);
    min-width: percentage(@span/@size);
  });
}

// usage:

.make-col(small, @span, @size);

你的 .grid-col-on-* mixin 也一样,它们只是一个:

.grid-col-on(@device, @span: 1, @size: 1) {
  .make-col(@device, @span, @size);
}

等等。

如果你真的想要一个 flexible/generic 网格 - 永远不要 将 device/breakpoint 名称硬编码到 mixin 或变量名称中(有关更多原理和示例,请参见 https://github.com/less/less.js/issues/2702).