如何编写自定义 Sass 函数
如果您构建过不少网站,可能已注意到可以在一个项目中轻易的复制代码然后跨项目应用。反复复制相同的代码会浪费时间和增加错误出现的可能性。在Sass之前的系列中,我曾说 mixins 是样式重用和 编写 DRYer代码 的一个选择。Functions是实现相同功能的另一个方法。
最近几个月我一直在讲 Sass 的数据类型、运算符和函数。我们讲过了 numbers
, strings
, colors
, colors again, lists
, lists again, 和 maps
。过去几周我讲到了控制指令。今天是该系列的最后一部分,我想以 @function
指令和如何编写自定义函数结课。
如何创建和使用自定义函数
函数是可返回一个 Sass 任何数据类型单一值的代码块。创建自定义函数需要两个Sass指令,@function
和@return
。前者创建函数,后者表明了函数将返回的值。
@function function-name($args) {
@return value-to-be-returned;
}
传递到函数中的参数是可选的,尽管你会经常使用它们。通常Sass函数会使用传递过去的参数进行运算,也可能是一些所有函数都可以访问的全局变量。
由于历史原因,函数名可交替使用破折号或下划线,故 function-name
和 function_name
是相同的函数,可使用破折号或下划线调用函数,无论命名时使用的是哪个。
上述代码只显示了一行返回一个值的代码,但大多数函数所做的并不仅限于此,于是 @return
指令将会作为函数的最后一行。
记得只有一个值返回,这个值可以是任何的数据类型,返回的可以是数字 9
,字符串 "I am a string"
,或者一种数据结构,比如list
或map
,里面包含您想要的任何值。
要使用函数您需要提供函数名和参数,放在想要返回值显示的位置。
p {
font-size: function-name($args);
}
p {
font-size: function_name($args);
}
重申,这两个都会调用同一个函数。可以假定该函数将计算px
或em
值,并返回作为段落的font-size
。
正像我所说的,函数可以访问任何全局定义的变量。下个示例中我创建了两个全局变量,$total
和$col
。$total
表示网格的总列数,$col
表示一个3
列宽的网格字段。
$total: 8;
$col: 3
@function column-width() {
@return percentage($col/$total);
}
这个函数没有任何参数。它用$col
除以$total
,使用内置percentage
函数将结果在返回之前变成百分值。
我们可在想要返回值显示的位置通过添加函数名来调用函数。因为这个函数不带参数,调用时无需传参。
.col-3 {
width: column-width();
}
函数完成运算后代码被编译为:
.col-3 { width: 37.5%; }
这样编写的函数用处不大,因为不得不硬编码总列数和网格字段的大小作为全局变量。一个更有用的方案是将这些变量当成参数传递,下面我们重写这个函数。
@function column-width($col, $total) {
@return percentage($col/$total);
}
该函数现在接收参数,我们必须在函数调用期间传值过去,尽管我们可以重用这个函数并用不同的参数调用它。
.col-3 {
width: column-width(3, 8);
}
.col-5 {
width: column-width(5, 8);
}
会编译成:
.col-3 {
width: 37.5%;
}
.col-5 {
width: 62.5%;
}
关键字参数
您可能已经注意到,在前面的实例中,我按照它们在函数中列出的顺序传递参数。这是必须的,除非您使用关键字。
可以使用key:value
的格式传递键/值对。
.col-3 {
width: column-width($col: 3, $total: 8);
}
如果包含了键名,则不必按它们在函数中列出的顺序来排列。
.col-3 {
width: column-width($total: 8, $col: 3);
}
尽管函数是以先$col
后$total
的顺序列出,通过使用每个值之前的关键字,函数知道哪个对应哪个。
您还可以在创建函数时声明参数的默认值。这里我修改了函数,所以总列数的默认值为8
。
@function column-width($col, $total:8) {
@return percentage($col/$total);
}
.col-3 {
width: column-width(3);
}
上面的代码只传递了一个值到函数。该函数会使用我没有传递的那个参数的默认值,仍然会编译成:
.col-3 {
width: 37.5%;
}
您可通过传递带有或者不带关键字的参数来覆盖默认值。
.col-3 {
width: column-width(3, 9);
}
.col-4 {
width: column-width($col:3, $total:12);
}
一个更实际的例子
到目前为止并没有哪个例子很实用。我写它们是为了解释某事物如何运作。下面我们来写一些更实用的代码。
这里我将全局变量$total
设置为8
,然后重写了前面例子中的函数,使用全局变量,而不是将总列数作为参数传递。
最后我使用了一个从1
运行到$total
值的for
循环。在循环里面,计数器$i
成为了类名的一部分,并且类的宽度是通过将$i的值传递给函数而生成的。
$total: 8;
@function column-width($col) {
@return percentage($col/$total);
}
@for $i from 1 through $total {
.col-#/{$i/} { width: column-width($i) };
}
Sass代码编译为:
.col-1 { width: 12.5%; }
.col-2 { width: 25%; }
.col-3 { width: 37.5%; }
.col-4 { width: 50%; }
.col-5 { width: 62.5%; }
.col-6 { width: 75%; }
.col-7 { width: 87.5%; }
.col-8 { width: 100%; }
如果您决定使用12
列或9
列或4
列而不是8
列布局,您只需要更改$total
的值。自定义函数和@for
循环将完成其余操作。
可变参数
像mixins一样,函数可以通过在参数名称后面使用3
个点(非省略号)来接收可变参数。该函数将从传递给它的变量参数创建一个列表。
在下面的示例中我创建了一个函数,它接收一个名为$index
的参数和一个名为$widths...
的变量参数。
@function column-width($index, $widths...){
@return nth($widths, $index);
}
该函数将使用内置的nth
函数找到$widths
中下标为$index
的值。当调用该函数时,我传递给它一个索引值和一系列的百分比宽度。
.col-3 {
width: column-width(3, 25%, 50%, 75%, 100%);
}
因为75%
是索引为3
的值,所以代码编译为:
.col-3 {
width: 75%;
}
坦白说这不是特别有用的函数,因为如果仅仅是设置宽度,不调用函数设置会更容易。虽然可变参数在mixins中有用,可以添加多个盒子阴影,但很难想象它们在函数中有什么用处。但这仍然是你可以做的事,我认为值得分享。
给您的函数名添加前缀
值得一提的是,给您的函数名添加一个前缀不失为一个好主意,这样可避免与内置函数或您可能正在使用的库产生命名冲突。
不难想象其他人创建了一个与我在示例中使用的函数名称冲突的column-width
函数。将其命名为vanseo-column-width
可能更好,因为第三方函数不太可能会使用相同的前缀。
Function还是Mixin
因为 Sass functions 和 Sass mixins 是相似的,您可能纳闷应该使用哪个。虽然类似,但它们有一个重要的区别,这表明了在什么时候使用哪个是最佳的。
两者之间的主要区别是,Sass代码的mixins输出行将直接编译为CSS样式,而函数则返回一个可以作为CSS属性或可传递给另一个function或mixin的值。
说实话,您可以将每个函数都改写为混合宏的形式,反之亦然,但每个都有清晰的用例。
想要直接输出样式,使用mixin;想执行返回值的运算,使用 function。例如,确定响应容器的百分比宽度公式可能看起来很熟悉
target / context = result
因为这是一个可能在样式表中执行多次的运算,适合使用function,您可以传递target和context的值从而得到返回的结果。
总结
Functions 是一种将可重用的代码移动到单独包的方法。它们与mixins相似,两者的不同点在于输出。 Functions 返回一个值而mixins输出代码。如果您知道怎么使用其中一个,那么使用另一个对您来说也不难。
Sass 数据类型,运算符和函数系列已经到了尾声。希望在系列的最后您能理解我为什么花时间讲每种不同的数据类型。除颜色外,其他的数据类型在function和mixins中更有用。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论