SVG基础知识大全

4,119 阅读30分钟

1. SVG简介

  • SVG,即可缩放矢量图形( Scalable Vector Graphics),是一种 XML应用

    • 来描述二维图形和绘图程序的语言
  • SVG指可伸缩矢量图形

  • SVG用来定义用于网络的基于矢量的图形

  • SVG使用XML格式定义图形

  • SVG图像在放大或改变尺寸的情况下其图形质量不会有所损失,即不会失真

  • SVG 可以制作成整体或局部动画

  • SVG 图像可以与DOM,CSS和JavaScript交互

  • SVG 可以被记事本等阅读器、搜索引擎访问

  • SVG 图像中的文本是可选的,同时也是可复制的

  • 相比其它位图,SVG图像文件更小,可压缩性更强

  • SVG 提供了一些图像编辑效果,比如屏蔽和剪裁、应用过滤器等等

  • SVG 只是文本,因此可以使用 GZip 对其进行有效压缩。

2. SVG和Canvas区别

  • canvas是html5的新特征,而svg存在的历史已经很久了
  • svg所描绘的图形为矢量图,所以用法上收到了限制,只能描绘矢量图
    • 而svg中不能引入普通的图片
    • 由于本质为矢量图,而百度地图就是用svg技术来做出来的
  • canvas所描绘的图形为位图,,你会看到canvas里面的图形和文字会失真
  • canvas支持颜色比svg多

3. 插入SVG的N种方式总结

1、使用svg标签

  • 直接把SVG整个标签内容丢到HTML中即可

2、使用img标签

<img src="./test.svg" style="display:block;width:330px;height:240px" />

3、使用iframe标签

  • 万能的iframe当然什么都能显示,但是无法控制内容大小 -- viewBox也搞不定,估计只能用百分比来定位了,太麻烦了,一般不使用
<iframe src="./test.svg" style="display:block;width:330px;height:240px;border:none;" ></iframe>

4、使用embed标签

  • 注意使用viewBox,标签的兼容性也很不错的,是个不错的选择。
<embed src="./test.svg" style="display:block;width:330px;height:240px" />

5、使用object标签

  • <object><embed>类似,也要注意配置viewBox.
<object type="image/svg+xml" data="./test.svg" style="display:block;width:330px;height:240px" >
    <param name="src" value="./test.svg" >
</object>

6、使用div的背景图片

  • svg图片是可以作为背景图片的。不过和<img>标签一样,无法显示SVG内嵌的.
<div style="display:block;width:330px;height:240px;background: url(./test.svg) no-repeat;background-size: 100%;" ></div>
//css
.loading-three-dots{
    background-image: url('data:image/svg+xml,<svg width="120" height="30" viewBox="0 0 120 30" xmlns="http://www.w3.org/2000/svg" fill="%23b5edf5"><circle cx="15" cy="15" r="15"><animate attributeName="r" from="15" to="15" begin="0s" dur="0.8s" values="15;9;15" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="1" to="1" begin="0s" dur="0.8s" values="1;.5;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="60" cy="15" r="9" fill-opacity="0.3"><animate attributeName="r" from="9" to="9" begin="0s" dur="0.8s" values="9;15;9" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="0.5" to="0.5" begin="0s" dur="0.8s" values=".5;1;.5" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="105" cy="15" r="15"><animate attributeName="r" from="15" to="15" begin="0s" dur="0.8s" values="15;9;15" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="1" to="1" begin="0s" dur="0.8s" values="1;.5;1" calcMode="linear" repeatCount="indefinite" /></circle></svg>');
}
html
 <div class="loading loading-three-dots"></div>

background-image内联svg注意事项

  • svg内容需要被url-转义才能执行,例如。#被替换为%23
  • 可使用SVG转义工具

7、使用picture标签

  • <picture>标签是HTML5新增的一个专门显示图片的标签。

注意设置<source>标签的属性srcset而非src. 此外必需要添加一个<img>标签,不过可以在<img>标签中指定另外一张图片,以便在浏览器无法显示<source>指定的图片的时候显示<img>标签中的图片。

<picture><img>一样,无法显示SVG内嵌的<image>.

<picture >
    <source srcset="./test.svg"  type="image/svg+xml">
    <img src="./test.png" style="display:block;width:330px;height:240px">
</picture>

4. SVG的基本图形和属性

图形

  • <rect> :矩形
  • <circle> :圆形
  • <ellipse> :椭圆
  • <line> :直线
  • <polyline> :折现
  • <polygon> :多边形
  • <path> :路径

属性

  • fill :填充
  • stroke :描边颜色
  • transform :图形变换
  • opacity :不透明度

stroke属性

1、stroke-width

  • 描边的粗细

