组件模板里可以直接写样式么
by Jake Wiesler
杰克·威斯勒(Jake Wiesler)
如何在没有模板文字的情况下使用样式化组件 (How you can use styled-components without template literals)
If you’ve used styled-components
in the past, you’ve probably seen the default (according to the documentation) way of declaring a component using the styled
API:
如果您过去使用过styled-components
,则可能已经看到了使用styled
API声明组件的默认方式(根据文档):
import styled from 'styled-components'
const Button = styled.button` background: palevioletred; color: #fff;`
Nothing shocking here. The documentation uses this pattern, and if you view any material on styled-components
, you’ve probably seen the exact same thing.
这里没有什么令人震惊的。 文档使用这种模式,如果您查看styled-components
上styled-components
任何材料,您可能已经看到了完全一样的东西。
Well, in the past few weeks I’ve seen a different pattern in a few libraries utilizing styled-components
, but I haven’t seen much information about it. Here it is:
好吧,在过去的几周里,我在一些使用styled-components
库中看到了一种不同的模式,但是我没有看到太多有关它的信息。 这里是:
const Button = styled('button')([], 'background: palevioletred', 'color: #fff')
This is interesting, and I’d like to explore it.
这很有趣,我想探索一下。
它是如何工作的? (How does it work?)
If you read Max Stoiber’s post The magic behind styled-components, he goes into some detail about the inner workings of his popular CSS library. The styled
API of styled-components
relies on tagged template literals, and this is probably the way you will see most people using it.
如果您阅读Max Stoiber的文章“样式化组件背后的魔力” ,那么他将详细介绍他流行CSS库的内部工作原理。 styled-components
的styled
API依赖于标记的模板文字,这可能是您看到大多数人使用它的方式。
But, it’s not the only way to declare components using the styled
API. This is the key idea behind this post, yet it may seem unclear right now. So, to answer the question, how does it work?, we first need to dive a bit further into tagged template literals.
但是,这不是使用styled
API声明组件的唯一方法。 这是这篇文章背后的关键思想,但现在似乎还不清楚。 那么,要回答这个问题, 它是如何工作的? ,我们首先需要进一步研究标记的模板文字。
标记的模板文字 (Tagged template literals)
Let’s make an important distinction regarding template literals vs tagged template literals. What is the difference?
让我们对模板文字与标记的模板文字进行重要区分。 有什么区别?
Template literals are, according to Mozilla:
根据Mozilla, 模板文字是:
“string literals allowing embedded expressions.”
“允许嵌入表达式的字符串文字。”
These strings can be multi-line:
这些字符串可以是多行:
const multiLiner = ` Look Ma, 2 lines!`
And they can also contain embedded expressions, which is another way of saying they support interpolations:
而且它们还可以包含嵌入式表达式,这是表示它们支持插值的另一种方式:
const food = 'burger'
const str = 'Mmmm! That is a tasty ${food}!
${ This here }
is an interpolation. Think of them as placeholders for JavaScript expressions.
${ This here }
是${ This here }
。 将它们视为JavaScript表达式的占位符。
Tagged template literals, on the other hand, are simply template literals that are used to call a function instead of the normal comma-separated values inside of parentheses:
另一方面,带标签的模板文字是仅用于调用函数的模板文字,而不是括号内的普通逗号分隔值:
// regular function call
myFunc(1, 2, 3)
// tag function call
myFunc`1, 2, 3`
The second version of myFunc
above is known as a tag function.
上面的myFunc
的第二个版本称为标记函数 。
The way the two call sites of myFunc
pass on their parameters is what sets them apart. You already know how a regular function call passes on its parameters, but I don’t expect you to know how tag functions do so.
myFunc
的两个调用站点传递其参数的方式使它们与众不同。 您已经知道常规函数调用如何传递其参数,但是我不希望您知道标记函数是如何传递的。
Max sums this up extremely well in his post, and it’s the thing you must understand about tagged template literals, so I will summarize how it works by using the same function he created:
马克斯总结这件事在他的岗位非常好,这是你必须了解有关标签模板文字的东西,所以我会总结一下它是如何工作原理是利用他创造了相同的功能:
const logArgs = (...args) => console.log(...args)
The function above uses the spread…rest operators. The arguments to the function are being collected into a single array named args
using the …args
syntax. This is referred to as rest. You can think of it as “collecting the rest” of the arguments into an array named args
. It’s useful when you don’t know how many arguments the function might have.
上面的函数使用spread…rest运算符。 使用…args
语法将函数的参数收集到名为args
的单个数组中。 这称为休息 。 您可以将其视为将参数的“收集”到一个名为args
的数组中。 当您不知道该函数可能有多少个参数时,这很有用。
Its sibling, spread, occurs when we log the arguments to the console using console.log(...args)
. We’re literally “spreading out” the contents of the args
array.
当我们使用console.log(...args)
将参数记录到控制台时,就会发生它的同级传播 。 我们实际上是在“散布” args
数组的内容。
These two operators help us visualize exactly what’s being passed to logArgs
. Let’s examine the result of this function when called in the two ways described earlier:
这两个运算符可帮助我们准确地可视化传递给logArgs
。 让我们检查一下以前面介绍的两种方式调用此函数时的结果:
logArgs(1, 2, 3)
// -> 1
// -> 2
// -> 3
logArgs`1, 2, 3`
// -> ["1, 2, 3"]
Calling the function as normal does what we expect. It spreads the args
array out into individual values, and logs each to the console.
正常调用该函数符合我们的期望。 它将args
数组散布为各个值,并将每个值记录到控制台。
Calling logArgs
using a tagged template literal, on the other hand, logs an array. This is our first lesson:
另一方面,使用带标签的模板文字调用logArgs
记录一个数组。 这是我们的第一课:
Tagged template literals pass an array of string values as the first argument to the tag function.
标记的模板文字将字符串值的数组作为标记函数的第一个参数传递。
Things get even more interesting when we include interpolations:
当我们包括插值时,事情变得更加有趣:
const food = 'burger'
logArgs`Mmmm! That is a tasty ${food}!`
// -> ["Mmmm! That is a tasty ", "!"]
// -> "burger"
logArgs
still outputs an array of string values as its first argument, but if the tagged template literal has an interpolation, then the expression inside the interpolation is passed as the next argument.
logArgs
仍将字符串值数组作为第一个参数输出,但是如果标记的模板文字具有插值,则插值内部的表达式将作为下一个参数传递。
What happens when there are multiple interpolations?
有多个插值时会发生什么?
const food = 'burger'
const adj = 'tasty'
logArgs`Mmmm! That is a ${adj} ${food}!`
// -> ["Mmmm! That is a ", " ", "!"]
// -> "tasty"
// -> "burger"
We could have as many interpolations as we want, and each one will be passed accordingly. This is the second lesson:
我们可以根据需要插入任意数量的插值,并且每个插值都会相应地传递。 这是第二课:
If interpolations exist inside tagged template literals, their containing expressions are passed as additional arguments to the tag function.
如果在标记的模板文字中存在插值,则将其包含的表达式作为附加参数传递给标记函数。
Let’s see how tagged template literals handle interpolated functions:
让我们看看带标签的模板文字如何处理内插函数:
logArgs`Mmmm! That is a tasty ${() => 'burger'}`
// -> ["Mmmm! That is a tasty", "!"]
// -> () => "burger"
The function itself is being included as an argument. This is the essence of styled-components
. By capturing such a function, the library can execute it and do what it needs to do, mainly merge the resulting value back in to the string values inside the array.
函数本身已作为参数包含在内。 这是styled-components
的本质。 通过捕获此类函数,库可以执行该函数并执行所需的操作,主要是将结果值合并回数组中的字符串值。
将我们新发现的知识捆绑在一起 (Tying our new-found knowledge together)
Now that we know how tagged template literals work, let’s gain a deeper understanding of the `styled` API:
现在我们知道加标签的模板文字是如何工作的,让我们更深入地了解“ styled” API:
const Button = styled.button` background: ${props => props.primary ? 'red' : 'white'}; color: black;`
styled.button
is a tag function. If we were to log the arguments of this function, we’d see this:
styled.button
是一个标记函数。 如果我们要记录此函数的参数,则会看到以下内容:
logArgs` background: ${props => props.primary ? 'red' : 'white'}; color: black;`
// -> ["background: ", "; color: black;"]
// -> props => props.primary ? "red" : "white"
Are you seeing the power here? It’s no wonder why styled-components
has become so popular as a CSS-in-JS solution. Not only do tagged template literals allow us to write multi-line CSS naturally, but it allows the library to manipulate styles through these interpolated functions, giving our components a dynamic feel.
您在这里看到力量吗? 难怪为什么styled-components
作为CSS-in-JS解决方案如此流行。 带标签的模板文字不仅使我们能够自然地编写多行CSS,而且还允许库通过这些内插函数来操纵样式,从而使我们的组件具有动态感。
那么其他模式如何工作? (So how does the other pattern work?)
Ah, yes. That’s why you’re here, isn’t it. Earlier, I showed another way of using the styled
API that I’ve been seeing lately:
是的。 那就是为什么你在这里,不是吗。 较早前,我展示了另一种使用styled
API的方法,该方法最近已经见过:
const Button = styled('button')([], 'background: palevioletred', 'color: #fff')
First, understand that styled.button
and styled('button')
are treated the same way. They’re interchangeable.
首先,了解对styled.button
和styled('button')
的处理方式相同。 它们是可互换的。
Second, there’s no tagged template literal action here. But, since we know that styled
supports them, we know how it expects its arguments. This is the major key ?.
其次,这里没有带标签的模板文字操作。 但是,由于我们知道styled
支持它们,因此我们知道 styled
如何期望其参数 。 这是主要的关键。
Remember the two rules:
记住以下两个规则:
Tagged template literals pass an array of string values as the first argument to the tag function.
标记的模板文字将字符串值的数组作为标记函数的第一个参数传递。
If interpolations exist inside tagged template literals, their containing expressions are passed as additional arguments to the tag function.
如果在标记的模板文字中存在插值,则将其包含的表达式作为附加参数传递给标记函数。
So the tag function expects an array of string values as its first argument, and interpolated expressions follow suit.
因此,标记函数期望将字符串值的数组作为其第一个参数,并且插值表达式也照此进行。
In the pattern above, which I will give the name “The Empty Array Pattern”, the arguments are:
在上面的模式中,我将其命名为“空数组模式” ,其参数为:
// -> []
// -> 'background: palevioletred'
// -> 'color: #fff'
The first argument is an array, and satisfies rule number one. Yes, there’s no string values inside the array, but that’s totally fine. The additional arguments are strings which, by definition are expressions that produce a value, and as such they satisfy rule number two.
第一个参数是一个数组,并且满足第一个规则。 是的,数组中没有字符串值,但这完全可以。 附加参数是字符串,根据定义,它们是产生值的表达式,因此它们满足第二个规则。
We’ve mimicked the behavior of tagged template literals without actually using them.
我们已经模拟了带标签的模板文字的行为,而没有实际使用它们。
结语 (Wrapping Up)
At the end of the day, both patterns produce the same value. What I’m finding difficult to discover is why you would want to use one over the other. I guess I could see a situation where, using tagged template literals, you had multiple interpolations, and for code readability you could choose the Empty Array Pattern instead:
最终,这两种模式都会产生相同的值。 我发现很难发现的是为什么您要使用另一个。 我想我会看到一种情况,使用标记的模板文字,您可以进行多个插值,并且出于代码可读性的考虑,您可以选择“ 空数组模式” :
// as tagged template literal
const Button = styled.button` background: ${ props => props.background }; color: ${ props => props.color };`
// as Empty Array Pattern
const Button = styed.button([], props => ({ background: props.background, color: props.color}))
I’d love to hear insights from others who have experience with these patterns, and what the pros and cons are of each!
我很想听听其他有这些模式经验的人的见解,以及每种方法的优缺点!
This was a cross-post from my own blog. ?
这是我自己的博客的一个交叉帖子。 ?
Say hi on Twitter ?
翻译自: https://www.freecodecamp.org/news/using-styled-components-without-template-literals-75496476e73d/
组件模板里可以直接写样式么