不想了解svg的直接看第六标题即可~
一、SVG是什么
SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。
<svg width="100%" height="100%">
<circle id="mycircle" cx="50" cy="50" r="50" />
</svg>上面代码直接插入网页
SVG 代码也可以写在一个独立文件中,然后用<img>、<object>、<embed>、<iframe>等标签插入网页。
<img src="circle.svg">
<object id="object" data="circle.svg" type="image/svg+xml"></object>
<embed id="embed" src="icon.svg" type="image/svg+xml">
<iframe id="iframe" src="icon.svg"></iframe>二、SVG的顶层标签
SVG 代码都放在顶层标签<svg>之中。
width和height属性,指定了 SVG 图像在 HTML 元素中所占据的宽度和高度。如果不指定这两个属性,SVG 图像的大小默认为300像素(宽)x 150像素(高)。
如果只想展示 SVG 图像的一部分,就要指定viewBox属性。
<svg width="100" height="100" viewBox="50 50 50 50">
<circle id="mycircle" cx="50" cy="50" r="50" />
</svg>
<viewBox>属性的值有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。上面代码中,SVG 图像是100像素宽 x 100像素高,viewBox属性指定视口从(50, 50)这个点开始。所以,实际看到的是右下角的四分之一圆。
注意,视口必须适配所在的空间。上面代码中,视口的大小是 50 x 50,由于 SVG 图像的大小是 100 x 100,所以视口会放大去适配 SVG 图像的大小,即放大了四倍。
如果不指定width属性和height属性,只指定viewBox属性,则相当于只给定 SVG 图像的长宽比。这时,SVG 图像的大小默认是所在的 HTML 元素的大小。
svg定义世界,width定义视窗,viewbox,preserveAspectRatio定义视野,世界是无限的,当视野和视窗不一致时preserveAspectRatio决定怎么样填充的问题
三、SVG的内部标签
<path>的d属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。
- M:移动到(moveto)
- L:画直线到(lineto)
- Z:闭合路径
以上标签全部是用于绘制具体图案,注意一点
SVG 里面标签的 CSS 属性与网页元素有所不同。
- fill:填充色
- stroke:描边色
- stroke-width:边框宽度
四、SVG样式
如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。
<svg
id="mysvg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 800 600"
preserveAspectRatio="xMidYMid meet"
>
<circle id="mycircle" cx="400" cy="300" r="50" />
<svg>
上面代码插入网页之后,就可以用 CSS 定制样式。
circle {
stroke-width: 5;
stroke: #f00;
fill: #ff0;
}
circle:hover {
stroke: #090;
fill: #fff;
}SVG四种样式:
- 内联样式
- 内部样式表
- 外部样式表
- 表现属性
内联样式
用法跟 css 一样,如下所示:
<line style="fill:yellow;stroke:blue;stroke-width=4" x1="10" y1="10" x2="100" y2="100"/>*内部样式表
用法也跟 css 的类名一样,如下所示:
.linestyle{
stroke:red;
stroke-width:2;
}
// 那么在使用标签时,指定此样式即可:
<line class="linestyle" x1="10" y1="10" x2="100" y2="100"/>外部样式表
跟 CSS 用法一样,把样式写在另外文件中,然后导入使用。
表现属性
咱们可能通过 style 属性修改样式,当然 style 里面的属性值,可以单独写,这种也叫表现属性:
<circle cx='10' cy='10' r='5'
fill='red' stroke='black' stroke-width='2'/>SVG内部有fill就不会被覆盖
svg原来的颜色 fill: currentColor; 当前字体颜色
.eyeball {
fill: red;
}Remember:
- This will override a presentation attribute
<path fill="#fff" ... /> - This will not override an inline style e.g.
<path style="fill: #fff;" ... />
继承优先级,“直接样式”比“祖先样式”优先级高
<div style="color: red">
<div class="son" style="color: blue"></div>
</div>五、使用SVG
一般呢我们不会去写一个SVG静态图案,我们一般只是去操作svg文件,下面介绍几个API
1.创建图形: document.createElementNS(ns,tagname)--创建一个具有指定的命名空间URI和限定名称的元素。
2.添加图形:element.appendChild(childElement)
3.设置获取属性:element.set/getAttribute(name,value)
xml命名空间用来避免不同来源名称相同的标签发生冲突。XML 命名空间在 XML 文档顶部使用 xmlns 属性定义
下面三步是icon网站的教程,我们看看是怎么样实现的:
第一步:拷贝项目下面生成的symbol代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
第二步:加入通用css代码(引入一次就行):
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>关键点就在于use标签是什么,xlink明显是命名空间里的,相当于一个herf,#icon-xxx明显在引入js代码时写在里面的,把相应的svg的xml文件抽成symbol标签放到use标签中
六、Vue中使用SVG-雪碧图
一个集合了三个SVG图标的SVG元素的代码结构会是这样:
<svg>
<symbol>
<!-- 第1个图标路径形状之类代码 -->
</symbol>
<symbol>
<!-- 第2个图标路径形状之类代码 -->
</symbol>
<symbol>
<!-- 第3个图标路径形状之类代码 -->
</symbol>
</svg>但是只要上面代码是无法实现icon的,差一个“使用”,也就是SVG中的<use>元素。我们上面已经了解过use,<use>的href属性指定所要复制的节点
use元素是SVG中非常强大,非常重要的一个元素
- 可重复调用;(多写几个use即可)
- 跨SVG调用;(SVG中的
use元素可以调用其他SVG文件的元素,只要在一个文档中。只要href的id写对就行)
跨SVG调用就是“SVG Sprite技术”的核心所在,试想下,我们只要在页面某处载入一个充满Sprite(symbol)的SVG文件(或直接include SVG代码),于是,在页面的任何角落,只要想使用这个图标,只要简单这一点代码就可以了:
<svg class="size">
<use xlink:href="#target" />
</svg>关键就在于怎么把多个svg文件/标签放到一个svg标签里,这就用到了 svg-sprite-loader技术
总结:利用svg的symbol元素,将每个icon包括在symbol中,通过use元素使用该symbol.
七、 svg-sprite-loader
svg-sprite-loader会把你的svg塞到一个个symbol中,symbol的id如果不特别指定,就是你的文件名。它最终会在你的html中嵌入这样一个svg,一般插在body顶部
svg-sprite-loader配置如下:
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
}有一点需要注意的是,我们并不是所有的svg都要放在我们的雪碧图里,有的也许我就想当做图片用。这时候在我们的webpack配置中,我们需要对这两种svg区别对待。
首先,我们要把所有要作为icon的svg团结在一起,放在某个文件夹中,例如assets/icons。其他的svg就随你便啦。
然后对于想要用作图片的:
{
test: /\.svg$/,
loader: 'file-loader',
exclude: path.resolve(__dirname, './src/assets/icons') // 不带icon 玩
}官方文档说的是在webpack开头的文件中操作,但是我们在Vue中没有,所以我们就要将Vue-cli的内容翻译成svg-sprite-loader文档的内容
chainWebpack: config => {
const dir = path.resolve(__dirname, "src/assets/icons");
config.module
.rule("svg-sprite")
.test(/\.svg$/)
.include.add(dir)
.end() // 包含 icons 目录
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({ extract: false })
.end();
// eslint-disable-next-line @typescript-eslint/no-var-requires
config
.plugin("svg-sprite")
// eslint-disable-next-line @typescript-eslint/no-var-requires
.use(require("svg-sprite-loader/plugin"), [{ plainSprite: true }]);
config.module.rule("svg").exclude.add(dir); // 其他 svg loader 排除 icons 目录
}svg-sprite-loader把引入为.svg后缀的文件,集合在一起,插入到body头部,我们用use直接使用即可,由于没有指定id,所以文件名就是href
八、个人实例
<template>
<svg v-if="icon in icons" class="icon">
<use :xlink:href="'#i-'+icon"></use>
</svg>
</template>
<script>
// import 'src/assets/icons/down.svg'
// import 'src/assets/icons/download.svg'
// import 'src/assets/icons/right.svg'
// import 'src/assets/icons/left.svg'
// import 'src/assets/icons/like.svg'
// import 'src/assets/icons/setting.svg'
export default {
data: function () {
return {
icons: {
down: "down",
setting:"setting",
download:"download",
right:"right",
left:"left",
like:"like",
loading:"loading"
}
}
},
props: ['icon']
}
</script>
<style lang="scss" scoped>
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>这个是采用script标签的,采用雪碧loader也可以,标签或者loader会把svg变成symbol都弄到一个svg里,注意v-if的作用
如果你不写v-if,那么如果你想传的svg不存在,还是会出现1em宽高的空白,写了当传错icon名字时就不会有svg这个标签
import Icon from './icon'
Vue.component('g-icon',Icon);<g-icon :icon="icon"></g-icon><script src="//at.alicdn.com/t/font_1660402_gwll4l9vydc.js"></script>你可以由以下script标签把svg都变成symbol集合到一个svg里,也可以自己下载svg自己import自己用雪碧loader,阿里的服务器坏的概率极小,看个人选择
还有一种方法(最推荐),把阿里链接的所有代码复制到svg.js,在Icon组件引入即可