2、stroke-linecap

  • 控制边框终点的形状
    • 属性的值有三种可能值
      • butt 用直边结束线段,它是常规做法,线段边界90度垂直于描边的方向、贯穿它的终点
      • squarebutt效果差不多,但是会稍微超出实际路径的范围,超出的大小由stroke-width控制。
        • round表示边框的终点是圆角,圆角的半径也是由stroke-width控制的

3、stroke-dasharray

  • 用于创建虚线,之所以后面跟的是array的,是因为可以是多个参数
stroke-dasharray = '10'
stroke-dasharray = '10, 5'
stroke-dasharray = '20, 10, 5'

上面代码理解:

stroke-dasharray为一个参数时:其实是表示虚线长度和每段虚线之间的间距   如:stroke-dasharray = '10' 表示:虚线长10,间距10,然后重复 虚线长10,间距10

两个参数或者多个参数时:一个表示长度,一个表示间距   如:stroke-dasharray = '10, 5' 表示:虚线长10,间距5,然后重复 虚线长10,间距5   如:stroke-dasharray = '20, 10, 5' 表示:虚线长20,间距10,虚线长5,接着是间距20,虚线10,间距5,之后开始如此循环

4、stroke-dashoffset

  • 属性指定了dash模式到路径开始的距离

5、stroke-linejoin

  • 控制两条描边线段之间,用什么方式连接
    • 属性的值有三种可能值
      • miter是默认值,表示用方形画笔在连接处形成尖
      • round表示用圆角连接,实现平滑效果
      • bevel,连接处会形成一个斜接

6、stroke-opacity

  • 描边透明度

4.1 矩形 <rect>

属性如下

  • x :属性定义矩形的左侧位置
  • y :属性定义矩形的顶端位置
  • width :矩形的宽
  • height :矩形的高
  • rx :rx定义圆角的宽
  • ry :ry定义圆角的高
    • 矩形的圆角效果,是用rx,ry定义的

4.2 圆形 <circle>

属性如下

  • cx :定义圆点的X坐标
  • cy :定义圆点的y坐标
  • r :定义圆的半径

4.3 椭圆 <ellipse>

1 、椭圆与圆很相似。不同之处在于椭圆有不同的x和y半径,而圆的x和y半径是相同的

2 、椭圆其实就是在圆的基础上增加了维度的半径

属性如下

  • cx :定义的椭圆中心的x坐标
  • cy :定义的椭圆中心的y坐标
  • rx :定义的水平半径
  • ry :定义的垂直半径

4.4 直线 <line>

直线:描述2个点定义一条直线

属性如下

  • x1
  • y1
  • x2
  • y2

4.5 折线 <polyline>

折现:是一组连接在一起的直线。因为它可以有很多的点,折线的的所有点位置都放在一个points属性中

属性

  • points
    • 格式 :points="x1 y2,x2 y2....."
    • 点集数列。每个数字用空白、逗号、终止命令符或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。
    • 如:
<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

4.6 多边形 <polygon>

polygon和折线很像,它们都是由连接一组点集的直线构成。不同的是,polygon的路径在最后一个点处自动回到第一个点。需要注意的是,矩形也是一种多边形,如果需要更多灵活性的话,你也可以用多边形创建一个矩形

属性

  • points
    • 格式 :points="x1 y2,x2 y2....."
    • 点集数列。每个数字用空白、逗号、终止命令符或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。

4.7 路径 <path>

-参考:developer.mozilla.org/zh-CN/docs/…

path可能是SVG中最常见的形状。你可以用path元素绘制矩形(直角矩形或者圆角矩形)、圆形、椭圆、折线形、多边形,以及一些其他的形状,例如贝塞尔曲线、2次曲线等曲线。因为path很强大也很复杂

属性

  • d :一个点集数列以及其它关于如何绘制路径的信息
    • 属性d的值是一个“命令+参数”的序列
    • 每一个命令都用一个关键字母来表示,比如,字母“M”表示的是“Move to”命令,当解析器读到这个命令时,它就知道你是打算移动到某个点
    • 跟在命令字母后面的是你需要移动到的那个点的x和y轴坐标。比如移动到(10,10)这个点的命令,应该写成“M 10 10”
    • 这一段字符结束后,解析器就会去读下一段命令。每一个命令都有两种表示方式,一种是用大写字母表示采用绝对定位。另一种是用小写字母表示采用相对定位
    • 属性d采用的是用户坐标系统,所以不需标明单位

4.7.1 svg的 <path>命令

M = moveto

M x y 移动到指定坐标,xy分别为x轴和y轴的坐标点,类似画笔的起点。

L = lineto

L x y 在初始位置(M 画的起点)和xy确定的坐标画一条线。 两点一线,直线,绘图中很常见的方式。

H = horizontal lineto

H x 沿着x轴移动一段位置

V = vertical lineto

V y 沿着y轴移动一段位置

C = curveto

