在React中使用个性化SVG图标

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

前段时间和大家一起探讨了在React框架体系下如何使用SVG构建SVG图标系统。不管是引入.svg文件当作React组件,还是通过工程能力将.svg文件转换成React组件,它们之间都有一定的共性,比如说无法修改SVG部分的外观特性等。但在SVG的内联使用中,我们是可以通过CSS的特性或调整SVG元素标签的属性,可以自定义SVG外观,甚至还可以添加动效。因此,今天想和大家探讨如何在React中使用自定义(个性化)的SVG。

构建个性化SVG

如果你对SVG有所了解的话,应该知道在SVG中很多地方和HTML非常的相似,比如说,在<svg>元素中可以包含一个子元素或多个子元素,以及单个或多个后代元素。即使是同一个SVG图标,也存在这样的场景。比如说一个关闭图标:

如果使用Sketch构建这个图标的话,有可能是两个<line>元素组合在一起构建出来:

Sketch直接导出来的SVG代码中会有部分垃圾代码,但我们可以使用SVGO对其进行优化:

<!-- 优化前的代码 -->
<?xml version="1.0" encoding="UTF-8"?>
<svg width="257px" height="257px" viewBox="0 0 257 257" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>编组</title>
    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
        <g id="编组" transform="translate(10.899600, 10.107908)" stroke="#000000" stroke-width="20">
            <line x1="7" y1="3" x2="228.941775" y2="233.525158" id="直线" transform="translate(117.970887, 118.262579) rotate(-1.086781) translate(-117.970887, -118.262579) "></line>
            <line x1="7" y1="3" x2="228.941775" y2="233.525158" id="直线" transform="translate(117.970887, 118.262579) rotate(88.913219) translate(-117.970887, -118.262579) "></line>
        </g>
    </g>
</svg>

<!-- 优化后的代码 -->
<svg xmlns="http://www.w3.org/2000/svg" width="257" height="257" viewBox="0 0 257 257">
    <g fill="none" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-width="20" transform="translate(10.9 10.108)">
        <line x1="7" x2="228.942" y1="3" y2="233.525" transform="rotate(-1.087 117.97 118.263)"/>
        <line x1="7" x2="228.942" y1="3" y2="233.525" transform="rotate(88.913 117.97 118.263)"/>
    </g>
</svg>

你可能已经看到了,这个<svg>元素中有两个<line>元素构建了关闭图标。

