Less.js: 将选择器保存到变量

创建于 2017-04-20  ·  50评论  ·  资料来源: less/less.js

我们有这个解决方案:

// LESS
.selector {
    <strong i="6">@r</strong>: ~'.selector';

    &--mode {
        @{r}__block {
            prop: value;
         }
    }
}

// CSS
.selector--mode .selector__block {
  prop: value;
}

我建议添加一个功能:编写<strong i="9">@r</strong>: &;而不是<strong i="11">@r</strong>: ~".selector";来获取当前选择器并将其保存在任何变量中。

例子:

// LESS
.selector {
  <strong i="15">@r</strong>: &; // .selector
}

.selector {
  &__inner {
    <strong i="16">@r</strong>: &; // .selector__inner
  }
}

.selector {
  &--modification &__inner {
    <strong i="17">@r</strong>: &; // .selector--modification .selector__inner
  }
}
feature request medium priority needs decision research needed

所有50条评论

奇怪的是,我绝对确定这样的请求已经存在。 显然不是。
(虽然显然这个想法之前确实出现在许多票证中:#1174,https://github.com/less/less.js/issues/1075#issuecomment-16891103 等)
所以我猜就这样吧。


顺便说一句,以防万一(并收集一些用例以考虑可能的 impl./syntax 冲突):
你打算如何使用它? 我怀疑在许多情况下,由于惰性评估,它不会像您期望的那样工作。 例如:

a {
    <strong i="11">@r</strong>: &;
    b {
        something: @r;
    }
}

将导致:

a b {
    something: a b; // not a!
}

因为@r值实际上是在a b内部评估的(即它的使用位置 -不是在您定义它的地方)。
(所以我怀疑某些用例实际上可能需要一些其他的语言构造来实现这一点——而不仅仅是一个变量。许多其他相关的用例之前被认为是 #1075 的主题)。

在许多情况下,由于惰性评估,它不会像您期望的那样工作
我怀疑某些用例实际上可能需要一些其他的语言构造——而不仅仅是一个变量

您需要这种特殊的语言结构来在定义时捕获选择器上下文,而不是在它被分配给它的变量的评估中调用它的时候。 评估应该只发出在定义站点捕获的上下文。

与通过闭包查找变量没有太大区别,但是是的; 它将需要一个特殊的语言结构而不是一个函数。

@rjgotten

是的,我想我们之前一直在讨论一些selector伪函数(伪函数,因为常规函数解析无论如何都无法处理所有选择器特定的组合器)然后因为它是伪函数(即像Url这样的专用类型)
所以像<strong i="10">@foo</strong>: selector(&);这样的东西我猜可以做一个伎俩。 虽然接下来出现了一个小问题:

a {
    <strong i="13">@var</strong>: selector(x, #y & .z);

    b {
        @{var} { // ? is it regular & or "saved-context-&" ?
            // ...
        }
    }
}

所以它可能需要&操作符/关键字。 (或者可能只是一个专用的伪函数,例如current-selector() ... 嗯,现在让我想到编写一个通用的PseudoFunction类型来不污染每个小东西的 API,哦哦!:)

我知道在语言中添加新东西时通常会犹豫不决,但选择符说明符可能会很方便。 我喜欢| ,尽管它是CSS @namespace选择器语法的一部分。 但是,似乎不允许| _start_ 选择器,因此它不应该发生冲突。 我使用它是因为它让我想起了 Math 的“绝对值”,这似乎有点恰当,而且因为它很简单。 只是一个激发对话的想法。

a {
  <strong i="10">@var</strong>: |x, #y & .z|; // starting w/ `|` means selector, in current context, ended w/ another `|`
  b {
    @{var} {
      //...
    }
  }
}

(事实上​​,它可以用来指定 _any_ var 应该被立即处理和存储,或者其他什么?但这感觉就像是 _way_ 范围过大。)

它是常规的&还是saved-context-&

我想说应该在站点上捕获选择器上下文,调用selector()伪函数,并且&应该在 _that_ 上下文中进行评估,最终结果应该分配给这个新类型Selector树节点。

当包含Selector类型树节点的 _any_ 变量被插入到选择器中时,例如在示例中使用@{var}的情况,生成的选择器应该以相同的方式构建当&内插器出现在选择器中时,即; 不要从一个嵌套级别开始加入选择器并为其添加前缀。

这背后的原因是两者都是捕获的选择器: selector()是用户捕获的选择器,而&是始终存在且捕获的“父”选择器。

然后,如果用户需要将捕获的Selector节点与 _current_ 选择器上下文一起插入,他们可以明确说明。 例如& @{var} { ... }

在结束

a {
    <strong i="24">@var</strong>: selector(x, #y & .z);

    b {
        @{var} { ... }
    }
}

应该产生

x, #y a .z { ... }

然而

a {
    <strong i="31">@var</strong>: selector(x, #y & .z);

    b {
        & @{var} { ... }
    }
}

应该产生

a b x,
a b #y a .z { ... }

嗯, @{var} vs. & @{var}看起来很人为,这不是这些东西在 Less 中的工作方式。 ... { & div ...... { div ...总是相等的语句。 另外,甚至不计算这个,如果我需要a b x, #y a b .zx, #y * .z定义在别处,我该怎么办?

我不喜欢选择器的类似函数的构造。 不过,我支持能够引用、修改或传输(分配给变量和重用)继承的选择器。

不过,只是为了确保其中有多少是 #1075(针对父选择器)的变体,或者可能与https://github.com/less/less-meta/issues/16#issuecomment -292679320(分配变量的单个选择器)? 或者这与别名混入不同,因为这是一个选择器列表而不是单个评估的选择器(或混合),并且输出是选择器列表而不是评估的规则集? 我假设这个功能是不同的; 我只是想确保所有这些都朝着同一个方向发展。

@马修院长
它确实是关于捕获实际的选择器列表,而不是关于捕获评估的规则集,并输出所述列表以供进一步使用。

可以想象一个像extract(list,index)这样的函数被更新,以便能够从选择器列表中提取选择器组件和类似的增强功能以​​简化选择器的使用,以便用户可以轻松地以有趣的方式操作它们。 例如,对于遵循某些命名方案(如 BEM)的组件。

例如给定一个 mixin

.my-bem-component(<strong i="10">@a</strong>, @b) {
  // Component will only ever be constructed on the first selector in
  // a list, for simplicity.
  <strong i="11">@selectors</strong> : selector(&);
  <strong i="12">@selector</strong>  : extract(<strong i="13">@selectors</strong>, 1);

  // Generate a clean block name, cleared of modifiers.
  // Grabs e.g. "bar" from ".foo > .bar--baz"
  @block-name : replace(<strong i="14">@selector</strong>, "\.([^\.\s]+)--\S+$", "$1" );

  // Generate the modifier name and generate different CSS for
  // BEM classes that have one.
  // Grabs e.g. "baz" in ".foo > .bar--baz"
  @mod-name : replace(<strong i="15">@selector</strong>, "\.+--(\S+)$", "$1" );

  .generate-block();
  // When @mod-name matches <strong i="16">@selector</strong>, no replacement has
  // occured and we are infact in the situation where we have no
  // BEM modifier and generate the 'base' component.
  .generate-block() when (@mod-name = "@{selector}") {
    @{selector} {
      prop-a : @a;
    }
    @{selector}__element {
      prop-b : @b;
    }
  }

  .generate-block() when (default()) {
    @{selector} {
      prop-a : @a;
    }
    @{selector} > .@{block}__element {
      prop-b : @b;
    }
  }
}

以下少

.block {
  .my-bem-component(foo, bar);
}
.block--caps {
  .my-bem-component(FOO, BAR);
}

生成 CSS

.block {
  prop-a : foo;
}
.block__element {
 prop-b : bar;
}
.block--caps {
  prop-a : FOO;
}
.block--caps > .block__element {
  prop-b : BAR;
}

Afaik,Sass 已经使用了很长时间,并且有许多非常巧妙地使用这种技术的例子。 在我的示例中的代码工厂中,或用于其他目的。

至于:

可能与less/less-meta#16(注释)冲突(将单个选择器分配给变量)

我个人认为以下行为:
“琐碎”选择器值(例如.mixin.ns.mixin#foo .barbaz等,幸运的是这涵盖了任何可以使用/定义为 mixin/function 的内容)被直接分配给一个变量(或作为参数函数传递)。 即我们实际上已经有了这个:

<strong i="15">@var</strong>: .ns.mixin; // OK, its just Anonymous value (representing an arbitrary identifier) 
function(.mixin); // error: TODO 

^这(基本上)与选择器完全无关- 只有当我们尝试使用@var(...)调用/评估它们时,这些值才会(试图)转换为选择器格式(以查找混合)或@var[...]语句
(通常,逻辑约定是忘记 mixin 标识符是(内部表示为)选择器,但始终将它们视为仅带有点或#前缀的标识符,以及诸如.ns > .mixin类的标识符最终因为多余和无用而逐渐消失:)

由于语法/解析器的歧义,复杂或“真实”选择器需要selector伪函数。 即像这样的事情:

  • <strong i="29">@var</strong>:foo>bar <- 选择器和(可能)一个逻辑表达式
  • <strong i="32">@var</strong>:.1+.2; <- 算术表达式有效的 Less选择器
    (等等,只需回忆所有特定的选择器符号 - 几乎每个符号都与值解析上下文中的某些内容发生冲突,当上述值可能作为参数传递给函数/mixin 时,这会更加戏剧化,例如以下是不可能的支持无selector()
    less: some-function(abc, selector(#foo .is :not(> bar)[baz="qux"], abc), selector(bla), 42); // ^ remove `selector()` and try to parse

我不喜欢选择器的类似函数的构造。

总之, selector伪函数只是为了一劳永逸地消除任何当前和潜在的语法和语义冲突所必需的。 所以我怀疑我们在这里真的有太多的选择(值和选择器解析上下文必须以某种方式分开)。


(以上所有并不意味着selector()返回的值不能用作可调用实体,例如@var() ,它可能 - 但这只是不必要/无用,因此几乎不值得打扰)。

@rjgotten

可以想象一个像extract(list,index)这样的函数被更新为能够提取选择器

当然,我们可以调整函数来处理字符串,假设这样的字符串可能包含一些选择器,但这意味着每个这样的函数(不仅仅是extract )都必须更新/调整/修改。 相反的方法会更有效/负担更轻。 即它要么是一个专用的selector-string->values转换函数,要么甚至直接通过selector返回正确的节点结构(在任何一种情况下,最棘手的部分是如何在每次使用时打包/解包选择器组合器-case 可能更喜欢不同的表示)。

(请注意,选择器插值功能本身最终仍然必须将@{var}转换为正确的格式,因此该 var 的值采用什么格式并不重要 - 无论是字符串,匿名还是其他节点结构 - 大多数转换技巧保持不变)。

@block-name : replace(<strong i="17">@selector</strong>, "\.([^\.\s]+)--\S+$", "$1" );

老实说,这看起来像是“内联 JavaScript 和类似 LessHat 的黑客”的轮回,无法禁止但会积极宣传。
(不算这个例子很不幸<- 计算行数)我宁愿建议一些less-plugin-bem-selectors东西(在那里你可以简单地拥有一个get-block-name函数,顺便说一句。即使没有&功能)而不是这种丑陋的正则表达式(“使用 CSS 预处理器作为任意文本处理器”的方法最终会严重松散到类似于 PostCSS 的东西)。

回到& vs. context-saving-& ,到目前为止,恐怕我没有比函数的专用标志更好的想法,例如selector(..., lazy or not) ,甚至两个分开的功能。 或者使用other-than-&-keyword (例如 )。 只是看不到任何安全的方法来自动解决评估点歧义。

我宁愿建议一些less-plugin-bem-selectors东西

绝对地。 基于正则表达式的提取只是提供一个不涉及自定义函数的示例。 ;)

我不喜欢选择器的类似函数的构造。

另外,如果您只指它的外观……当然也可能是其他结构,例如⁞#foo:not(.bar)⁞ ,但您知道我们已经用完了免费符号。 所以伪函数语法只是建议,因为我们已经有了url这样的概念(因此不需要考虑新概念可能或将要破坏的东西)。

现在,有趣的部分。

我创建了一个current-selector函数的快速而肮脏的插件实现(只是为了看看它会变得多么臃肿,当然希望它因为 var 延迟评估而不会很有用),并且知道什么? 这个基本示例:

div {
    <strong i="9">@x</strong>: current-selector();
    span {
        r: @x; // -> div
    }
}

结果r: div :)
不知道究竟是哪一段编译器代码处理了这种特殊行为,但这里有更高级的例子来说明这个魔法:

div {
    <strong i="15">@x</strong>: current-selector();     // [1]
    <strong i="16">@y</strong>: current-selector() @v;  // [2]
    <strong i="17">@z</strong>: current-selector(@v);   // [3]
    <strong i="18">@v</strong>: whatever;
    span {
        1: @x; // div
        2: @y; // div span
        3: @z; // div span
        4: current-selector();  // [4] div span
    }
}

只有[2][3]语句被调用两次(即实际上是惰性求值的),而[1]则不是(显然是因为该值不包含任何变量,虽然再一次,我不知道这是故意的还是只是某些缓存的副作用,或者它可能是我代码中的一个幸运错误 - 例如,这一行可能会触发这种缓存的副作用 - 但不清楚为什么它会受到额外变量的影响 - 即需要更多的研究)。


也就是说,基于插件的context-saving-&似乎是可能的(当然,除了<strong i="29">@var</strong>: &您将使用类似<strong i="31">@var</strong>: current-selector() )虽然该函数不应该有任何参数,否则它会被延迟评估(如果传入一个变量) - 这很可悲,因为我最初计划它有四个 :)。
相当滥用,但可以作为一种解决方法/polyfill。 一个更真实的例子也可以正常工作:

div#zoo {
    <strong i="35">@x</strong>: current-selector();
    span {
        <strong i="36">@y</strong>: replace(<strong i="37">@x</strong>, div, body);
        r: @y; // OK, body#zoo
        @{y} { 
        // ^ not very useful this way (except maybe bem stuff) since you can't remove div
            color: red;
        }
    }
}

即后续的变量赋值/函数调用不影响初始变量的评估点。

@七阶段最大
爱它。

即使当存在参数参数时,延迟评估当前会在工作中抛出一个扳手,_that_ 大概是可以为“真实”实现解决的问题。

另外,如果你只是指它的外观……当然也可以是其他结构,例如⁞# foo:not (.bar)⁞,但你知道我们已经用完了免费符号。

很公平。 就使用而言,我还没有真正考虑过这个问题,也没有更好的想法。 我想这似乎有什么特别之处,但也许没有。 我知道在某个时候有关于$() ,但我们最终挪用了$ 。 顺便说一句,不是selectors()而不是selector()吗? 它不能(如& )包含任意数量的选择器吗?

似乎selector(&)current-selector()更有意义。 即:“从 X 对象创建一个选择器列表,无论是&还是字符串”。 无论最终的语法是什么,它似乎都以&作为参数。

似乎selector(&)current-selector()更有意义

这些是不同的东西。 current-selector只是&的函数变体(因为解析器不支持后者)。 而selector(...)是解析器支持任意选择器(包括& )的补丁。


至于selectors - 嗯,确实如此。 但由于它是单个选择器用例的 99%,我想复数形式对大多数用户来说听起来不那么明显(在大多数情况下,他们通常将h1, h2, h3 {}称为选择器并继续谈论较少的父选择器(甚至如果是选择S):)所以何必呢?

喔好吧。

@马修院长
除了 CSS 规范作者之外,复数和单数形式几乎可以互换。 事实上,对于包括规范作者

非常好笑; 复数术语“选择器”甚至不是指定逗号分隔集的官方方式。 我相信复数形式的严格正确的术语是 _selector list_。

所以你可以看出这个模棱两可的参考是多么的根深蒂固。

我相信复数形式的严格正确的术语是选择器列表。

是的,我昨天也搜索了 w3c,它是“选择器组”、“选择器列表”等,没有什么比“选择器是由组合子分隔的一个或多个简单选择器序列的链”更奇怪的了有 :) 只是“选择器”形式主要用于描述“选择器类型”的东西。

“选择器是由组合子分隔的一个或多个简单选择器序列的链”

对于任何认为可能指的是逗号分隔列表的人来说:事实并非如此。 该引用的完整形式应该是:“_complex_selector 是由组合子分隔的一个或多个简单选择器序列的链。”

CSS 规范还有另一个问题,即“选择器”的广义形式主要用于指代规范正式称为 _complex 选择器_ 的东西。 复杂选择器是简单的选择器,例如tag#id ; .class ; [attr] ; 等,通过组合器链接,例如>+ ; ~

ul > li这样的东西被称为复杂选择器。


警告以下将是一个咆哮:

遗憾的是,CSS 规范是一堆不一致和命名不当的术语。 你走得越远,它逐渐变得越糟。 大量 CSS3 模块不断引用 CSS 2.1 模块或新的 CSS3 模块是通过逐字复制旧的 CSS 2.1 文档来指定的,这无济于事。 然而,选择器的规范和视觉格式模型是最糟糕的。 如此多模棱两可、发音相似或名称简单的术语。

以远比ul > li重要的东西为例,例如[*|attr^="value" i] 。 后者在技术上被归类为简单的选择器。 (对真的。)

几年前的某个时候,我也不得不尝试向我的一位更注重设计的同事解释后一种视觉格式模型规范的部分内容。 我认为一些保险丝实际上是在我们的大脑中_both_ 熔断了,而我们浏览了处理线盒概念的段落,这甚至不是其中最糟糕的部分。 (如果您对自己的理智没有什么价值,请尝试进入神奇的 la-la-land,即表格格式化模型。)

开源项目文档的多种乐趣...

以远比ul > li重要的东西为例,例如[*|attr^="value" i] 。 后者在技术上被归类为简单的选择器

这对我来说实际上很有意义,哈哈,只是因为它不使用组合器。 它精确地遵循定义。 仅仅因为它使用了很多符号并不会使它变得更“复杂”。 ul > li很复杂,因为它涉及两组查询,即查询与li匹配的所有元素,然后从每个元素向上遍历树以确定哪些元素包含在ul 。 后者只测试单个元素一次。 这是一个查询,所以它是一个简单的选择器。

复数术语“选择器”甚至不是指定逗号分隔集的官方方式。 我相信复数形式的严格正确的术语是选择器列表。

对,你是对的。 “选择器”实际上只是允许您选择元素的定义位,但ul > li > .title是“选择器”单数。 所以我猜selector()实际上可能在语义上更接近。

@七阶段最大

刚刚遇到了 quick-n-dirty 插件功能的另一个小问题:它不能正确处理来自命名空间的 mixin 的访问。 命名空间是一个常规的Ruleset类型框架,因此它们的名称被添加到选择器中。

一个真正的实现可能也应该涵盖这种情况。


[编辑]
使其工作的技巧是检查函数上下文堆栈上的帧之一是否为MixinDefinition ,如果是_is_,则跳过该堆栈上的下一个x帧,其中x等于MixinDefinition栈上的帧数。

(基本上;当MixinCall执行MixinDefinition时,这会跳过添加到堆栈中的“闭包”帧。)

删除了“陈旧”标签。 这仍然是一个值得探索的好问题。

也许current-selector()还不错。 虽然,要清楚,它实际上是current-selectors() 。 但这仍然有点冗长。 我想如果我们能想到一个更简洁的“捕获&”的函数名称,我会更赞成。

“捕获&”的函数名称更简洁。

只需将其命名为&() 。 毕竟,它在概念上只不过是&内容的吸气剂。
例如

.rule {
  <strong i="11">@selectors</strong> : &();
}

🤔
是的,应该没问题。 有异议吗?

我将尝试总结一下,看看我是否理解提议的功能:

新函数&()返回&将在当前上下文中输出的内容,允许这样做。

.component { // I only write "component" once!  Much concise, such DRY!
  <strong i="9">@this</strong>: &();

  /* base styles */

  &_child {
    /* styles for the child */
  }

  &-variant { // component-variant styles all together, and inside the `.component` block
    /* nothing too schmancy so far */
    @{this}_child {
      /* IT'S MAGIC! */
    }
  }
}

这一切都会输出这个。

.component {
  /* base styles */
}
.component_child {
  /* styles for the child */
}
.component-variant {
  /* nothing too schmancy so far */
}
.component-variant .component_child {
  /* IT'S MAGIC! */
}

因为那太棒了,我喜欢它。

考虑更多,我认为对我来说最引人注目的(在第一次通过之后;如果我太疯狂,请阻止我)是具有标准化组件“块”(规则集)样式的可能性。 基本上,我几乎希望函数不是保存一个简单的选择器字符串值,而是映射到 _" & ,但在范围内,变量定义在 "_ 中,这将允许这种创作风格对于一个组件(我称之为Behavior A ):

.component{ <strong i="8">@this</strong>:&();
  /* default styles */
  @{this}_child {
  // ↑ The crucial difference: `@{this}` here behaves _like `&`_, **NOT** like `.component`
    /* child default styles */
  }
}

然后我可以说“到处使用@this而不是& ”。

我唯一关心的是翻转案例(我将其称为Behavior B ),但我想不出一个令人信服的案例,我想要这种行为。 那就是我不明白为什么有人会想要这样做。

.foo { <strong i="16">@and</strong>: &();
  @{and} {
    /*stuff meant to live under selector `.foo.foo` */
  }
}

因为目前实现这一目标的方法_更_更简洁(并且可读性也更高,一旦&在您的词汇表中清晰明了)。

.foo {
  && {
    /*stuff meant to live under selector `.foo.foo` */
  }
}

行为 B 优于行为 A 是否有令人信服的案例(除了难以实施)?

这只是我认为应该在工作开始之前回答的问题之一。


TL;DR:我的投票是&()是动态的,这意味着本质上是 _" & ,但好像嵌套在这里而不是更深的"_,而不是返回静态 _"的值& 。”_

@calvinjuarez你的例子有点令人困惑,因为你没有写出预期的输出,所以它们看起来有点在理论领域,但基本上:

.component{
  <strong i="7">@this</strong>: &();  // <strong i="8">@this</strong> is now assigned the value of `.component`
  @{this}_child { a: b; } // this variable, when evaluated, forms the selector .component_child
}
// therefore this output is:
.component .component_child {
  a: b;
}

本质上的意思是“&,但好像嵌套在这里而不是更深”,而不是返回静态的“现在 & 的值”。

我真的不明白这是什么意思。

思考这个问题的另一种方式。 这:

.component {
  <strong i="6">@this</strong>: &()
}

相当于写:

.component {
  <strong i="10">@this</strong>: .component;
}

@马修院长

是的。 但是从 mixin 的角度考虑一下, &()将获取 mixin 调用者的选择器上下文。

它支持编写基于 mixin 的组件,其中作者自己可以以自然的方式自由决定类名的根。 例如给定

.my-button {
  #buttons.base();
  #buttons.size( ... );
  #buttons.inset-icon-support( left right );
}

.my-button--wide {
  #buttons.size( ... )
}

.my-button--condensed {
  #buttons.size( ... )
}

那里使用的 mixins 可以通过&()读取类并将其适当地处理到它们的输出中。 例如,为第二个和第三个规则捕获的选择器可以分解 BEM 语法以获得基本块类,该类可用于为嵌套元素选择器生成覆盖。

那是; 它可用于生成像.my-button--wide > .my-button__text这样的选择器,而无需传入任何选择器名称作为参数。 仅来自被调用方选择器上下文。


像这样的基于 Mixin 的 _component factory_ 避免了使用样式框架时遇到的许多要么全有要么全无的问题。 它们允许您注册框架,但可以精细地选择要实际合并的组件以及名称。

@rjgotten

那里使用的 mixin 可以通过 &() 读取类并将其适当地处理到它们的输出中。 例如,为第二个和第三个规则捕获的选择器可以分解 BEM 语法以获得基本块类,该类可用于为嵌套元素选择器生成覆盖。

是的,我明白了。 它可能在 mixin 中最有用。 我肯定会使用直接选择器名称获得&()的效用。 我的观点只是试图澄清给定示例中&()的值。

更进一步,我认为这是一个很好的句法解决方案,如果有人想接受它,我个人会为推进&()实现给予 👍。

@马修院长

您的示例有些令人困惑,因为您没有编写预期的输出

哎呀,抱歉。 我会正确地重述它。 如果这里的 Less 编译成下面的 CSS,我觉得&()会是一个更强大的功能。

.component { <strong i="10">@this</strong>:&();
  /* default styles */
  @{this}_child {
  // ↑ The crucial difference: `@{this}` here behaves _like `&`_, **NOT** like `.component`
  // (since it's in the same rule block and scope level).
    /* child default styles */
  }
}
.component {
  /* default styles */
}
.component_child {
  /* child default styles */
}

如果<strong i="15">@this</strong>:&();在这种情况下表现得就像<strong i="17">@this</strong>:.component; ,我们将把这个特性降级到 mixin 中的 _only_ 实用程序,但我认为它可以提供更多。

本质上的意思是“&,但好像嵌套在这里而不是更深”,而不是返回静态的“现在 & 的值”。

我真的不明白这是什么意思。

这意味着我认为.thing{ & {} }.thing{ <strong i="11">@amp</strong>:&(); @{amp} {} }应该产生相同的输出。

这意味着,更实际地,您不必编写 mixin 来执行简单的 BEM,而是可以内联定义它。 回到我以前的例子之一:

_component.less_

.component { // I only write "component" once!  Much concise, such DRY!
  <strong i="16">@this</strong>: &();

  /* base styles */

  @{this}_child {
    /* styles for the child */
  }

  @{this}-variant { // component-variant styles all together, and inside the `.component` block
    /* nothing too schmancy so far */
    @{this}_child {
      /* IT'S MAGIC! */
    }
  }
}

↓↓↓

_component.css_

.component {
  /* base styles */
}
.component_child {
  /* styles for the child */
}
.component-variant {
  /* nothing too schmancy so far */
}
.component-variant .component_child {
  /* IT'S MAGIC! */
}

好处:您不必询问您的团队他们的意思是&还是@{this} 。 您只需说“只需在任何地方使用@{this} ”。

它实际上也会使组件工厂 mixin 定义在内部更加一致。

_hypothetical-button-mixin.less_

#button () {
  .size(large) { <strong i="7">@button</strong>: &();
    @{button} { // same scope, so it behaves _exactly_ like `&`.
      font-size: 1.8rem;
    }
    @{button}-primary { // same scope, so it behaves _exactly_ like `&`.
      border-width: 5px;
      @{button}_icon { // nested scope, behaves like the parent selector at the mixin call (.btn).
        height: 1.8rem;
        width:  1.8rem;
      }
    }
  }
}
// ...

_hypothetical-styles.less_

.btn {
  #button.size(large);
}

_hypothetical-styles.css_

.btn {
  font-size: 1.8rem;
}
.btn-primary {
  border-width: 5px;
}
.btn-primary .btn_icon {
  height: 1.8rem;
  width:  1.8rem;
}

这意味着我认为 .thing{ & {} } 和 .thing{ @amp :&(); @{amp} {} } 应该产生相同的输出。

是的,我认为我们在说同样的事情,但让我用这个例子来确认。 这就是我如何看待此功能与就地&

.mixin() {
  <strong i="10">@this</strong>: &();
  .a {
    .b @{this} { c: d; }
  }
}
.component {
  .mixin();
}

// outputs:
.component .a .b .component {
  c: d;
}

然而:

.mixin() {
  .a {
    .b & { c: d; }
  }
}

会产生:

.b .component .a {
  c: d;
}

@calvinjuarez我想我很困惑,因为我认为没有人提出与您的示例不同的建议。 &()本质上就像在那个位置评估this.selectors.toCSS()不是真的,但只是为了说明......实际上这可能是最快的方法)。 然后将该字符串插入其他地方以作为选择器重新评估。

@马修院长
如果它将选择器列表公开为实际的选择器列表,包括基于所有列表成员扩展选择器的特殊行为,它实际上会更棒。

有例如

.a, .b {
  <strong i="8">@this</strong> : &();

  @{this} {
    c : d;  
  }
}

输出

.a .a,
.a .b,
.b. .a,
.a .b {
  c : d
}

就像原生的&一样。

是的,这正是它会做的。 在 3.5 中,选择器中评估的任何变量都会导致整个选择器列表被重新解析为新的选择器列表。 所以是的,这会按预期工作。 由于我最近做了一些 PR,这实际上很容易。

在2018年7月7日,在上午10:34,rjgotten [email protected]写道:

@马修院长
如果它将选择器列表公开为实际的选择器列表,包括基于所有列表成员扩展选择器的特殊行为,那实际上会更棒。

有例如

.a, .b {
@this : &();

@{这} {
c : d;
}
}
输出

.a .a,
.a.b,
.b. 。一个,
.a .b {
丙:丁
}
就像本机 & 一样。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看,或将线程静音。

.component{
 <strong i="6">@this</strong>: &();  // <strong i="7">@this</strong> is now assigned the value of `.component`
 @{this}_child { a: b; } // this variable, when evaluated, forms the selector .component_child
}
// therefore this output is:
.component .component_child {
 a: b;
}

额外的.component是我反对的。 我建议它应该像这样工作:

less .component{ <strong i="12">@this</strong>: &(); // <strong i="13">@this</strong> is now assigned the value of `.component < &` @{this}_child { a: b; } // this variable evaluates like `&_child` } // therefore this output is: .component_child { // < Note: `.component_child` !== `.component .component_child` a: b; }

不过,该功能似乎朝着不同的方向发展。 只是想澄清一下我的立场。

我建议它应该像这样工作:

即,如果选择器中有一个替代标记,它是一个 _selector list_ 而不是一个普通的 _string_,那么替代标记的作用与指定了&并且它_disables_ 由嵌套产生的正常选择器链相同。

我认为,如果&()输出一个节点类型,使其可识别为实际的选择器列表,那么这种行为将相对容易实现。

事实上,如果要输出专用的节点类型,这也可能有助于稍后创建插件函数来_manipulate_ 捕获的选择器列表。

对我来说,这听起来像是让 &() 一次做太多的工作。 如果您希望它将选择器保存到变量中,那是一回事,但是让该变量禁用选择器链接,因为它的 _content_ 在语法中是不清楚的。 该变量可以来自任何地方(例如从 mixin 传递),并且选择器列表可以通过简单的变量赋值生成。 也就是说,根据变量的使用情况,并不清楚会根据变量的内容发生不同的链接行为。

我想如果你想禁用链接,你必须指定你想用另一个值替换隐式 & ,比如(原谅格式,我在手机上) -

。零件 {
@var : &();
&(@var)_child {} // 或一些类似的“& 替换”语法
}

所以我明白为什么结果是可取的,但 IMO 我们不能仅仅根据选择器列表的来源“魔术切换”变量合并行为。 这需要两个不同的功能。

哦...我真的很喜欢&(...)东西...

哈,真的吗? 您不认为&() (从 & 捕获选择器)和&(@arg) (用选择器替换 &)的语义混淆?

您可能要考虑不混合它们,因为有人可能想用空选择器替换&以便基本上丢弃它。 (将一个孩子放在根部。)虽然我猜它可能是&(“”) .child?

我不知道,它值得一些思考/考虑。

此外,正如“父选择器应该有目标”线程中所述,有一些用例可以替换继承选择器的特定部分(或全部),因此考虑到这一点,我认为这些应该作为两个单独的问题进行跟踪。 这个问题应该只是关于捕获 &

为了结束这个圈子,这里是我提到用类似函数的构造就地更改&的地方。 - https://github.com/less/less.js/issues/1075#issuecomment -397697714

所以,我更喜欢关于“如何/是否改变&继承”的讨论留在父选择器线程中,而这个线程是关于<strong i="9">@var</strong>: &()是否适合捕获 in - 将&选择器放置到变量中。 尽管有其他线程,但在我看来,这似乎仍然可以。 我不确定是否有机会同时做到这两点。

我正在尝试这样做

.html, .css, .js, .php, .mysql, .jquery, .txt, .java {
    <strong i="6">@html</strong>: '\f2d0';
    <strong i="7">@css</strong>: '\f034';
    <strong i="8">@js</strong>: '\f121';
    <strong i="9">@php</strong>: '\f120';
    <strong i="10">@mysql</strong>: '\f1c0';
    <strong i="11">@jquery</strong>: '\f78c';
    <strong i="12">@java</strong>: '\f11b';
    <strong i="13">@txt</strong>: '\f15c';
    &:before {
        content+_: @&;
    }
}

但这在实施之前是行不通的

此页面是否有帮助?
0 / 5 - 0 等级