C x1 y1 x2 y2 x y 三次贝塞尔曲线

S = smooth curveto

S x2 y2 x y 简化的贝塞尔曲线

1.如果S命令跟在一个C命令或者另一个S命令的后面,它的第一个控制点,就会被假设成前一个控制点的对称点。

2.如果S命令单独使用,前面没有C命令或者另一个S命令,那么它的两个控制点就会被假设为同一个点。

Q = quadratic Bézier curve

Q x1 y1 x y 二次贝塞尔曲线Q 只需要一个控制点,用来确定起点和终点的曲线斜率。因此它需要两组参数,控制点和终点坐标。

T = smooth quadratic Bézier curveto

Q命令的简写命令。
与S命令相似,T也会通过前一个控制点,推断出一个新的控制点。

1.T命令前面必须是一个Q命令,或者是另一个T命令

2.如果T单独使用,那么控制点就会被认为和终点是同一个点,所以画出来的将是一条直线

A = elliptical Arc

A rx,ry x-axis-rotation large-arc-flag sweep-flag x,y rx 弧的半长轴长度 ry 弧的半短轴长度 x-axis-rotation 是此段弧所在的x轴与水平方向的夹角,即x轴的逆时针旋转角度,负数代表顺时针旋转角度。 large-arc-flag 为1表示大角度弧线,0表示小角度弧线 sweep-flag 为1表示从起点到终点弧线绕中心顺时针方向,0表示逆时针方向。 xy 是终点坐标。

Z = closepath

从当前位置到起点画一条直线闭合。

注意:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。

4.7.2 直线命令

<path>元素里有5个画直线的命令,顾名思义,直线命令就是在两个点之间画直线。首先是“Move to”命令,M,前面已经提到过,它需要两个参数,分别是需要移动到的点的x轴和y轴的坐标。假设,你的画笔当前位于一个点,在使用M命令移动画笔后,只会移动画笔,但不会在两点之间画线。因为M命令仅仅是移动画笔,但不画线。所以M命令经常出现在路径的开始处,用来指明从何处开始画。

  • 格式
M x y

or

m dx dy

4.7.3 曲线命令

绘制平滑曲线的命令有三个,其中两个用来绘制贝塞尔曲线,另外一个用来绘制弧形或者说是圆的一部分。如果你在Inkscape、Illustrator或者Photoshop中用过路径工具,可能对贝塞尔曲线有一定程度的了解。欲了解贝塞尔曲线的完整数学讲解,请阅读这份Wikipedia的文档。在这里不用讲得太多。贝塞尔曲线的类型有很多,但是在path元素里,只存在两种贝塞尔曲线:三次贝塞尔曲线C,和二次贝塞尔曲线Q。

5. SVG基本操作API

5.1 创建图形

//创建一个具有指定的命名空间URI和限定名称的元素
//要创建一个元素而不指定命名空间URI,请使用createElement 方法。
let element = 
document.createElementNS(namespaceURI, name[, options]);

参数

  • namespaceURI

指定与元素相关联的命名空间URI的字符串。创建的元素的namespaceURI属性使用namespaceURI的值进行初始化

  • name

字符串值,可为此元素节点规定其名称。

  • options (可选的)

一个可选的包含单个属性的ElementCreationOptions对象,其值是预先使用customElements.define()定义的自定义元素的标签名称。为了向后兼容自定义元素规范的早期版本,一些浏览器允许您在此使用字符串替代对象,其中字符串的值是自定义元素的标签名称。

返回值

  • 新元素

5.1.1 有效的命名空间URI

HTML - 参阅 www.w3.org/1999/xhtml

SVG - 参阅 www.w3.org/2000/svg

XBL - 参阅 www.mozilla.org/xbl

XUL - 参阅 www.mozilla.org/keymaster/g…

5.2 添加图形

element.appendChild(childElement)

5.3 设置/获取属性

element.setAttribute(name,value) 
element.getAttribute(name)

6. 简单的SVG编辑器

7.在线SVG压缩和转义工具

  • 支持选择SVG文件上传,支持拖拽上传,也支持直接粘贴SVG代码进行压缩
  • 例如从iconfont.cn网站随便下一个SVG图标,然后上传下,还有将近40%的压缩比:
  • www.zhangxinxu.com/sp/svgo/

8. SVG Sprites还原与管理的在线工具

  • 每个SVG小图标可以独立下载,也可以复制内联SVG代码,或者base64代码或者作为CSS背景使用的转义SVG代码。内置1500多个 Font Awesome小图标,对于一些要求不高的项目,可以直接复制这些小图标。
  • www.zhangxinxu.com/sp/icon/

9.验证 SVG

  • SVG 文件是 XML,可以用无效的格式编写,有些服务或应用程序可能不接受无效的 SVG 文件。

  • SVG 可以使用validator.w3.org/验证