我们再来看另一种构建这个关闭按钮的方式,和上面唯一不同的方式就是使用路径(<path>来绘制:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" class="icon" viewBox="0 0 1024 1024">
    <defs><style/></defs>
    <path d="M925.468404 822.294069 622.19831 512.00614l303.311027-310.331931c34.682917-27.842115 38.299281-75.80243 8.121981-107.216907-30.135344-31.369452-82.733283-34.259268-117.408013-6.463202L512.000512 399.25724 207.776695 87.993077c-34.675754-27.796066-87.272669-24.90625-117.408013 6.463202-30.178323 31.414477-26.560936 79.375815 8.121981 107.216907l303.311027 310.331931L98.531596 822.294069c-34.724873 27.820626-38.341237 75.846432-8.117888 107.195418 30.135344 31.43699 82.72919 34.326806 117.408013 6.485715l304.178791-311.219137 304.177767 311.219137c34.678824 27.841092 87.271646 24.951275 117.408013-6.485715C963.808618 898.140501 960.146205 850.113671 925.468404 822.294069z"/>
</svg>

虽然两种不同的方式构建出一个相同的关闭图标,但是两者之间还是有着很大的差异性。比如说,这个关闭图标两条直线希望不同的颜色,那么只有第一种方式才能实现,只需要给两个<line>stroke设置不同的颜色:

<line stroke="red" x1="7" x2="228.942" y1="3" y2="233.525" transform="rotate(-1.087 117.97 118.263)"/>
<line stroke="orange" x1="7" x2="228.942" y1="3" y2="233.525" transform="rotate(88.913 117.97 118.263)"/>

这个时候效果如下:

但对于使用第二种方式构建的SVG图形,要实现这样的效果是不可能的。

另外,通过多个元素来SVG图形,并且希望不同的SVG元素具有个性化特性,即简称 自定义SVG图形。这种SVG图形的使用场景也越来越广泛,比如现在比较流行的SVG插画,就可以采用这种方式来构建:

如果你对SVG构建基本图形方面的知识感兴趣的话,可以花点时间阅读《通过Sketch设计软件学习SVG基础知识》和《How to Simplify SVG Code Using Basic Shapes》。

SVG动效

时至今日,Web动效在Web应用的开发中非常常见,而Web动效的开发方式也在不断的变革,比如:

  • 早期的.gif图,实现帧率变换的动效以及现代的.apng图替代.gif图动效
  • CSS的animation的帧动效
  • JavaScript的动效

其实在SVG的世界中,动效也是SVG的特性之一。而且在SVG制作动效的方式也有很多种。

.svg文件自身就具备动效

不管是早期的.gif文件,还是近年出现的.apng文件,都是以文件格式来描述动效的一种方式:

其实,在SVG的世界中,.svg文件也可以类似于.gif(或.apng)文件格式类似,用文件方式来描述动画效果,比如:

如果我们有一个类似上图的.svg文件,不管是在HTML的<img>还是在CSS的background-image中引入该.svg文件,都将会具有动画效果(有点类似于.gif文件):

<!-- HTML -->
<img src="path/svg__animation.svg" alt="">

/* CSS */
.box {
    width: 30vmin;
    height: 30vmin;
    max-width: 400px;
    max-height: 400px;
    border: 1px solid black;
    box-shadow: 0 0 10px rgba(0,0,0,0.2);
    background: url(path/svg__animation.svg);
}

如果你将上面示例中引用的.svg文件下载到本地,并且用文本编辑器打开该文件,你可以看到对应的SVG代码如下所示:

<!-- .svg文件对应的SVG代码 -->
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <style>
        circle {
            animation: bounce 2s infinite ease-in-out alternate;
            transform-origin: 50px 50px;
        }
        @keyframes bounce {
            to {
                transform: scale(0);
            }
        }
    </style>
    <circle cx="50" cy="50" r="25" />
</svg>

从代码中不难发现,虽然是.svg格式的文件,但在该文件对应的SVG代码中有我们熟悉的CSS Animation的身影

CSS animation实现SVG动效

上面的示例告诉我们,在<svg>中我们可以通过内联<style>的方式引入CSS的animation特性,让SVG动起来。

简单地说,如果想通过animation来控制<svg>中的某个元素(比如某个<path>元素)动起来,就需要用多个元素来构建一个SVG图形,比如下面这个效果:

svg-icon

上面的SVG图标对应的SVG代码如下:

<svg id="my-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 290 290">
    <title>SVG Animation with CSS Animation</title>
    <circle id="circle" cx="145" cy="145" r="124.67" style="fill: none;stroke: #444;stroke-miterlimit: 10;stroke-width: 20px"/>
    <polyline id="checkmark" points="88.75 148.26 124.09 183.6 201.37 106.32" style="fill: none;stroke: #444;stroke-linecap: round;stroke-linejoin: round;stroke-width: 25px"/>
</svg>

正如上面的代码所示,我们可以在对应的<cirle><polyline>元素上显式的设置classid,然后将<style>内联到<svg>中(有点类似于将<style>放置在HTML的<head>中),并且借且CSS的animation能力(@keyframes定义的动效)让SVG动起来。

<!-- SVG Code -->
<svg id="my-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 290 290">
    <title>SVG Animation with CSS Animation</title>
    <style>
        #circle {
            opacity: 0;
            transform: scale(0.9);
            transform-origin: center;
            animation: circle-animation 0.5s ease-out forwards;
        }

        #checkmark {
            stroke-dasharray: 400;
            stroke-dashoffset: 400;
            transform-origin: center;
            stroke: #cfd8dc;
            animation: checkmark-animation 1s ease-out forwards;
            animation-delay: 0.25s;
        }

        @keyframes circle-animation {
            100% {
                opacity: 1;
剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/react/personalized-svg-icon.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部