10. SVG的世界: 视野、视窗的概念

视窗:是浏览器渲染出来的一个区域

视野:是SVG文件编写者定义的多大的视野观察世界

11. SVG颜色表示

SVG和canvas中是一样的,都是使用标准的HTML/CSS中的颜色表示方法,这些颜色都可以用于fill和stroke属性。

基本有下面这些定义颜色的方式:

1、颜色名字: 直接使用颜色名字red, blue, black…

2.rgba/rgb值: 这个也很好理解,例如#ff0000,rgba(255,100,100,0.5)。

3.十六进制值: 用十六进制定义的颜色,例如#ffffff。

4.渐变值:这个也与canvas中一样,支持两种渐变色:线性渐变,径向渐变。

5、图案填充:使用自定义的图案作为填充色。

12. 渐变

12.1 线性渐变

线性渐变沿着直线改变颜色,要插入一个线性渐变,你需要在SVG文件的defs元素内部,创建一个<linearGradient>节点即可定义线性渐变。每一个渐变色成分使用stop元素定义。

12.2 径向渐变

径向渐变是从一个点开始发散绘制渐变,创建径向渐变需要在文档的defs中添加一个<radialGradient>元素

12.3 <stop>节点元素

一个渐变上的颜色坡度,是用stop元素定义的。stop元素可以是<linearGradient>元素或者<radialGradient>元素的子元素

这些结点通过指定位置的offset(偏移)属性和stop-color(颜色中值)属性来说明在渐变的特定位置上应该是什么颜色;可以直接指定这两个属性值,也可以通过CSS来指定他们的值

13. 结构元素

<defs>,<g>, <svg>, <symbol>, <use>

13.1 <defs> 元素

1、SVG 允许我们定义以后需要重复使用的图形元素。 建议把所有需要再次使用的引用元素定义在defs元素里面。

2、这样做可以增加SVG内容的易读性和可访问性。

3、在defs元素中定义的图形元素不会直接呈现。 你可以在你的视口的任意地方利用<use>元素呈现这些元素。

13.2 <use> 元素

1、use元素在SVG文档内取得目标节点,并在别的地方复制它们。

2、use元素还可以跨SVG调用

3、出于安全原因,一些浏览器可能在use元素上应用同源策略,还有可能拒绝载入xlink:href属性内的跨源URI。

4、use元素是通过xlink:href属性,寻找要使用的元素的

use 复制调用例子

  • 如果我们用了好多给坐标值绘制了半天,如果想弄一个同样的类型,只是位置不同,这时候如果复制一遍代码,会造成我们的代码冗余,因此我们就可以使用use特性重复调用节点
<svg>
  <defs>
    <g id="shape">
        <rect x="0" y="0" width="50" height="50" />
        <circle cx="0" cy="0" r="50" />
    </g>
  </defs>

  <use xlink:href="#shape" x="50" y="50" />
  <use xlink:href="#shape" x="200" y="50" />
</svg>

代码理解:

use元素是通过xlink:href属性,寻找要使用的元素的。#shape对应的就是id为shape的元素。use元素可以有自己的坐标,以及支持transform变换,甚至可以use其他use元素。

这里,两个use元素使用的是同一个g元素(组合),从而实现了图形的重复调用功能。

use 跨SVG调用例子

  • SVG中的use元素可以调用其他SVG文件的元素,只要在一个文档中。

紧接着上面的SVG复制调用的例子

<svg width="500" height="110"><use xlink:href="#shape" x="50" y="50" /></svg>

其实跨SVG调用就是“SVG Sprite技术”的核心所在

13.3 <g>元素

1、g是group(分组)的缩写。

2、<g>元素通常用来对相关图形元素进行分组,盔甲统一操作,例如旋转,缩放或添加相关样式等

3、<g>元素的属性会被其所有的子元素继承

4、<g>元素也可以用来定义复杂的对象,之后可以通过<use>元素来引用它们

5、<g>分组定义的内容直接会显示

13.4 <symbol>元素

1、symbol元素用来定义一个图形模板对象,它可以用一个<use>元素实例化

2、<symbol>能够创建自己的视窗,因此能够应用viewBox和preserveAspectRatio属性

3、一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了symbol的 <use>元素)才能呈现。

14. SVG动画

14.1 animate元素

  • svg中animate元素可以用于实现动画效果,属性如下
    • attributeName 定义发生变化的元素属性名
    • attributeType 当attributeType="XML"时,attributeName被认为是XML的属性;当attributeType="CSS"时,attributeName被认为是css的属性;不指定attributeType时,默认为"auto",会先将attributeName作为css的属性,如果无效,再将attributeName作为XML的属性。
    • from、to、by from和to分别定义发生变化的属性的初始值和终止值。from可缺省,表示初始值即为animate父元素相应的属性值。可用by替换to,表示变化偏移量。
    • begin、dur、end begin定义动画开始时间;dur定义动画所需时间(持续时间);end定义动画终止时间。时间单位h:小时;min:分钟;s:秒;ms:毫秒。默认时间单位为:s
    • fill 当fill="freeze"时,动画终止时,发生变化的元素属性值停留在动画终止时的状态;当fill="remove"时,动画终止时,发生变化的元素属性值回复到动画起始时的状态。fill属性默认值为:remove
<rect x="10" y="10" width="200" height="20" stroke="green" fill="none">
    <animate attributeName="width" attributeType="XML"
    from="20" to="200" begin="0s" dur="3s" fill="freeze" />
</rect>
  • 以上代码会实现一个绿色正方形逐渐拉长的动画。

14.2 animateTransform 元素

  • 实现transform属性改变的动画,使用animateTransform来替代animate元素
    • animateTransform的attributeName被指定为transform
    • 用type属性指定需要改变的属性,如:translate,scale,rotate,skewX,skewY等。和css3的transform属性值一样
    • animateTransform还有个additive属性。默认情况下additive属性值为replace,表示当前animateTransform的初始状态与之前的animateTransform变化结果无关,如果additive="sum",表示当前animateTransform的变化基于之前的animateTransform变化之上、
<rect x="10" y="10" width="20" height="20" style="fill: #ff9; stroke: black;">
    <animateTransform id="a1" attributeName="transform" attributeType="XML" type="scale" from="1" to="4 2" additive="sum" begin="0s" dur="4s" fill="freeze"></animateTransform>
    <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="45" additive="sum" begin="a1.end" dur="4s" fill="freeze"></animateTransform>
</rect>

14.3 animateMotion 元素

  • animateMotion可以实现单凭css动画属性无法实现的效果。

  • animateMotion可以让父元素沿着指定的路径运动,如:

  • animateMotion有个rotate属性,默认为0,元素在运动时不会旋转。当设置为auto时,元素对应的水平轴会始终与path路径保持水平

<g>
    <rect x="0" y="0" width="50" height="30" style="fill: #ccc;"/>
    <circle cx="40" cy="30" r="10" style="fill: #fff; stroke: black;"/>
    <circle cx="10" cy="30" r="10" style="fill: #fff; stroke: black;"/>
    <animateMotion path="M50,125 C 100,25 150,225, 200, 125" dur="4s" fill="freeze"/>
</g>

14.4 小例子

Loading效果

  • 利用background-image属性显示svg动画作为loading状态,注意url后需要添加数据说明:data:image/svg+xml, 来表示这是sv

公共css

.loading {
    width: 100px;
    height: 100px;
    background-repeat: no-repeat;
    background-size: cover;
}

HTML

<div class="loading loading-audio"></div>
<div class="loading loading-ball-triangle"></div>
<div class="loading loading-bars"></div>
<div class="loading loading-circles"></div>
<div class="loading loading-grid"></div>
<div class="loading loading-oval"></div>
<div class="loading loading-puff"></div>
<div class="loading loading-spinning-circles"></div>
<div class="loading loading-tail-spin"></div>
<div class="loading loading-three-dots"></div>

CSS

.loading-audio {
    background-image: url('data:image/svg+xml,<svg width="55" height="80" viewBox="0 0 55 80" xmlns="http://www.w3.org/2000/svg" fill="#9fe8e0"><g transform="matrix(1 0 0 -1 0 80)"><rect width="10" height="20" rx="3"><animate attributeName="height" begin="0s" dur="4.3s" values="20;45;57;80;64;32;66;45;64;23;66;13;64;56;34;34;2;23;76;79;20" calcMode="linear" repeatCount="indefinite" /></rect><rect x="15" width="10" height="80" rx="3"><animate attributeName="height" begin="0s" dur="2s" values="80;55;33;5;75;23;73;33;12;14;60;80" calcMode="linear" repeatCount="indefinite" /></rect><rect x="30" width="10" height="50" rx="3"><animate attributeName="height" begin="0s" dur="1.4s" values="50;34;78;23;56;23;34;76;80;54;21;50" calcMode="linear" repeatCount="indefinite" /></rect><rect x="45" width="10" height="30" rx="3"><animate attributeName="height" begin="0s" dur="2s" values="30;45;13;80;56;72;45;76;34;23;67;30" calcMode="linear" repeatCount="indefinite" /></rect></g></svg>')
}

.loading-ball-triangle {
    background-image: url('data:image/svg+xml,<svg width="57" height="57" viewBox="0 0 57 57" xmlns="http://www.w3.org/2000/svg" stroke="#9fbde8"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle cx="5" cy="50" r="5"><animate attributeName="cy" begin="0s" dur="2.2s" values="50;5;50;50" calcMode="linear" repeatCount="indefinite" /><animate attributeName="cx" begin="0s" dur="2.2s" values="5;27;49;5" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="27" cy="5" r="5"><animate attributeName="cy" begin="0s" dur="2.2s" from="5" to="5" values="5;50;50;5" calcMode="linear" repeatCount="indefinite" /><animate attributeName="cx" begin="0s" dur="2.2s" from="27" to="27" values="27;49;5;27" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="49" cy="50" r="5"><animate attributeName="cy" begin="0s" dur="2.2s" values="50;50;5;50" calcMode="linear" repeatCount="indefinite" /><animate attributeName="cx" from="49" to="49" begin="0s" dur="2.2s" values="49;5;27;49" calcMode="linear" repeatCount="indefinite" /></circle></g></g></svg>');
}

.loading-bars {
    background-image: url('data:image/svg+xml,<svg width="135" height="140" viewBox="0 0 135 140" xmlns="http://www.w3.org/2000/svg" fill="#c19fe8"><rect y="10" width="15" height="120" rx="6"><animate attributeName="height" begin="0.5s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" /><animate attributeName="y" begin="0.5s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" /></rect><rect x="30" y="10" width="15" height="120" rx="6"><animate attributeName="height" begin="0.25s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" /><animate attributeName="y" begin="0.25s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" /></rect><rect x="60" width="15" height="140" rx="6"><animate attributeName="height" begin="0s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" /><animate attributeName="y" begin="0s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" /></rect><rect x="90" y="10" width="15" height="120" rx="6"><animate attributeName="height" begin="0.25s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" /><animate attributeName="y" begin="0.25s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" /></rect><rect x="120" y="10" width="15" height="120" rx="6"><animate attributeName="height" begin="0.5s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" /><animate attributeName="y" begin="0.5s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" /></rect></svg>');
}

.loading-circles {
    background-image: url('data:image/svg+xml,<svg width="135" height="135" viewBox="0 0 135 135" xmlns="http://www.w3.org/2000/svg" fill="#e8b69a"><path d="M67.447 58c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zm9.448 9.447c0 5.523 4.477 10 10 10 5.522 0 10-4.477 10-10s-4.478-10-10-10c-5.523 0-10 4.477-10 10zm-9.448 9.448c-5.523 0-10 4.477-10 10 0 5.522 4.477 10 10 10s10-4.478 10-10c0-5.523-4.477-10-10-10zM58 67.447c0-5.523-4.477-10-10-10s-10 4.477-10 10 4.477 10 10 10 10-4.477 10-10z"><animateTransform attributeName="transform" type="rotate" from="0 67 67" to="-360 67 67" dur="2.5s" repeatCount="indefinite"/></path><path d="M28.19 40.31c6.627 0 12-5.374 12-12 0-6.628-5.373-12-12-12-6.628 0-12 5.372-12 12 0 6.626 5.372 12 12 12zm30.72-19.825c4.686 4.687 12.284 4.687 16.97 0 4.686-4.686 4.686-12.284 0-16.97-4.686-4.687-12.284-4.687-16.97 0-4.687 4.686-4.687 12.284 0 16.97zm35.74 7.705c0 6.627 5.37 12 12 12 6.626 0 12-5.373 12-12 0-6.628-5.374-12-12-12-6.63 0-12 5.372-12 12zm19.822 30.72c-4.686 4.686-4.686 12.284 0 16.97 4.687 4.686 12.285 4.686 16.97 0 4.687-4.686 4.687-12.284 0-16.97-4.685-4.687-12.283-4.687-16.97 0zm-7.704 35.74c-6.627 0-12 5.37-12 12 0 6.626 5.373 12 12 12s12-5.374 12-12c0-6.63-5.373-12-12-12zm-30.72 19.822c-4.686-4.686-12.284-4.686-16.97 0-4.686 4.687-4.686 12.285 0 16.97 4.686 4.687 12.284 4.687 16.97 0 4.687-4.685 4.687-12.283 0-16.97zm-35.74-7.704c0-6.627-5.372-12-12-12-6.626 0-12 5.373-12 12s5.374 12 12 12c6.628 0 12-5.373 12-12zm-19.823-30.72c4.687-4.686 4.687-12.284 0-16.97-4.686-4.686-12.284-4.686-16.97 0-4.687 4.686-4.687 12.284 0 16.97 4.686 4.687 12.284 4.687 16.97 0z"><animateTransform attributeName="transform" type="rotate" from="0 67 67" to="360 67 67" dur="8s" repeatCount="indefinite"/></path></svg>');
}

.loading-grid {
    background-image: url('data:image/svg+xml,<svg width="105" height="105" viewBox="0 0 105 105" xmlns="http://www.w3.org/2000/svg" fill="#d4f39f"><circle cx="12.5" cy="12.5" r="12.5"><animate attributeName="fill-opacity" begin="0s" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="12.5" cy="52.5" r="12.5" fill-opacity=".5"><animate attributeName="fill-opacity" begin="100ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="52.5" cy="12.5" r="12.5"><animate attributeName="fill-opacity" begin="300ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="52.5" cy="52.5" r="12.5"><animate attributeName="fill-opacity" begin="600ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="92.5" cy="12.5" r="12.5"><animate attributeName="fill-opacity" begin="800ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="92.5" cy="52.5" r="12.5"><animate attributeName="fill-opacity" begin="400ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="12.5" cy="92.5" r="12.5"><animate attributeName="fill-opacity" begin="700ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="52.5" cy="92.5" r="12.5"><animate attributeName="fill-opacity" begin="500ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="92.5" cy="92.5" r="12.5"><animate attributeName="fill-opacity" begin="200ms" dur="1s" values="1;.2;1" calcMode="linear" repeatCount="indefinite" /></circle></svg>');
}

.loading-oval {
    background-image: url('data:image/svg+xml,<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#efe1a4"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></g></svg>');
}

.loading-puff {
    background-image: url('data:image/svg+xml,<svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="#a0d9f1"><g fill="none" fill-rule="evenodd" stroke-width="2"><circle cx="22" cy="22" r="1"><animate attributeName="r" begin="0s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite" /><animate attributeName="stroke-opacity" begin="0s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite" /></circle><circle cx="22" cy="22" r="1"><animate attributeName="r" begin="-0.9s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite" /><animate attributeName="stroke-opacity" begin="-0.9s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite" /></circle></g></svg>');
}

.loading-spinning-circles {
    background-image: url('data:image/svg+xml,<svg width="58" height="58" viewBox="0 0 58 58" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g transform="translate(2 1)" stroke="#FFF" stroke-width="1.5"><circle cx="42.601" cy="11.462" r="5" fill-opacity="1" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="1;0;0;0;0;0;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="49.063" cy="27.063" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;1;0;0;0;0;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="42.601" cy="42.663" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;1;0;0;0;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="27" cy="49.125" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;0;1;0;0;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="11.399" cy="42.663" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;0;0;1;0;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="4.938" cy="27.063" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;0;0;0;1;0;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="11.399" cy="11.462" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;0;0;0;0;1;0" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="27" cy="5" r="5" fill-opacity="0" fill="#efa2dd"><animate attributeName="fill-opacity" begin="0s" dur="1.3s" values="0;0;0;0;0;0;0;1" calcMode="linear" repeatCount="indefinite" /></circle></g></g></svg>');
}

.loading-tail-spin {
    background-image: url('data:image/svg+xml,<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="8.042%" y1="0%" x2="65.682%" y2="23.865%" id="a"><stop stop-color="#f5fda9" stop-opacity="0" offset="0%"/><stop stop-color="#f5fda9" stop-opacity=".631" offset="63.146%"/><stop stop-color="#f5fda9" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)"><path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke="url(#a)" stroke-width="2"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="0.9s" repeatCount="indefinite" /></path><circle fill="#fff" cx="36" cy="18" r="1"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="0.9s" repeatCount="indefinite" /></circle></g></g></svg>');
}

.loading-three-dots{
    background-image: url('data:image/svg+xml,<svg width="120" height="30" viewBox="0 0 120 30" xmlns="http://www.w3.org/2000/svg" fill="#b5edf5"><circle cx="15" cy="15" r="15"><animate attributeName="r" from="15" to="15" begin="0s" dur="0.8s" values="15;9;15" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="1" to="1" begin="0s" dur="0.8s" values="1;.5;1" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="60" cy="15" r="9" fill-opacity="0.3"><animate attributeName="r" from="9" to="9" begin="0s" dur="0.8s" values="9;15;9" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="0.5" to="0.5" begin="0s" dur="0.8s" values=".5;1;.5" calcMode="linear" repeatCount="indefinite" /></circle><circle cx="105" cy="15" r="15"><animate attributeName="r" from="15" to="15" begin="0s" dur="0.8s" values="15;9;15" calcMode="linear" repeatCount="indefinite" /><animate attributeName="fill-opacity" from="1" to="1" begin="0s" dur="0.8s" values="1;.5;1" calcMode="linear" repeatCount="indefinite" /></circle></svg>');
} 

解决Loading效果打开浏览器,一片空白

  • 上面的css代码,background-imageurl()内联SVG留了点坑,浏览器打开会发现一片空白
  • 请注意: svg内容需要被url-转义才能执行,例如。#被替换为%23,即可显示效果

效果

在vue中封装使用svg

1、首先我们创建一个专门放置图标 icon 的文件夹如:@/src/icons,将所有 icon 放在这个文件夹下。 之后我们就要使用到 webpack 的 require.context。很多人对于 require.context可能比较陌生,直白的解释就是

  • require.context("./test", false, /.test.js$/); 这行代码就会去 test 文件夹(不包含子目录)下面的找所有文件名以 .test.js 结尾的文件能被 require 的文件。 更直白的说就是 我们可以通过正则匹配引入相应的文件模块。

require.context有三个参数:

  • directory:说明需要检索的目录
  • useSubdirectories:是否检索子目录
  • regExp: 匹配文件的正则表达式

2、在src目录下创建icons文件及子文件svg和index.js并配置从svg文件夹中读取svg文件

1. 下载插件 svg-sprite-loader

github:github.com/JetBrains/s…

svg-sprite-loader是Webpack加载器,用于创建SVG精灵,可以实现自己的icon组件

它的工作原理是: 利用svg的symbol元素,将每个icon包括在symbol中,通过use元素使用该symbol.

npm i svg-sprite-loader --save

2.vue.config.js (webpack配置)

/*
 * @Descripttion:  vue.config.js的配置
 * @version: 
 */
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
    chainWebpack(config) {
        // config.plugins.delete('preload') // TODO: need test
        // config.plugins.delete('prefetch') // TODO: need test
        // set svg-sprite-loader
        config.module
            .rule('svg')
            .exclude.add(resolve('src/icons'))
            .end()
        config.module
            .rule('icons')
            .test(/\.svg$/)
            .include.add(resolve('src/icons'))
            .end()
            .use('svg-sprite-loader')
            .loader('svg-sprite-loader')
            .options({
                symbolId: 'icon-[name]'
            })
            .end()
    },

}

3.在components公共组件文件夹下创建SvgIcon文件夹下的index.vue并加入以下组件配置代码

index.vue

<!--
 * @Descripttion:  svg组件
 * @version: 
 * @Author: sueRimn
 * @Date: 2019-12-14 15:01:04
 * @LastEditors: sueRimn
 * @LastEditTime: 2019-12-14 19:04:11
 -->
<template>
  <svg :class="svgClass"
       aria-hidden="true"
       v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    iconName () {
      return `#icon-${this.iconClass}`
    },
    svgClass () {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

4、svg文件夹

  • src/icon/Svg

  • 将复制好的svg图标代码放到src下icon文件夹的子文件svg下

<svg t="1576321314655" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5136" width="200" height="200"><path d="M391.25 820.42c21.862 0 39.584-17.726 39.584-39.584 0-21.862-17.722-39.582-39.584-39.582-21.858 0-39.582 17.72-39.582 39.582C351.668 802.694 369.392 820.42 391.25 820.42zM628.754 820.42c21.858 0 39.584-17.726 39.584-39.584 0-21.862-17.724-39.582-39.584-39.582-21.866 0-39.584 17.72-39.584 39.582C589.168 802.694 606.888 820.42 628.754 820.42zM510 10C233.858 10 10 233.858 10 510s223.858 500 500 500 500-223.858 500-500S786.142 10 510 10zM824.774 333.832l-57.484 249.086-19.792 0-435.414 35.418 0 4.166c0 21.86 17.722 39.582 39.584 39.582l455.208 0c0 19.956 0.62 39.582 0 39.582l-178.122 0c43.72 0 79.166 35.444 79.166 79.168 0 43.724-35.444 79.17-79.166 79.17-43.724 0-79.168-35.444-79.168-79.17 0-43.724 35.444-79.168 79.168-79.168L391.25 701.666c43.724 0 79.168 35.444 79.168 79.168 0 43.724-35.444 79.17-79.168 79.17-43.72 0-79.166-35.444-79.166-79.17 0-43.724 35.444-79.168 79.166-79.168l-39.582 0c-43.724 0-79.168-35.442-79.168-79.164L272.5 266.254l-59.374 0c-10.932 0-19.792-8.862-19.792-19.792 0-10.93 8.86-19.798 19.792-19.798l118.75 0c10.928 0 19.792 8.868 19.792 19.798 0 10.93-8.864 19.792-19.792 19.792l-19.792 0 0 39.582 494.792 0c10.93 0 19.792 8.86 19.792 19.792C826.668 328.578 825.932 331.318 824.774 333.832zM312.084 581.358l424.392-33.508 50.606-202.428-475 0L312.082 581.358z" p-id="5137" data-spm-anchor-id="a313x.7781069.0.i8" class="selected" fill="#d4237a"></path></svg>

5、index.js

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon' // svg组件

// register globally 注册为全局组件
Vue.component('svg-icon', SvgIcon)

const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

6、main.js

  • 在main.js中全局引入icon
import '@/icons' // icon

7、在组件中使用

  • iconClass是你保存在iconsvg文件下的svg名称.
<svg-icon iconClass="car"/>

参考