w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com zh-hans w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-intro.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>自从2014年开始陆陆续续的开始就在接触SVG。但由于自身的原因,并没有对SVG进行系统化的学习,在实际的工作项目中并未真正的使用SVG相关的技术。为了储备相关的知识,并尝试在项目中使用SVG,有必要对该技术进行系统化的梳理和学习。所以开始每周会抽出大半的时间来学习和整理SVG相关的知识,希望在几个月后,这方面的技术有所突破。</p> <blockquote> <p>为了能记录SVG的学习和探索过程,整个学习的路径以及笔记将会在W3cplus的SVG之旅中分享出来。希望对喜欢SVG的同学有所帮助。如果您是这方面的专家,欢迎分享您的经验。</p> </blockquote> <p>要学习SVG相关的知识,那么就很有必要的知道,SVG是什么?今天我们就简单的来介绍SVG是什么?</p> <h2>图形系统</h2> <p>计算机中描述图形的信息主要有两大系统:<strong>栅格图形和矢量图形</strong>。</p> <h3>栅格图形</h3> <p>栅格图形(Raster Graphics)又常称为位图或点阵图,是使用像素阵列(Pixel-Array / Dot-Matrix点阵)来表示图像。其实栅格图形也是一种数据结构,代表了有限区域中的稠集(Dense Set),每一个元素至少出现一次,没有其他的数据和元素相关联。在索引,数据压缩等方面有广泛应用。</p> <p>栅格图形系统中,图像被表示为图片元素或者像素的长方形数组。而栅格图像的像素部分都分配有特定的<strong>位置</strong>和<strong>颜色值</strong>。每个像素的颜色信息由RGB组合或者灰度值表示。</p> <p>根据位深度,可将栅格图形分为<code>1</code>、<code>4</code>、<code>8</code>、<code>16</code>、<code>24</code>和<code>32</code>位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量就越大。比如,位深度为<code>1</code>的像素位图只有两个可能的值(黑色和白色),所以又称之为<strong>二值位图</strong>。位深度为<code>8</code>的图像有<code>2</code>的<code>8</code>次方个可能的值(也就是<code>256</code>)。位深度为 <code>8</code> 的灰度模式图像有 <code>256</code> 个可能的灰色值。</p> <p>RGB图像由三个颜色通道组成。<code>8</code> 位/像素的 RGB 图像中的每个通道有 <code>256</code> 个可能的值,这意味着该图像有 <code>1600</code> 万个以上可能的颜色值。有时将带有 <code>8</code> 位/通道 (<code>bpc</code>) 的 RGB 图像称作 <code>24</code> 位图像(<code>8 位 x 3 通道 = 24 位数据/像素</code>)。通常将使用<code>24</code>位RGB组合数据位表示的的位图称为真彩色位图。</p> <p>在浏览器还没有对SVG这样的矢量图进行支持之前,我们在Web中使用的图像都是<strong>栅格图形</strong>,比如<code>jpg</code>和<code>gif</code>等格式的图形。栅格图形的再现能力较强,但是在某些情形下会显得不足。比如,当浏览器以不同大小显示图像时,特别是当一张小图放大显示时,通常会产生锯齿边缘。也就是我们常说的,致使图像失真。</p> <h3>矢量图形</h3> <p><strong>矢量图形</strong>是计算机图形学中用<strong>点、直线或者多边形等基于数学方程的几何图元表示图像</strong>。简单地说,在矢量图形系统中,图像被<strong>描述为一系列几何形状</strong>。矢量图形阅读器接受在指定坐标集上绘制形状的指令,而不是接受一系列已计算好的像素。</p> <p>通俗的说:矢量图通过指定为确定每个像素的值所需的指令而不是指定这些值本身,克服了这些困难中的一部分。例如,向量图形不再为一个直径一英寸的圆提供像素值,而是告诉浏览器创建一个直径一英寸的圆,然后让浏览器(或插件)做其余事情。这消除了光栅图形的许多限制;使用向量图形,浏览器只要知道它必须画一个圆。如果图像需要以正常大小的三倍来显示,那么浏览器只要按正确的大小画圆而不必执行光栅图像通常的插入法。类似地,浏览器接收的指令可以更容易地与外部信息源(如应用程序和数据库)绑定,要对图像制作动画,浏览器只要接收有关如何操纵属性(如半径或颜色)的指令即可。</p> <p>矢量图形相对于栅格图形而言,具有以下几个优势:</p> <ul> <li>保存最少的信息,文件大小比位图要小,并且文件大小与物体的大小无关</li> <li>在图像处理软件中,任意放大矢量图形,不会丢失细节或影响清晰度,因为矢量图形是与分辨率无关的。无限地放大这个圆,它仍然保持平滑;用多边形表示的曲线将会显现出不是真正的曲线</li> <li>在放大的时候,直线与曲线都不会成比例地变粗,它只会保持不变或者要小于缩放比例;为了看起来比较平滑,使用简单几何形状表示的不规则曲线将会成比例地变粗,并且看起来不再像这些几何形状</li> <li>保存的物体参数可以在后面修改。这也就是说物体的运动、缩放、旋转、填充等都不会降低绘制的精度。另外,可以用与设备无关的单位表示,这样更好地栅格设备上进行栅格化。</li> <li>从三维的视角来看,由于阴影可以抽象为形成它们的光线,所以矢量图形的阴影渲染更加真实。这样就可以得到真实感的图像及渲染效果。</li> <li>当调整矢量图形的大小、将矢量图形打印到 PostScript 打印机、在 PDF 文件中保存矢量图形或将矢量图形导入到基于矢量的图形应用程序中时,矢量图形都将保持清晰的边缘。因此,对于将在各种输出媒体中按照不同大小使用的图稿(如徽标),矢量图形是最佳选择。</li> </ul> <p>用一张图来形象的表示矢量图和栅格图的区别:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-ch1-1.jpg" alt="SVG简介" /></p> <p><em>左边的是矢量图,右边的是栅格图</em></p> <p>而我们所要学的SVG就是矢量图形,也常称之为<strong>可缩放矢量图形</strong>(Scalable Vector Graphics,简称SVG)。那么什么是SVG?这也是今天我们主要要了解的东东。</p> <h2>SVG是什么?</h2> <p><strong><a href="http://xxysy.com/quot;//developer.mozilla.org/en/SVG">SVG</a>是<" href="http://xxysy.com/quot;//developer.mozilla.org/en/XML">XML</a>语言</strong>的一种形式,有点类似XHTML,它可以用来绘制矢量图形,例如下图。SVG可以通过定义必要的线和形状来创建一个图形,也可以修改已有的位图,或者将这两种方式结合起来创建图形。图形和其组成部分可以变形,可以合成,还可以通过滤镜完全改变外观。</p>" <p><img src="/sites/default/files/blogs/2017/1712/svg-ch1-2.png" alt="SVG简介" /></p> <p>SVG推出于1999年,之前有几个相互竞争的格式规范被提交到<a href="http://xxysy.com/quot;//www.w3.org/">W3C</a>,但是由于之前1998年提交给W3C的<" href="http://xxysy.com/quot;//zh.wikipedia.org/w/index.php?title=PGML&amp;action=edit&amp;redlink=1">PGML</a>、<" href="http://xxysy.com/quot;//zh.wikipedia.org/wiki/VML">VML</a>标准构成竞争,所以造成SVG的标准没有完全通过。当下的浏览器支持程度请参考<" href="http://xxysy.com/quot;//caniuse.com/#search=svg">Ca" I use</a>。即便浏览器实现了一些规范,但实现速度完全不能和它的竞争技术相比,它的竞争技术比如说<a href="http://xxysy.com/quot;//developer.mozilla.org/en/HTML/Canvas">HTM" Canvas</a>,都已经实现了成熟的应用接口。但是SVG也有自身的优点,比如它实现了DOM接口(比Canvas方便),不需要安装第三方插件就可以在浏览器中使用。当然,是否使用SVG还要取决于你要实现什么。</p> <p>SVG严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。SVG允许3种图形对象类型:矢量图形、栅格图像以及文本。图形对象——包括PNG、JPEG这些栅格图像——能够被编组、设计、转换及集成进先前的渲染对象中。文本可以在任何适用于应用程序的XML命名空间之内,从而提高SVG图形的搜索能力和无障碍性。SVG提供的功能集涵盖了嵌套转换、裁剪路径、Alpha通道、滤镜效果、模板对象以及可扩展性。</p> <p>SVG绘图是交互式和动态的。 例如,可使用脚本来定义和触发动画。这一点与Flash相比很强大。Flash是二进制文件,动态创建和修改都比较困难。而SVG是文本文件,动态操作是相当容易的。而且,SVG直接提供了完成动画的相关元素,操作起来非常方便。</p> <p>SVG与其他Web标准兼容,并直接支持文档对象模型DOM。这一点也是与HTML5中的Canvas相比很强大的地方。因而,可以很方便的使用脚本实现SVG的很多高级应用。而且SVG的图形元素基本上都支持DOM中的标准事件。可将大量事件处理程序(如<code>onmouseover</code>和<code>onclick</code>)分配给任何SVG图形对象。 虽然SVG的渲染速度比不上<code>canvas</code>元素,但是胜在DOM操作很灵活,这个优势完全可以弥补速度上的劣势。</p> <h3>SVG优点</h3> <p>SVG主要具有以下几个优点:</p> <ul> <li>图像文件可读,易于修改和编辑(理论上如此,但实际上却是因为各种不同的SVG档编辑器而可能存储成不易解读的SVG文件)</li> <li>与现有技术可以互动融合。例如,SVG技术本身的动态部分(包括时序控制和动画)就是基于SMIL标准。另外,SVG文件还可嵌入JavaScript(严格地说,应该是ECMAScript)脚本来控制SVG对象</li> <li>SVG图形格式可以方便的创建文字索引,从而实现基于内容的图像搜索</li> <li>SVG图形格式支持多种滤镜和特殊效果,在不改变图像内容的前提下可以实现位图格式中类似文字阴影的效果</li> <li>SVG图形格式可以用来动态生成图形。例如,可用SVG动态生成具有交互功能的地图,嵌入网页中,并显示给终端用户</li> </ul> <h3>SVG缺点</h3> <p>SVG有优点也一定会有一些缺点,其缺点主要有:</p> <ul> <li>如何和已经占有重要市场份额的矢量图形格式Adobe Animate竞争的问题。</li> <li>SVG的本地运行环境下的厂家支持程度。</li> <li>由于原始的SVG档是遵从XML语法,导致数据采用未压缩的方式存放,因此相较于其他的矢量图形格式,同样的文件内容会比其他的文件格式稍大。Adobe因此使用<code>gzip</code>压缩开发出压缩的SVG档格式,附档名为 <code>.svgz</code>, 但此种文件格式除了Adobe旗下的软件以外,未被广泛支持使用。</li> <li>旧版的SVG Viewer无法正确显示出使用新版SVG格式的矢量图形。</li> </ul> <h2>SVG在Web中的表现方式</h2> <p>在整个系列,我们默认是浏览器对SVG支持,不做过多的讨论。SVG提供了类似HTML的DOM形式。众所周知,HTML提供了标题、段落、表格等内容的元素。与此类似,在SVG中也提供了一些元素,比如用于定义圆、矩形、曲线和多边形等。一个简单的SVG文档由<code>&lt;svg&gt;</code>根元素(相当于<code>&lt;html&gt;</code>根元素)和基本的形状元素构成。另外还有一个<code>&lt;g&gt;</code>元素,用来把若干个基本形状编写成一个组。</p> <p>对于Web页面或Web应用程序中使用SVG,主要采取的方式由<strong>内联到HTML</strong>和<strong>引用外部的独立的<code>.svg</code>文件</strong>。对于内联到HTML方式,可以像我们平时使用HTML元素一样,直接在HTML代码中使用<code>&lt;svg&gt;</code>和其相关的图形元素。比如:</p> <pre><code>&lt;svg width="100%" height="200"&gt; &lt;rect width="100%" height="100%" fill="red" /&gt; &lt;circle cx="50%" cy="100" r="80" fill="green" /&gt; &lt;text x="50%" y="125" font-size="60" text-anchor="middle" fill="white"&gt;SVG&lt;/text&gt; &lt;/svg&gt; </code></pre> <div style="margin-bottom: 20px;border: 1px solid #ccc; padding: 2px;"> <svg width="100%" height="200"> <rect width="100%" height="100%" fill="red" /> <circle cx="50%" cy="100" r="80" fill="green" /> <text x="50%" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text> </svg> </div> <p>除此之外,你可以把上面的<code>&lt;svg&gt;</code>的所有代码复制到一个编辑器中,然后保存成一个<code>.svg</code>的文件。然后在HTML页面中通过<code>&lt;img&gt;</code>、<code>&lt;object&gt;</code>和<code>&lt;iframe&gt;</code>元素引用到<code>.svg</code>文件。你也可以在CSS中通过<code>background-image</code>和<code>border-image</code>这样的属性来引用独立的<code>.svg</code>文件。用来装饰HTML中的元素。而且你也可以通过JavaScript动态创建SVG,并注入到HTML DOM中。这样有一个优点,可以对浏览器使用替代技术,在不能解析SVG的情况下,可以替换创建的内容。</p> <blockquote> <p>这里提前声明一下,此系列后续的文章,我们介绍的都是内联到HTML的SVG。除非有特别的声明。</p> </blockquote> <h2>SVG文件类型</h2> <p>SVG也具有自己的文件类型格式。SVG文件主要有两种形式。普通SVG文件是包含SVG标记的简单文本文件。推荐使用<code>.svg</code>作为此类文件的扩展名。</p> <p>由于在某些应用(比如地图应用等)中使用时,SVG文件可能会很大,SVG标准同样允许<code>gzip</code>压缩的SVG文件。推荐使用<code>.svgz</code>作为此类文件扩展名 。使用<code>gzip</code>压缩的SVG文件格式,需要注意服务器相关的配置。如果服务器配置错误会引起SVG加载失败。不过这里我们不做过多的讨论(在这方面我也是小白)。</p> <h2>SVG的种类</h2> <p>自从2003年成为W3C推荐标准以来,最接近的“完整版”SVG版本是<a href="http://xxysy.com/quot;//www.w3.org/TR/SVG11/">1.1版</a>,它基于1.0版,并且增加了更多便于实现的模块化内容,SVG1.1的第二个版本在2011年成为推荐标准,完整的<" href="http://xxysy.com/quot;//www.w3.org/TR/SVG12/">SVG1.2</a>本来是下一个标准版本,但它又被<" href="http://xxysy.com/quot;//www.w3.org/TR/SVG2/">SVG2.0</a>取代。<" href="http://xxysy.com/quot;//www.w3.org/standards/techs/svg#w3c_all">SVG2.0正在制定当中</a>,它采用了类似CSS3的制定方法,通过若干松散耦合的伟德1946手机版形成一套标准。</p>" <p>除了完整的SVG推荐标准,W3C工作组还在2003年推出了<a href="http://xxysy.com/quot;//www.w3.org/TR/SVGMobile/">SV" Tiny和SVG Basic</a>。这两个配置文件主要瞄准移动设备。首先SVG Tiny主要是为性能低的小设备生成图元(比如移动端),而SVG Basic实现了完整版SVG里的很多功能,只是舍弃了难以实现的大型渲染(比如动画)。2008年,<a href="http://xxysy.com/quot;//www.w3.org/TR/SVGTiny12/">SV" Tiny1.2成为W3C推荐标准</a>。</p> <h2>开始编写SVG之前</h2> <p>市面上有很多应用软件,比如Inkscape、Adobe Illustrator和Sketch等都可以支持SVG格式的文件,也可以使用这些制图软件,绘制矢量图形,然后导出SVG格式的文件(只是导出的SVG文件会产生一定的垃圾代码,需要手工或者通过一定的工具来处理,这部分我们后续将会涉及到)。但是此系列建议在学习过程中使用文本编辑器。因为只有手动去写SVG代码,才能更好的理解SVG内部的原理。这也是我们学习SVG的最终目标。</p> <p>各种浏览器对SVG的渲染是有所差异的,但后系的SVG只在Chrome浏览器(当然后续会研究SVG在手淘这样的APP中的应用)。其次,还可以将JavaScript和CSS相关的技术结合一起来用SVG。这将是我们最期待,也是将是最有意思的一部分内容。比如怎么通过CSS来控制SVG的风格,怎么通过JavaScript来更好的控制SVG的动画。</p> <p>在正式开始之前,你需要基本掌握HTML这样的标记语言,最好是对XML有一定的了解,如果你和我一样对XML不是很熟悉,那么在手动编写SVG代码时需要记住:</p> <ul> <li>SVG的元素和属性必须按标准格式书写,因为XML是区分大小写的(这一点和HTML不同)</li> <li>SVG里的属性值必须用引号引起来,就算是数值也必须这样做</li> </ul> <p>SVG是一个庞大的规范,我们将会从入门级别开始,一旦我们掌握了这此基础内容,我们将继续学习更复杂的部分,从而系统的掌握SVG相关的内容,也是我们学习SVG的最终目标。</p> <h2>学习SVG相关资料</h2> <ul> <li><a href="http://xxysy.com/quot;//www.w3.org/TR/SVG2/">W3C的SVG规" V2.0</a></li> <li><a href="http://xxysy.com/quot;//learn-the-web.algonquindesign.ca/topics/advanced-svg/">Advance" SVG</a></li> <li><a href="http://xxysy.com/quot;//tutorials.jenkov.com/svg/index.html">Jakob'" SVG Tutorial</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/SVG/Tutorial">MDN" SVG Tutorial</a></li> <li><a href="http://xxysy.com/quot;//medium.com/tag/svg">Medium" SVG Tag</a></li> <li><a href="http://xxysy.com/quot;//dev.w3.org/SVG/tools/svgweb/samples/svg-files/">SV" Examples</a></li> <li><a href="http://xxysy.com/quot;//codepen.io/tag/svg/">Codepen" SVG Demo</a></li> <li><a href="http://xxysy.com/quot;//tympanus.net/codrops/tag/svg/">Codrops" SVG Tag</a></li> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg-tutorial">W3cplus的SVG伟德1946网页版</a></li>" </ul> <h2>总结</h2> <p>通过这篇文章的学习,我们简单的了解了图形系统中的两大系统:栅格图形和矢量图形。并且知道两者之间的区别。最主要的了解SVG的一些概况,对SVG有了一个初步的认识。就算是阅读到文章的末尾,可能还是无法写出任何SVG相关的代码,还是不会用SVG绘制矢量图。但这一切都不是问题,随着后面的学习,我相信我们都能做到。比如给自己定一个小目标,经过对SVG的学习,我们可以写出像下面这样的SVG效果:</p> <div style="margin-bottom: 20px;"><iframe id="vpOyjj" src="//codepen.io/airen/embed/vpOyjj?height=400&amp;theme-id=0&amp;slug-hash=vpOyjj&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-intro.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-intro.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/html5"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">HTML5</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/svg-tutorial"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/647.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG之旅</a></div></div></div> Thu, 14 Dec 2017 15:24:04 +0000 Airen 2325 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/custom-directive.html%29 <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>在Vue中为了更好的操作DOM元素,其内置了一些指令,比如<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-model.html"><code>v-model</code></a>、<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-if-vs-v-show.html"><code>v-if</code>、<code>v-show</code></a>、<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-text-and-v-html.html"><code>v-text</code>、<code>v-html</code></a>、<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-for.html"><code>v-for</code></a>和<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-bind.html"><code>v-bind</code></a>等。除此之外,Vue也允许注册自定义指令。这些自定义指令可以说我们对普通DOM元素进行底层操作。比如@SARA" DRASNER写的一篇有关于<a href="//css-tricks.com/power-custom-directives-vue/">Vue自定义指令的文章</a>,简单易懂。今天自己也仔细撸了一下Vue中怎么实现自定义的指令。</p> <h2>钩子函数</h2> <p>创建自定义指令,在Vue中一个指令定义对象可以提供下面几个钩子函数,而这几个钩子函数都是可选的:</p> <ul> <li><strong><code>bind</code></strong>:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置</li> <li><strong><code>inserted</code></strong>:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)</li> <li><strong><code>update</code></strong>:所在伟德1946手机版的<code>VNode</code>更新时调用,<strong>但是可能发生在其子<code>VNode</code>更新之前</strong>。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新</li> <li><strong><code>componentUpdated</code></strong>:指令所在伟德1946手机版的<code>VNode</code>及其子<code>VNode</code>全部更新后调用</li> <li><strong><code>unbind</code></strong>:只调用一次,指令与元素解绑时调用</li> </ul> <p><img src="/sites/default/files/blogs/2017/1712/vue-cutom-directive.svg" alt="自定义指令" /></p> <p><em>上图来自于《<a href="//css-tricks.com/power-custom-directives-vue/">The Power of Custom Directives in Vue</a>》一文。</em></p> <p>来看一个简单的示例,看看这些钩子函数的触发时机。</p> <p>至于怎么自定义一个指令,先不阐述。在Vue中通过<code>Vue.directive('directiveName', {...})</code>方式来注册一个指令。在实际调用的时候需要前面添加<code>v-</code>来使用。有关于这方面的细节,我们稍后再阐述。</p> <pre><code>Vue.directive('hello', { // 只调用一次,指令第一次绑定到元素时调用 bind: function (el) { console.log('触发bind钩子函数!') }, // 被绑定元素插入父节点时调用 inserted: function (el) { console.log('触发inserted钩子函数!') }, // 所在伟德1946手机版的`VNode`更新时调用,但是可能发生在其子元素的`VNode`更新之前 update: function (el) { console.log('触发update钩子函数!') }, // 所在伟德1946手机版的`VNode`及其子元素的`VNode`全部更新时调用 componentUpdated: function (el) { console.log('触发componentUpdated钩子函数!') }, // 只调用一次,指令与元素解绑时调用 unbind: function (el) { console.log('触发unbind钩子函数!') } }) let myComponent = { template: '&lt;h1 v-hello&gt;{{ message }}&lt;/h1&gt;', props: { message: String } } let app = new Vue({ el: '#app', data () { return { message: 'Hello! 大漠' } }, components: { myComponent: myComponent }, methods: { update: function () { this.message = 'Hi! 大漠' }, uninstall: function () { this.message = '' }, install: function () { this.message = 'Hello!W3cplus' } } }) &lt;div id="app"&gt; &lt;my-component v-if="message" :message="message"&gt;&lt;/my-component&gt; &lt;div class="actions"&gt; &lt;button @click="update"&gt;更新&lt;/button&gt; &lt;button @click="uninstall"&gt;卸载&lt;/button&gt; &lt;button @click="install"&gt;安装&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> <div style="margin-bottom: 20px;"><iframe id="aEzpdK" src="//codepen.io/airen/embed/aEzpdK?height=400&amp;theme-id=0&amp;slug-hash=aEzpdK&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>当页面加载时就触发了<code>bind</code>和<code>inserted</code>两个钩子函数:</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-1.png" alt="自定义指令" /></p> <p>当我们点击“更新”按钮,将会更改<code>message</code>的值,会触发伟德1946手机版<code>myComponent</code>更新。</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-2.png" alt="自定义指令" /></p> <p>这个时候触发了<code>update</code>和<code>componentUpdated</code>两个钩子函数。</p> <p>接下来我们再点击“卸载”按钮,<code>message</code>的数据将会置空,这个时候传给<code>v-if</code>的值为<code>false</code>,将会触发伟德1946手机版<code>myComponent</code>伟德1946手机版卸载。</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-3.png" alt="自定义指令" /></p> <p>此时触发了<code>unbind</code>钩子函数。</p> <p>最后我们再点击“安装”按钮,<code>message</code>将会重新被赋值,触发<code>myComponent</code>伟德1946手机版重新安装。</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-4.png" alt="自定义指令" /></p> <p>这个时候触发了<code>bind</code>和<code>inserted</code>两个钩子函数。</p> <p>通过上面这个简单的示例,我们对五个钩子函数的触发时间有了一个初步的认识。对于我这样的初学者而言,对<code>bind</code>和<code>inserted</code>、<code>update</code>和<code>componentUpdated</code>之间的区别还是存在一定的疑问。为了解惑,在上面的示例的基础上,再来做简单的测试。</p> <p>首先来看<code>bind</code>和<code>inserted</code>之间的区别,Vue的官网文档是这样对两个钩子函数进行描述的:</p> <ul> <li><strong><code>bind</code></strong>:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置</li> <li><strong><code>inserted</code></strong>:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)</li> </ul> <p>修改一下上例中的代码:</p> <pre><code>bind: function (el) { console.log(el.parentNode) console.log('触发bind钩子函数!') }, inserted: function (el) { console.log(el.parentNode) console.log('触发inserted钩子函数!') } </code></pre> <div style="margin-bottom: 20px;"><iframe id="BJypXR" src="//codepen.io/airen/embed/BJypXR?height=400&amp;theme-id=0&amp;slug-hash=BJypXR&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-5.png" alt="自定义指令" /></p> <p>从上图中我们可以看出,在<code>bind</code>钩子函数被触发时,其父节点为<code>null</code>,而<code>inserted</code>钩子函数触发时,父节点是存在的。</p> <p>再来看<code>update</code>和<code>componentUpdated</code>两个钩子函数间的区别,同样先来看官方规范的描述:</p> <ul> <li><strong><code>update</code></strong>:所在伟德1946手机版的<code>VNode</code>更新时调用,<strong>但是可能发生在其子<code>VNode</code>更新之前</strong>。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新</li> <li><strong><code>componentUpdated</code></strong>:指令所在伟德1946手机版的<code>VNode</code>及其子<code>VNode</code>全部更新后调用</li> </ul> <p>从描述来看,这两个钩子函数都和伟德1946手机版更新周期有关。同样的,基于前面的示例,修改一下<code>update</code>和<code>componentUpdated</code>两个钩子函数中的代码:</p> <pre><code>update: function (el) { console.log(el.parentNode) console.log(el.innerHTML) console.log('触发update钩子函数!') }, componentUpdated: function (el) { console.log(el.parentNode) } </code></pre> <div style="margin-bottom: 20px;"><iframe id="BJypXR" src="//codepen.io/airen/embed/BJypXR?height=400&amp;theme-id=0&amp;slug-hash=BJypXR&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>从控制台输出的结果可以看出<code>update</code>和<code>componentUpdated</code>两个钩子函数就是伟德1946手机版更新前和更新后的区别。</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-6.png" alt="自定义指令" /></p> <p>前面也提到过了,创建Vue的自定义指令的这五个钩子函数都是可选的,不一定要全部出现。而这其中<code>bind</code>和<code>update</code>两个钩子函数是最有用的。在实际使用的时候,我们应该根据需求做不同的选择。比如在恰当的时间通过<code>bind</code>钩子函数去初始化实例,<code>update</code>钩子函数去做对应的参数更新和使用<code>unbind</code>钩子函数去释放实例资源占用等。</p> <p>另外,这些钩子函数都带有参数,即<code>el</code>、<code>binding</code>、<code>vnode</code>和<code>oldVnode</code>。</p> <ul> <li><code>bind(el, binding, vnode)</code></li> <li><code>inserted(el, binding, vnode)</code></li> <li><code>update(el, binding, vnode, oldVnode)</code></li> <li><code>componentUpdated(el, binding, vnode, oldVnode)</code></li> <li><code>unbind(el, binding, vnode)</code></li> </ul> <p>接下来我们看看钩子函数的参数。</p> <h2>钩子函数参数</h2> <p>指令钩子函数会被传入以下参数:</p> <ul> <li><strong><code>el</code></strong>:指令所绑定的元素,可以用来直接操作DOM</li> <li><strong><code>binding</code></strong>:一个对象,这个对象包含一些属性,稍后列出每个属性的含义</li> <li><strong><code>vnode</code></strong>:Vue编译生成的虚拟节点。有关于<code>VNode</code>更多的资料,可以阅读<a href="http://xxysy.com/quot;//cn.vuejs.org/v2/api/#VNode-%E6%8E%A5%E5%8F%A3"><code>VNode</code>相关的API</a></li>" <li><strong><code>oldVnode</code></strong>:上一个虚拟节点,仅在<code>update</code>和<code>componentUpdated</code>两个钩子函数中可用</li> </ul> <p><code>binding</code>参数是一个对象,其包含以下一些属性:</p> <ul> <li><strong><code>name</code></strong>:指令名,不包括<code>v-</code>前缀</li> <li><strong><code>value</code></strong>:指令的绑定值,如例<code>v-hello = "1 + 1"</code>中,绑定值为<code>2</code></li> <li><strong><code>oldValue</code></strong>:指令绑定的前一个值,仅在<code>update</code>和<code>componentUpdated</code>钩子中可用,无论值是否改变都可用</li> <li><strong><code>expression</code></strong>:字符串形式的指令表达式。例如<code>v-hello = "1 + 1"</code>中,表达式为<code>"1 + 1"</code></li> <li><strong><code>arg</code></strong>:传给指令的参数,可选。例如<code>v-hello:message</code>中,参数为<code>"message"</code></li> <li><strong><code>modifiers</code></strong>:一个包含修饰符的对象。例如<code>v-hello.foo.bar</code>中,修饰符对象为<code>{foo:true, bar:true}</code></li> </ul> <blockquote> <p>除了 <code>el</code> 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 <code>dataset</code> 来进行。</p> </blockquote> <p>在很多时候,你可能想在 <code>bind</code> 和 <code>update</code> 时触发相同行为,而不关心其它的钩子。比如这样写:</p> <pre><code>Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value }) </code></pre> <p>如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式。</p> <pre><code>&lt;div v-demo="{ color: 'white', text: 'hello!' }"&gt;&lt;/div&gt; Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // =&gt; "white" console.log(binding.value.text) // =&gt; "hello!" }) </code></pre> <h2>创建一个自定义指令</h2> <p>接下来,咱们来通过实例来看看怎么创建Vue的自定义指令。</p> <p>模态(Modal)伟德1946手机版是我们经常看得到的伟德1946手机版。该Modal伟德1946手机版包含了一些文本输入框,而这个输入框是根据<code>v-for</code>指令动态生成。当切换到可见状态时,第一个输入框将会自动获得焦点。</p> <p>实现自动获取第一个输入框得到焦点,此时需要一个自定义指令,这里把他称为<strong><code>v-focus</code></strong>指令。</p> <pre><code>// 首先需要注册一个新指令,它会自动添加v-前缀 Vue.directive('focus', { componentUpdated: function (el, binding, vnode) { // 当binding.value 绑定的值为true,文本框获取焦点 if (binding.value) { el.focus() } } }) </code></pre> <p>添加Modal伟德1946手机版的基本代码:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { fields: [ '姓名', '邮箱', '地址', '电话' ], modalIsOpen: false } }, methods: { toggleModal: function () { this.modalIsOpen = !this.modalIsOpen } }, computed: { buttonText: function () { return this.modalIsOpen ? '关闭' : '打开' } } }) </code></pre> <p>在HTML中写入所需要的模板:</p> <pre><code>&lt;div id="app"&gt; &lt;button @click="toggleModal"&gt;{{ buttonText }}&lt;/button&gt; &lt;transition name="modal-toggle"&gt; &lt;div class="modal" v-show="modalIsOpen"&gt; &lt;input type="text" v-for="(field, key) in fields" v-focus="key === 0" :placeholder="field" /&gt; &lt;/div&gt; &lt;/transition&gt; &lt;/div&gt; </code></pre> <p>最终效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="aEzwWa" src="//codepen.io/airen/embed/aEzwWa?height=400&amp;theme-id=0&amp;slug-hash=aEzwWa&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>打开Modal框时,第一个输入框将自动会获得焦点:</p> <p><img src="/sites/default/files/blogs/2017/1712/vue-custom-directives-7.gif" alt="自定义指令" /></p> <p>大家记得<code>&lt;textarea&gt;</code>这样的表单控件元素,我们有一个属性<code>maxlength</code>属性,用来控制表单控件最长输入的字符数。如果不设置这个属性,我们可以使用Vue自定义的指令来完成,比如我们创建一个<code>v-maxchars</code>的指令。</p> <pre><code>Vue.directive('maxchars', { bind: function (el, binding, vnode) { let maxChars = binding.expression let handler = function (e) { if (e.target.value.length &gt; maxChars) { e.target.value = e.target.value.substr(0, maxChars) } } el.addEventListener('input', handler) } }) </code></pre> <p>比如我们来做一个Twitter发推的小伟德1946手机版:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { imgUrl: '//pbs.twimg.com/profile_images/468783022687256577/eKHcWEIk_normal.jpeg', content: '', totalcount: 140 } }, computed: { reduceCount () { return this.totalcount - this.content.length } } }) </code></pre> <p>对应的模板:</p> <pre><code>&lt;div id="app"&gt; &lt;div class="twitter"&gt; &lt;img :src="imgUrl" /&gt; &lt;div class="content"&gt; &lt;textarea v-model="content" v-maxchars="140"&gt;有什么新鲜事情?&lt;/textarea&gt; &lt;p&gt;您还可以输入{{ reduceCount }}字&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="jYELOz" src="//codepen.io/airen/embed/jYELOz?height=400&amp;theme-id=0&amp;slug-hash=jYELOz&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>感兴趣的同学,可以体验一下。当你输入到第<code>141</code>个字的时候,将无法继续输入。</p> <p>上面我们看到的都是通过<code>Vue.directive('your-directive-name', {...})</code>注删的全局自定义指令。除此之外,还可以在伟德1946手机版中使用<code>directives</code>的选项,注册一个局部的自定义指令。</p> <pre><code>directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } } </code></pre> <h2>总结</h2> <p>在Vue中除框架自带的一些内置指令可以操作DOM之外,还可以通过Vue的<code>Vue.directive()</code>和伟德1946手机版的<code>directives</code>选项,分别注册一个全局指令和局部指令。每个指令都有五个钩子函数。这些函数可以帮助我们实现所需要的自定义指令功能。文章末尾通过两个简单的示例,演示了在Vue中怎么创建自定义的指令,以及如何使用这些自定义的指令。</p> <p>由于自身是Vue的初学者,如果文章中有不对之处,还请各路大婶拍正,如果你在这方面有更好的建议或经验,欢迎在下面的评论中与我们一起分享。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/custom-directive.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/custom-directive.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Wed, 13 Dec 2017 15:34:25 +0000 Airen 2324 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sass/hexi-flexi-grid.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>在《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/preprocessor/creat-css-polygon-wiht-border-and-clip-path-property.html">Sass绘制多边形</a>》和《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/preprocessor/diamond-grid-using-sass.html">使用Sass制作菱形网格布局</a>》文章中,我们了解了怎么通过Sass来实现多边形和菱形相关的网格布局,但这些在实际的布局中使用场景并不常见。最近<" href="http://xxysy.com/quot;//github.com/vmcreative">@vmcreative</a>的<" href="http://xxysy.com/quot;//github.com/vmcreative/Hexi-Flexi-Grid">Hex" Flexi Grid</a>让我感到<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/355.html">CS" Grid</a>布局更强大的一面。而这种布局在实际的布局也可以一用。今天把这个仓库中的功能集成了<a href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic">SassMagic</a>中。那么简单的花点时间来看看Hex" Flexi Grid布局。</p> <h2>案例</h2> <p>先上一个Demo的效果:</p> <div style="margin-bottom: 20px;"><iframe id="opNzEW" src="//codepen.io/airen/embed/opNzEW?height=400&amp;theme-id=0&amp;slug-hash=opNzEW&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>简单点说就是一个六边形的网格布局。</p> <h2>简介</h2> <p>Hexi Flexi Grid是一个SCSS伟德1946手机版,它是基于CSS的网格布局上创建了一个六边形的网格布局。为这样的布局创建了一个<code>@mixin</code>,而这个<code>@mixin</code>包含了许多可定制的设置,这些设置主要用来控制六边形网格的大小、布局和外观效果等。</p> <h2>特性</h2> <p>Hexi Flexi Grid布局具有一定的特性:</p> <ul> <li>纯CSS实现的六边形网格布局,没有任何的JavaScript代码</li> <li>灵活的高度、宽度、列和行数</li> <li>单个单元格、列和行具有独特的样式</li> <li>支持自动背景图像</li> </ul> <h2>支持的浏览器</h2> <p>如果你阅读了Hexi Flexi Grid布局的SCSS源码,你不难发现,其中运用的CSS技术,其关键点通过CSS Grid的布局技术实现布局,然后通过<code>clip-path</code>来实现六边形。从而创建了一个网格形的六边形布局。而这两个属性都是CSS的最新特性。如此一来,就需要面对浏览器的支持性。目前Hexi Flexi Grid的布局能支持的浏览器有:</p> <ul> <li>Firefox 56+</li> <li>Chrome 61+</li> <li>Safari 10.1+</li> <li>iOS Safari 10.3+</li> <li>Android Chrome 62+</li> <li>IE11或Edge</li> </ul> <h2>开始</h2> <p>至于Hexi Flexi Grid 怎么实现,估计很多同学并不太关注,而关注的是怎么使用。那么接下来,我们来看看怎么使用Hexi Flexi Grid。</p> <p>先来上一个简单的示例,创建一个<code>6x4</code>的多边形网格,如下所示:</p> <div style="margin-bottom: 20px;"><iframe id="vpYKxE" src="//codepen.io/airen/embed/vpYKxE?height=400&amp;theme-id=0&amp;slug-hash=vpYKxE&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>那么,问题来了,这样的效果怎么实现。下面的内容简单的介绍一下如何实现。</p> <h2>HTML</h2> <p>上面的示例,我们创建了一个<code>6x4</code>的六边形网格布局,对于任保一个布局,都离不开HTML的布局。针对上面的布局,我们的HTML的结构嵌套,如下所示,不过有一个唯一的<code>id</code>,当然,我们不一定要使用唯一的<code>id</code>,咱们可以使用<code>class</code>之类的。这个根据自己的需求来定,咱们先来看看最基本的六边形网格布局的HTML结构:</p> <pre><code>&lt;div id="myHexGrid"&gt; &lt;div class="hexCrop"&gt; &lt;div class="hexContainer"&gt; &lt;div class="hex"&gt;&lt;/div&gt; &lt;!-- 中间省略24个`div.hex`的标签 --&gt; &lt;div class="hex"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; </code></pre> <p>在<code>.hexContainer</code>容器内包含了一些<code>div.hex</code>的元素,这些元素等于网格中六边形的网格数目,在这个示例中,是<code>24</code>个。</p> <h2>SCSS</h2> <p>根据你自己的项目需求,引入<code>_hexi-flexi-grid.scss</code>文件。如果你引用的是<a href="//github.com/W3cplus/SassMagic">SassMagic</a>,你只需要将<code>_sassMagic.scss</code>文件引入到你的项目。当然如果你没有使用SassMagic项目,你可以根据你自己的项目结构,把Hexi Flexi Grid对应的SCSS文件引入到你的项目中。比如<code>hex-style.scss</code>:</p> <pre><code>@import 'path/to/hex-style.scss'; </code></pre> <p>在<code>hex-style</code>(或者说SassMagic中的<code>_hexi-flexi-grid.scss</code>)的内部是一个模块化的代码块(其实也相当于一个简单的CSS或者说SCSS模块),它包含了六边形的网格设置。在<code>id</code>选择器中设置为代码块的顶部,用来匹配顶级的父<code>div</code>的<code>id</code>。比如前在HTML结构中的<code>#myHexGrid</code>。</p> <p>在<code>#myHexGrid</code>这个唯一的<code>id</code>中,配置<code>@mixins</code>所在要的参数:</p> <pre><code>#myHexGrid { $gridWidth: 40em; // 'auto',(px,pt,r/em,vw/h) $gridHeight: auto; // 'auto',(px,pt,r/em,vw/h) $columnCount: 6; // 'auto',(number) $rowCount: 4; // 'auto',(number) $hexCount: auto; // 'auto',(number) $hexLayout: row; // 'row','column','strict' $gridOrient: vertical; // 'vertical','horizontal' $crop: none; // 'none','crop' $cropFactor: 1; // (number) $hexContent: auto; // 'auto','center' $hexSize: auto; // 'auto',(px,pt,r/em,vw/h) $hexMargin: 0.5em; // (px,pt,r/em,vw/h) $hexShape: hexagon; // 'hexagon','circle' $hexColor: #48a999; // hexcode,rgb/a,named $images: none; ... } </code></pre> <p>上面的参数对应了<code>@mixin hexContainer()</code>中的参数。但这只是所需变量的设置,如果真正要实现一个六边形的网格布局之外,除了上述参数的配置之外,还需要:</p> <pre><code>#myHexGrid { $gridWidth: 40em; // 'auto',(px,pt,r/em,vw/h) $gridHeight: auto; // 'auto',(px,pt,r/em,vw/h) $columnCount: 6; // 'auto',(number) $rowCount: 4; // 'auto',(number) $hexCount: auto; // 'auto',(number) $hexLayout: row; // 'row','column','strict' $gridOrient: vertical; // 'vertical','horizontal' $crop: none; // 'none','crop' $cropFactor: 1; // (number) $hexContent: auto; // 'auto','center' $hexSize: auto; // 'auto',(px,pt,r/em,vw/h) $hexMargin: 0.5em; // (px,pt,r/em,vw/h) $hexShape: hexagon; // 'hexagon','circle' $hexColor: #48a999; // hexcode,rgb/a,named $images: none; @include hexWrapper( $gridWidth, $gridHeight, $gridOrient, $rowCount, $columnCount); .hexCrop { @include hexCrop($crop,$cropFactor) } .hexContainer { @include hexContainer( $gridWidth, $gridHeight, $gridOrient, $columnCount, $images, $rowCount, $hexLayout, $hexContent, $hexShape, $hexColor, $hexMargin, $hexCount, $hexSize ) } } </code></pre> <p>如此一来,你就能看到上面Demo中展示的<code>6x4</code>的一个六边形的网格布局。</p> <h2>定制</h2> <p>上一个Demo我们看到的<code>6x4</code>的六边形网格布局是一个纯色的网格布局。如果我们希望六边形的网格颜色并全部一样的时候,我们还可以为六边形的风格做一些定制。</p> <p>六边形的网格样式的定制主要由<code>@mixins hex-style</code>代码块来完成,具体的SCSS代码在这里不做过多展示。</p> <p>Hexi Flexi Grid为六边形网格中的每一个单独的列、行和单元格分配唯一的类名:</p> <ul> <li><code>c-[n]</code>:以列<code>[n]</code>中的每个单元格为目标</li> <li><code>r-[n]</code>:以行<code>[n]</code>中的每个单元格为目标</li> <li><code>c-[n1].r-[n2]</code>:单元格位于列<code>[n1]</code>和行<code>[n2]</code></li> </ul> <p>如果我们需要给不同的行和列的单元格设置不同的背景色或特殊的样式,我样可以这样做:</p> <pre><code>#myHexGrid { // ... margin: 2em; // 网格的外边距为`2em` // 列一的单元格背景色为`red` .c-1 { background-color: red; } // 行2的单元格将缩小80% .r-2 { transform: scale(0.8); } // 列3和行1的单元格,透明度为50% .c-3.r-1 { opacity:0.5; } // ... } </code></pre> <p>通过这样的方式,我们可以定制一些不同的六边形网格布局的效果,比如:</p> <div style="margin-bottom: 20px;"><iframe id="ypLayG" src="//codepen.io/airen/embed/ypLayG?height=400&amp;theme-id=0&amp;slug-hash=ypLayG&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>上面的示例,我们看到的都是纯色的六边形,以及后面两行做了一些个性化的定制效果。除此之外,还可以在<code>$images</code>的配置中,设置图片,比如:</p> <pre><code>#myHexGrid { // ... $images: 'path/to/image-1.jpg' 'path/to/image-2.jpg' 'path/to/image-3.jpg' 'path/to/image-4.jpg' 'path/to/image-5.jpg' 'path/to/image-6.jpg' ; // ... } </code></pre> <p>如此一来,看到的效果,就如文章中最早提供的Demo效果。</p> <blockquote> <p>上面的所有Demo效果,并没有向大家展示任何一行有关于SCSS的代码,也就是<a href="//github.com/W3cplus/SassMagic/blob/0a7d73e90811329c1e2ef6dcf561f0c7f70f7ad3/src/mixins/_hexi-flexi-grid.scss"><code>_hexi-flexi-grid.scss</code></a>的代码。如果你对源码感兴趣的话,可以在<a href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic">SassMagic</a>的<" href="//github.com/W3cplus/SassMagic/blob/0a7d73e90811329c1e2ef6dcf561f0c7f70f7ad3/src/mixins/_hexi-flexi-grid.scss"><code>_hexi-flexi-grid.scss</code></a>文件中阅读源码,除此之外,你也可以在<a href="http://xxysy.com/quot;//github.com/vmcreative">@vmcreative</a>的<" href="http://xxysy.com/quot;//github.com/vmcreative/Hexi-Flexi-Grid">He" Flexi Grid</a>仓库中阅读源码。<a href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic">SassMagic</a>中除了Hex" Flexi Grid的的SCSS代码之外,还包含了其了很多有意思的<code>@function</code>和<code>@mixins</code>。如果你感兴趣的话,可以关注这个仓库。</p> </blockquote> <h2>网格配置</h2> <p>虽然我们没有花大篇幅的时间来介绍<code>_hexi-flexi-grid.scss</code>中的源码,但我们有必要了解其中的的参数配置,只有了解这些配置,才能更好的使用六边形的网格布局。</p> <h3><code>$gridWidth</code></h3> <p>设置六边形网格的宽度。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>网格宽度将匹配<code>$gridHeight</code>的比例。当设置为<code>auto</code>时,<code>$gridHeight</code>必须显式设置</td> </tr> <tr> <td><code>&lt;length&gt;</code></td> <td>显式的设置网格的高度。注意,不支持百分比宽度</td> </tr> </tbody> </table> <h3><code>$gridHeight</code></h3> <p>设置六边形网格的高度。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>网格的高度将匹配<code>$gridWidth</code>的比例。当设置为<code>auto</code>时,<code>$gridWidth</code>必须显式设置</td> </tr> <tr> <td><code>&lt;length&gt;</code></td> <td>显示设置网格的高度。注意,不支持百分比高度</td> </tr> </tbody> </table> <h3><code>$columnCount</code></h3> <p>设置六边形网格的列数。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>列的数量将按行的单元格数来进行匹配。 当设置为<code>auto</code>时, 必须显式地设置<code>$rowCount</code>和<code>$hexCount</code></td> </tr> <tr> <td><code>number</code></td> <td>显式的设置列的数量值</td> </tr> </tbody> </table> <h3><code>$rowCount</code></h3> <p>设置六边形网格的行数。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>单元格的数量将匹配列数乘以行数。 当设置为<code>auto</code>时,必须显式设置<code>$rowCount</code>和<code>$columnCount</code></td> </tr> <tr> <td><code>number</code></td> <td>显式的设置单元格数量值</td> </tr> </tbody> </table> <h3><code>$hexLayout</code></h3> <p>设置单元格填充网格的方向。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>row</code></td> <td>单元格将从网格的左上角开始填充,并将其横向填充,当一行满了之后将再填充到下一行</td> </tr> <tr> <td><code>column</code></td> <td>单元格将从网格的左上角开始填充,并将其纵向填充,当一列满了之后将再填充到下一列</td> </tr> </tbody> </table> <h3><code>$gridOrient</code></h3> <p>设置网格单元格对齐的方向。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>vertical</code></td> <td>列方向对齐,行将偏移一个半单元格</td> </tr> <tr> <td><code>horizontal</code></td> <td>行方向对齐,先将偏移一个半单元格</td> </tr> </tbody> </table> <h3><code>$crop</code></h3> <p>设置网格是否为矩形裁剪。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>none</code></td> <td>网格将不会被裁剪</td> </tr> <tr> <td><code>crop</code></td> <td>网格将会根据<code>$cropFactor</code>因子进行缩放,并且<code>overflow:hidden</code></td> </tr> </tbody> </table> <h3><code>$cropFactor</code></h3> <p>当网格被裁剪时,设置网格的缩放。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>number</code></td> <td>显示的设置网格的缩放因子。<code>1.2</code>的值相当于<code>120%</code></td> </tr> </tbody> </table> <h3><code>$hexContent</code></h3> <p>设置单元格的内容。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>单元格内容将延伸到整个单元格的大小,其大小值不包含<code>$hexMargin</code>的值</td> </tr> <tr> <td><code>center</code></td> <td>单元格内容在单元格中居中,并与<code>$hexSize</code>的值相匹配。其大小包含<code>$hexMargin</code>的值</td> </tr> </tbody> </table> <h3><code>$hexSize</code></h3> <p>设置单元格的大小。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>auto</code></td> <td>单元格将占满<code>100%</code>的可用空间</td> </tr> <tr> <td><code>number</code></td> <td>显式设置单元格大小。注意:不支持百分比的值</td> </tr> </tbody> </table> <h3><code>$hexMargin</code></h3> <p>设置单元格外边距。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>number</code></td> <td>显式设置单元格外边距。注意:此值不支持百分比的值</td> </tr> </tbody> </table> <h3><code>$hexShape</code></h3> <p>设置单元格的形状。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>hexagon</code></td> <td>单元格为六边形</td> </tr> <tr> <td><code>circle</code></td> <td>单元格为圆形</td> </tr> </tbody> </table> <h3><code>$hexColor</code></h3> <p>设置单元格的背景颜色。</p> <table> <thead> <tr> <th>值</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>color</code></td> <td>设置单元格背景色,接受十六进制颜色、<code>rgb</code>和<code>rgba</code>以及颜色关键词</td> </tr> </tbody> </table> <h3><code>$images</code></h3> <p>设置六边形单元格的背景图像。文件将按照<code>$gridLayout</code>指定的顺序添加到网格中。如果<code>$images</code>的值为<code>none</code>,将表示单元格的背景为<code>url(none)</code>,不会有任何背景图像填充到单元格。</p> <h2>总结</h2> <p>通过Sass的特性,创建了一个灵活具有弹性的六边形的网格布局。在整篇文章中,并没有剖析六边形网格布局的Sass代码,只是基于<code>_hexi_flexi_grid.scss</code>的<code>@function</code>和<code>@mixins</code>能让我们快速的实现<code>m x n</code>的六边形网格布局。文章的示例,通过几行简单的代码就可以快速的实现六边形的网格布局。当然如果你对Sass的代码感兴趣的话,可以阅读其<a href="//github.com/W3cplus/SassMagic/blob/0a7d73e90811329c1e2ef6dcf561f0c7f70f7ad3/src/mixins/_hexi-flexi-grid.scss">源码</a>。</p> <p>除了六边形的网格布局之外,<a href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic">SassMagic</a>还提供了其他一些相关的<code>@function</code>和<code>@mixins</code>。如果你的项目是通过Sass来完成,建议你引用这个库,能帮助你快速实现一些常用的功能模块。如果你对改库感兴趣,欢迎<" href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic#fork-destination-box">Fork</a>或者点赞。当然,如果你有相关的Mixins,欢迎给我们提<" href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic/pulls">Pul" Requests</a>。或者你发现其中有误之处,也可以给我们提<a href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic/issues">Issues</a>。希望更多的开发者参与<" href="http://xxysy.com/quot;//github.com/W3cplus/SassMagic">SassMagic</a>的构建和维护。</p>" <p><strong>最后要特别感谢<a href="http://xxysy.com/quot;//github.com/vmcreative">@Vincen" Martin</a>给我们提供了一个这么<a href="http://xxysy.com/quot;//vmcreative.github.io/Hexi-Flexi-Grid/">优秀的方案</a>,能帮助我们快速的完成六边形的网格布局。</strong></p>" <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sass/hexi-flexi-grid.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sass/hexi-flexi-grid.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/CSS3"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/356.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3 Grid Layout</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/355.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Grid</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/302.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sass</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/368.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SCSS</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/518.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS处理器</a></div></div></div> Tue, 12 Dec 2017 16:01:13 +0000 Airen 2323 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-cutom-directive.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明:本文转载<a href="http://xxysy.com/quot;//futu.im/author/Diandian">@Diandian</a>翻译的《<" href="//css-tricks.com/power-custom-directives-vue/">Vue 自定义指令的魅力</a>》一文,如需转载,烦请注明原文出处: 英文:<a href="//css-tricks.com/power-custom-directives-vue/">https://css-tricks.com/power-custom-directives-vue/</a></p> <p>译文:<a href="//futu.im/posts/2017-10-31-vue-cutom-directive/">https://futu.im/posts/2017-10-31-vue-cutom-directive/</a></p> rel="nofollow" </blockquote> <p>在你初次接触一个新的JavaScript框架时,会像第一次进糖果店的孩子一样。给啥拿啥,而更直接点,有些东西可以让你更容易成为一个开发者。不可避免的是,我们在用框架时都会有一个同感,就是总有些场景是框架不能帮我们完成的。</p> <p><a href="http://xxysy.com/quot;//vuejs.org/">Vue</a>框架的漂亮之处在于它的功能非常强大,虽然这个框架的指令不够面面俱到,但也能在开发上助你一臂之力了,因为创建一个自定义指令是很轻松的。</p>" <h2>什么是指令?</h2> <p>我在<a href="//css-tricks.com/guides/vue/">Vue.js Guide</a>中写过指令的一篇文章,现在再一起复习下。</p> <p>指令是可以写在DOM元素的小命令,他们以<code>v-</code>为前缀,Vue就能识别这是一个指令并保持语法的一致性。如果你需要对HTML进行底层操作的话,这种方式是非常有用的。</p> <p>如果你已经用过Vue或者Angular的话,对于<code>v-if</code>,<code>v-else</code>,<code>v-show</code>等指令就会比较熟悉了,但是我还是要介绍一些基础的知识,如果你更想直接看例子,可以直接看后文就好了。</p> <p>以下是使用指令的几种方法,以及示例,这些例子并不规范,它们只是示例。这里的<code>example</code>代替了实际的指令。</p> <p><code>v-example</code> —— 会实例化一个指令,但这个指令没有参数。如果不传参数会比较不灵活,但是这样就已经操作DOM元素的能力了。</p> <p><code>v-example="value"</code> —— 这样可以传值到指令中,指令会根据<code>value</code>值来操作<code>html</code>。</p> <pre><code>&lt;div v-if="stateExample"&gt;stateExample为true时会显示&lt;/div&gt; </code></pre> <p><code>v-example="'string'"</code> —— 使用字符串作为表达式。</p> <pre><code>&lt;p v-html="'&lt;strong&gt;this is an example of a string in some text&lt;strong&gt; '"&gt;&lt;/p&gt; </code></pre> <p><code>v-example:arg="value"</code> —— 这里可以传参数(<code>arg</code>),在下面的例子中,我们绑定一个<code>class</code>,然后给这个<code>class</code>设置样式。</p> <pre><code>&lt;div v-bind:class="someClassObject"&gt;&lt;/div&gt; </code></pre> <p><code>v-example:arg.modifier="value"</code> —— 使用修饰符(<code>modifier</code>),下面的例子可以在<code>click</code>事件上调用<code>preventDefault()</code>:</p> <pre><code>&lt;button v-on:submit.prevent="onSubmit"&gt;&lt;/button&gt; </code></pre> <h2>了解自定义指令</h2> <p>现在对指令有了大概的了解后,我们再来学习下如何创建一个自定义指令。自定义指令的典型例子就是创建一个<code>scroll</code>事件的指令,下面让我们一起来看一下。</p> <p>首先创建一个单纯的全局指令(它还没有做任何事情)。</p> <pre><code>vue.directive('tack'); </code></pre> <p>根据这个指令HTML就是这样的:</p> <pre><code>&lt;p v-tack&gt;This element has a directive on it&lt;/p&gt; </code></pre> <p>指令定义函数提供了几个钩子函数 (可选):</p> <ul> <li><code>bind</code>:只调用一次,指令第一次绑定到元素时调用。</li> <li><code>insert</code>:被绑定元素插入父节点时调用。</li> <li><code>update</code>:所在伟德1946手机版的 VNode 更新时调用,但是可能发生在其子元素的 VNode 更新之前。</li> <li><code>componentUpdated</code>:所在伟德1946手机版的 VNode 及其子元素的 VNode 全部更新时调用。</li> <li><code>unbind</code>:只调用一次,指令与元素解绑时调用。</li> </ul> <p><img src="/sites/default/files/blogs/2017/1712/vue-cutom-directive.svg" alt="Vue 自定义指令的魅力" /></p> <p>我认为这五个钩子函数中<code>bind</code>和<code>update</code>是最有用的。</p> <p>他们中的每一个都有可以用的<code>el</code>,<code>binding</code>和<code>vnode</code>参数,除了<code>update</code>和<code>componentUpdated</code>之外,还会暴露<code>oldVnode</code>,以区分传递的旧值和新值。</p> <ul> <li><code>el</code> 指令所绑定的元素,可以用来直接操作 DOM 。</li> <li><code>binding</code> 一个对象,包含以下属性:<code>name</code>,<code>value</code>,<code>oldValue</code>,<code>expression</code>,<code>arg</code>和<code>modifiers</code>。</li> <li><code>vnode</code> Vue 编译生成的虚拟节点。</li> </ul> <p><code>binding</code>和<code>vnode</code>都是只读。</p> <h2>创建一个自定义指令</h2> <p>了解了自定义指令概念后,来看下如何使用一个自定义指令,下面用一个例子来实现我们刚才所说的:</p> <pre><code>Vue.directive('tack',{ bind(el,binding,vnode){ el.style.position = 'fixed' } }) </code></pre> <p>相对应的HTML就是:</p> <pre><code>&lt;p v-tack&gt;I will now be tacked onto the page&lt;/p&gt; </code></pre> <p>这样就可以了,但是还不够灵活。如果能接受参数以便后续更新它的表现或者进行复用的话就会更加灵活。让我们看下如何实现让这个元素离页面顶部有一定的距离:</p> <pre><code>Vue.directive('tack',{ bind(el,binding,vnode){ el.style.position = 'fixed'; el.style.top = binding.value + 'px'; } }) &lt;div id="app"&gt; &lt;p&gt;向下滚动页面&lt;/p&gt; &lt;p v-tack="70"&gt;我固定在离顶部70px的地方&lt;/p&gt; &lt;/div&gt; </code></pre> <p>完成后的CodePen展示:(如无法展示效果,点击<a href="http://xxysy.com/quot;//codepen.io/sdras/pen/0959829d6dfd86f6a1e06be2fd424ec7">链接</a>查看)</p>" <div style="margin-bottom: 20px;"><iframe id="xpKjPR" src="//codepen.io/airen/embed/xpKjPR?height=400&amp;theme-id=0&amp;slug-hash=xpKjPR&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>假设我们想要区分偏离的<code>70px</code>是在顶部还是左侧,可以通过传递一个参数来实现:</p> <pre><code>&lt;p v-tack:left="70"&gt;现在我会在距离左侧70px的地方&lt;/p&gt; Vue.directive('tack',{ bind(el,binding,vnode){ el.style.position = 'fixed'; const s = (binding.arg == 'left'?'left':top); el.style[s] = binding.value + 'px'; } }) </code></pre> <p>完成后的CodePen展示:(如无法展示效果,点击<a href="http://xxysy.com/quot;//codepen.io/sdras/pen/4dfeb0b4f8ac1158236d3b9fea71cc9a">链接</a>查看)</p>" <div style="margin-bottom: 20px;"><iframe id="YYKLaY" src="//codepen.io/airen/embed/YYKLaY?height=400&amp;theme-id=0&amp;slug-hash=YYKLaY&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>你也可以使用多个值,像自带指令一样用:</p> <pre><code>&lt;p v-tack="{top:'40',left:'100'}"&gt;我固定在离顶部40px、左侧100px的地方&lt;/p&gt; </code></pre> <p>然后这两个值将会在指令上同时生效:</p> <pre><code>Vue.directive('tack',{ bind(el,binding,vnode){ el.style.position = 'fixed'; el.style.top = binding.value.top+'px'; el.style.left = binding.value.left+'px'; } }) </code></pre> <div style="margin-bottom: 20px;"><iframe id="babMKZ" src="//codepen.io/airen/embed/babMKZ?height=400&amp;theme-id=0&amp;slug-hash=babMKZ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>我们还可以编写更复杂的东西,我们可以根据自定义指令来创建和修改方法。这里,我们简单创建一个滚动动画小例子:</p> <pre><code>Vue.directive('scroll',{ inserted:function(el,binding){ let f = function(evt){ if(binding.value(evt,el)){ window.removeEventListener('scroll',f); } } window.addEventListener('scroll',f); } }); //main app new Vue({ el:'#app', methods:{ handleScroll:function(evt,el){ if(window.scrollY&gt;50){ TweenMax.to(el,1.5,{ y:-10, opacity:1, ease:sine.easeOut }) } return window.scrollY&gt;100; } } }); &lt;div class="box" v-scroll="handleScroll"&gt; &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.&lt;/p&gt; &lt;/div&gt; </code></pre> <p>完成后的CodePen展示:(如无法展示效果,点击<a href="http://xxysy.com/quot;//codepen.io/sdras/pen/5ca1e0c724d7d900603d8898b5551189">链接</a>查看)</p>" <div style="margin-bottom: 20px;"><iframe id="EoYLdZ" src="//codepen.io/airen/embed/EoYLdZ?height=400&amp;theme-id=0&amp;slug-hash=EoYLdZ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>以上都是很简单的代码来实现效果,在实际的开发中,你可以创建更高级灵活的自定义指令。</p> <p>在一个实际构建过程中,我会将指令代码放在<code>main.js</code>中,这个文件位于<code>src</code>目录下(如果你使用的是Vue-CLI这样的工具的话),这样<code>App.vue</code>及以<code>.vue</code>后缀名的文件都可以引入使用。你当然也可以使用其他的方式,但这是我认为在实现整个App过程中最灵活的方式。</p> <p>如果你想了解有关Vue框架的更多知识,请查看<a href="//css-tricks.com/guides/vue/">Guide</a>。</p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/624.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">转载</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div> Mon, 11 Dec 2017 15:13:29 +0000 Airen 2322 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-pocket-guide.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明:本文根据<a href="http://xxysy.com/quot;//twitter.com/JoniTrythall">@Jon" Trythall</a>的《<a href="http://xxysy.com/quot;//svgpocketguide.com/book/">Pocke" Guide to Writing SVG</a>》所译。其中<a href="http://xxysy.com/quot;#简介">简介</a>、<" href="http://xxysy.com/quot;#第1节-文档组织">第1节" 文档组织</a>和<a href="http://xxysy.com/quot;#第2节-基本图形和路径">第2节:基本图形和路径</a>由<" href="http://xxysy.com/quot;//hujiangtech.github.io/tech/">沪江技术学院</a>翻译整理。如需转换,烦请注明原文出处:<" href="//svgpocketguide.com/book/">http://svgpocketguide.com/book/</a></p> rel="nofollow" </blockquote> <p><img src="/sites/default/files/blogs/2017/1712/cover3.svg" alt="" /></p> <p class="btns-zone"><a class="btn-demo" href="http://xxysy.com/quot;//svgpocketguide.com/book/audio/completeaudio.zip"" target="_blank">音频版本</a><a class="btn-download" href="http://xxysy.com/quot;//github.com/jonitrythall/svgpocketguide"" target="_blank">查看源码</a></p> <h2>简介</h2> <p>Scalable Vector Graphics (SVG)是在XML中描述二维图形的语言。这些图形由路径,图片和(或)文本组成,并能够在不失真的情况下任意变换尺寸。</p> <p>本书主要介绍了内联SVG,它是指在HTML中编写的嵌入式代码,以便在浏览器中生成这些图形。</p> <p>以这种方式使用SVG有许多优点,包括为了交互目的访问所有图形的各个部分,支持访问 SVG 文档构成的 DOM 节点树,查询、修改 DOM 节点的属性,提升用户可访问性。</p> <p>先介绍基本组织和简单形状,再继续描述SVG坐标系或画布,然后用它绘制图形的内部和/或边框,变换,以及使用和操作图形文本。通过渐变和模式等更高级的功能来总结。</p> <p>这个指南快速且详细的介绍内联式SVG以及所有涵盖的可使用的功能,有助于你学习SVG。 它面向设计师和开发人员,希望以最可行的方式将SVG添加到他们的工作流程中。</p> <p>从小笔画细节到开始使用手工制作的模式,本指南旨在成为一个围绕“go-to”编写SVG的参考。</p> <h3>前言</h3> <p>本“口袋指南”只针对已经有一些HTML和CSS基础的人,在你喜爱的浏览器中绘制SVG之前最好知道一些额外的知识, 例如:在SVG中正确渲染的信息,如何让你的图形更容易访问,以及何时何处使用矢量图形软件。</p> <h4>使用SVG</h4> <p><a href="//css-tricks.com/using-svg/">有许多方法可以把SVG插入到你的项目</a>:内联、<code>img</code>、<code>background-image</code>、<code>&lt;object&gt;</code>或者<code>Data URI</code>。我们主要介绍内联SVG的使用方法,包括如何在结构清晰的HTML文档中编写SVG代码。</p> <p>尽管我们只是介绍了内联SVG的使用方法,但在某些特定情况下,其他方法也许会更好。例如,如果你不需要图形本身的编辑功能或访问其各个部分,则用<code>&lt;img&gt;</code>标签可能更适合。</p> <h4>矢量图形软件</h4> <p>当你想要创建几乎不可能手写的更复杂的图形时,矢量图形软件更实用。你可以将<a href="http://xxysy.com/quot;//www.adobe.com/products/illustrator.html">Adob" Illustrator</a>, <a href="http://xxysy.com/quot;//www.inkscape.org/en">Inkscape</a>" <a href="http://xxysy.com/quot;//bohemiancoding.com/sketch">Sketch</a>" <a href="http://xxysy.com/quot;//www.indeeo.com/idraw">iDraw</a>" <a href="http://xxysy.com/quot;//www.webcodeapp.com">WebCode</a>这些工具放到你的SVG技能包中。</p>" <p>可以用这些工具直接导出SVG代码并嵌入你的HTML。我们过一会再讨论这个。</p> <h4>Web中的内联SVG</h4> <p>为了简洁起见,SVG DOCTYPE,版本号,<a href="http://xxysy.com/quot;//www.w3.org/TR/REC-xml-names"><code>xmlns</code></a>和<" href="http://xxysy.com/quot;//www.w3.org/TR/2004/REC-xml11-20040204/#sec-white-space"><code>xml:space</code></a>在这本书中不会被提到。</p>" <p>这些属性专注于<a href="http://xxysy.com/quot;//www.w3.org/TR/xml11">SVG的版本</a>和文档的<" href="http://xxysy.com/quot;//www.w3.org/TR/REC-xml-names">命名空间</a>。只要记住这一点,你不需要这些属性就能成功地在浏览器中呈现图形。</p>" <p>如下面这个例子,在Illustrator生成的SVG代码时不要吃惊:</p> <pre><code>&lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt; &lt;svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"&gt; &lt;/svg&gt; </code></pre> <p>在大多数情况下,<code>&lt;svg&gt;</code>元素中的<code>DOCTYPE</code>和属性不是必需的,可以删除,以缩减你的代码。</p> <h4>SVG用户可访问性</h4> <p>使用<a href="http://xxysy.com/quot;//www.sitepoint.com/tips-accessible-svg">SVG可访问性</a>是一个好习惯,但是为了简洁,描述和标题不会包含在整本书的代码中。</p>" <p>一旦你更熟练的写SVG,这些元素将使你的图形更能被用户接受。例如,<code>&lt;desc&gt;</code>元素中的内容允许你向屏幕阅读器的用户提供图形的详细描述。</p> <p>由于SVG文本可以被检测和读取,并且可以容易地调整大小以适应特定的阅读偏好,提供了在可访问性方面优于传统的基于光栅的图像的巨大优势。</p> <h4>注意事项</h4> <p>使用之前一些更通用的注释:整本书的演示字体都可通过<a href="http://xxysy.com/quot;//www.google.com/fonts">Googl" Fonts</a>获得。虽然你可以通过<code>font-family</code>看到这些字体显示出来,但你不会看到获取谷歌字体时使用的相关<code>link</code>或<code>@import</code>。</p> <p>示例始终使用像素和百分比作为单位标识符。 SVG支持的长度单位为:<code>em</code>,<code>ex</code>,<code>px</code>,<code>pt</code>,<code>pc</code>,<code>cm</code>,<code>mm</code>,<code>in</code>和百分比。</p> <p>本书中的SVG代码可以添加到任何文本编辑器,并且在<a href="http://xxysy.com/quot;//caniuse.com/svg-html5">任何支持内联SVG的浏览器</a>中查看。通常情况下浏览器支持对于SVG非常强大,但是有更多高级的特性(例如渐变)时这种支持会变得弱一些。<" href="http://xxysy.com/quot;//caniuse.com">Ca" I Use</a>是一个检查功能支持的实用网站,但实践才是检验真理的唯一方法。</p> <p>你也可以复制代码,通过<a href="http://xxysy.com/quot;//codepen.io">CodePen</a>把它放在一个HTML部分,就能立即在屏幕上看到你的图形。我说的可能不够好,但它是我对SVG感兴趣的第一因素。练习,修改甚至失败是我最喜欢的学习方式。</p>" <p>最终,由于篇幅限制,一部分例子会有图形代码注释,其他不想关的将被省略。</p> <pre><code>&lt;svg&gt; &lt;!--&lt;path d=&lt;this path is commented out&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <h2>第1节: 文档组织</h2> <p>SVG详细信息位于<code>&lt;svg&gt;</code>元素中。此元素中有几个属性,可以自定义你的图形画布。虽然这些属性对于呈现图像不是完全必要的,但是在跨浏览器执行时忽略它们可能使更复杂的图形易受攻击,并且使得它们容易不按预期进行呈现。</p> <p>如上所述,内联图形可以“手动”编写,或者通过矢量图形软件生成的<code>XML</code>代码来嵌入。因为这些图形元素的顺序决定了它们的堆叠顺序,所以无论哪种方式,正确的组织和结构对于编写高效的SVG代码至关重要的。</p> <h3>组织和语义</h3> <p>SVG文档片段由<code>&lt;svg&gt;</code>元素中包含的任意数量的SVG元素组成。本文档中的组织是至关重要的。文档中的内容可以快速扩展,正确的组织提高了可访问性和效率,使作者和用户都受益。</p> <p>本节将介绍编写SVG的关键 —— <code>&lt;svg&gt;</code>元素 —— 并查看帮助初始文档设置的一些常见属性。</p> <h4><code>svg</code>元素</h4> <p><code>&lt;svg&gt;</code>元素归属于容器和结构元素,在文档内允许嵌套使用独立的SVG片段。每个独立的片段都有自己的坐标系。</p> <p>此元素中使用的属性(如<code>width</code>,<code>height</code>,<code>preserveAspectRatio</code>和<code>viewBox</code>)定义正在写入图形的画布。</p> <p>当从某些矢量软件获得SVG代码时,在<code>&lt;svg&gt;</code>元素中有很多<a href="http://xxysy.com/quot;//www.w3.org/TR/SVG/struct.html#SVGElement">附加信息</a>,例如SVG版本号(指示正在使用的SVG语言版本)和<code>DOCTYPE</code>。正如我已经提到的,这些信息不会包括在本指南的示例中,缺少它们不会阻止你的图形在屏幕上呈现。</p>" <h4><code>g</code>元素</h4> <p><code>g</code>元素是组合相关图形的容器元素。将此元素与描述和标题元素结合使用提供图形的相关信息,并将相关图形伟德1946手机版分在同一组在一起提高访问性。</p> <p>此外,通过相关元素分在同一组,可以将它们看作一个整体与各个独立的部分。移动这些元素尤其方便,例如,可以移动整个组。</p> <p>不包含在<code>g</code>中的任何元素则认为有它们自己的组。</p> <h4><code>use</code>元素</h4> <p><code>&lt;use&gt;</code>元素允许您在整个文档中重复使用元素。此元素中可以包含其他属性,例如<code>x</code>,<code>y</code>,<code>width</code>和<code>height</code>,这些属性定义图形在坐标系中的详细映射位置。</p> <p>在这里使用<code>xlink:href</code>属性可以调用要重用的元素。例如,如果存在需要重新使用的苹果的图像的<code>apple</code>的<code>id</code>的<code>&lt;g&gt;</code>,则该图像可以由<code>&lt;use&gt;</code>:<code>&lt;use x =“50”y =“50” xlink:href="http://xxysy.com/“#apple”/&gt;</code>。</p>" <p>这个元素作为一个重要的时间保护程序帮助压缩代码。</p> <h4><code>defs</code>元素</h4> <p>虽然<code>&lt;use&gt;</code>允许重用已经渲染的图形,但<code>&lt;defs&gt;</code>元素中的图形不会渲染到画布上,而是能够被引用,然后通过使用<code>xlink:href</code>来渲染。</p> <p>图形在<code>&lt;defs&gt;</code>中定义,然后可以通过引用该图形的<code>id</code>在整个文档中使用。</p> <p>例如,下面的代码绘制一个非常简单的矩形渐变:</p> <pre><code>&lt;svg&gt; &lt;defs&gt; &lt;linearGradient id="Gradient-1"&gt; &lt;stop offset="0%" stop-color="#bbc42a" /&gt; &lt;stop offset="100%" stop-color="#765373" /&gt; &lt;/linearGradient&gt; &lt;/defs&gt; &lt;rect x="10" y="10" width="200" height="100" fill= "url(#Gradient-1)" stroke="#333333" stroke-width="3px" /&gt; &lt;/svg&gt; </code></pre> <p><code>&lt;defs&gt;</code>除非引用其唯一的<code>id</code>来调用,不然内容没有直观的输出,在这个实例中通过矩形的<code>fill</code>属性完成内容渲染。</p> <h4><code>symbol</code>元素</h4> <p><code>&lt;symbol&gt;</code>元素类似于<code>&lt;g&gt;</code>,因为它提供了一种组元素的方法,但是,如果没有使用<code>&lt;use&gt;</code>元素,<code>&lt;symbol&gt;</code>中的元素没有可视化输出(如<code>&lt;defs&gt;</code>)。</p> <p>它也不同于<code>&lt;g&gt;</code>元素,<code>&lt;symbol&gt;</code>建立自己的坐标系,与渲染的视口分开。</p> <p>SVG的<code>viewport</code>和<code>viewBox</code>共同建立被映射的图形的坐标系统,将进一步介绍不同的部分。</p> <h3>堆叠顺序</h3> <p>HTML中的其他元素的堆叠顺序可以CSS中的<code>z-index</code>操纵,但SVG不能。 SVG元素的堆叠顺序完全取决于它们在文档片段中的位置。</p> <p>下面的葡萄和西瓜在同一个<code>&lt;svg&gt;</code>元素中。西瓜出现在葡萄前面,因为文档中包含组成西瓜的路径的组被列在葡萄之后。</p> <pre><code>&lt;svg&gt; &lt;g class="grapes"&gt; &lt;!--&lt;path &lt;stem path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;grapes path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;leaf path&gt; /&gt;--&gt; &lt;/g&gt; &lt;g class="watermelon"&gt; &lt;!--&lt;path &lt;outside path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;inside path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;seeds path&gt; /&gt;--&gt; &lt;/g&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/stackedfirst.png" alt="Stacked watermelon and grapes, watermelon on top" /></p> <p>如果包含葡萄的组被移动到文档的末尾,它将出现在西瓜的前面。</p> <pre><code>&lt;svg&gt; &lt;g class="watermelon"&gt; &lt;!--&lt;path &lt;outside path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;inside path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;seeds path&gt; /&gt;--&gt; &lt;/g&gt; &lt;g class="grapes"&gt; &lt;!--&lt;path &lt;stem path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;grapes path&gt; /&gt;--&gt; &lt;!--&lt;path &lt;leaf path&gt; /&gt;--&gt; &lt;/g&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/stackingtwo.png" alt="Stacked watermelon and grapes, grapes on top" /></p> <p>这种定型的堆叠顺序的方法也适用于组内的每一个元素。例如,将葡萄的茎的路径移动到组的末尾将导致茎在顶部。</p> <p><img src="/sites/default/files/blogs/2017/1712/stackingthree.png" alt="Stem on top of grapes" /></p> <h2>第2节:基本图形和路径</h2> <p>当你需要在HTML中使用更复杂的内联SVG图形时就没有办法再手工编写了。那些更复杂的图形可以使用矢量软件创建,但现在我们来学习下手动编码的基础。</p> <h3>基本图形</h3> <p>SVG包含以下基本形状元素集:<strong>矩形,圆形,椭圆形,直线,折线和多边形</strong>。每个元素在渲染之前需要一些属性,如坐标和大小等详细信息。</p> <h4>矩形</h4> <p><code>&lt;rect&gt;</code>元素定义一个矩形。</p> <pre><code>&lt;svg&gt; &lt;rect width="200" height="100" fill="#BBC42A" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basicrect.png" alt="Rectangle" /></p> <p><code>width</code>和<code>height</code>属性确定矩形的大小,而<code>fill</code>则设置形状的内部颜色。数值默认为<code>px</code>,当未指定时,<code>fill</code>将默认为<code>black</code>。</p> <p>其他属性还有<code>x</code>和<code>y</code>坐标。这些值将图形沿<code>&lt;svg&gt;</code>元素对应的轴移动相应的距离。</p> <p>也可以通过指定<code>rx</code>和<code>ry</code>属性中的值来创建圆角。例如,<code>rx =“5” ry =“10”</code>将产生具有<code>5px</code>半径的角的水平边,以及具有<code>10px</code>半径的角的垂直边。</p> <h4>圆形</h4> <p>基于中心点和外半径设置<code>&lt;circle&gt;</code>元素。</p> <pre><code>&lt;svg&gt; &lt;circle cx="75" cy="75" r="75" fill="#ED6E46" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basiccircle.png" alt="Line" /></p> <p><code>cx</code>和<code>cy</code>坐标建立圆的中心相对于由<code>&lt;svg&gt;</code>设置的工作空间尺寸的位置。</p> <p><code>r</code>属性设置外半径的大小。</p> <h4>椭圆</h4> <p><code>&lt;ellipse&gt;</code>元素基于中心点和两个半径定义椭圆。</p> <pre><code>&lt;svg&gt; &lt;ellipse cx="100" cy="100" rx="100" ry="50" fill="#7AA20D" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basicellipse.png" alt="Ellipse" /></p> <p>当<code>cx</code>和<code>cy</code>值基于到SVG坐标空间中的像素距离建立中心点时,<code>rx</code>和<code>ry</code>值定义形状的边的半径。</p> <h4>直线</h4> <p><code>line</code>元素定义具有开始点和结束点的直线。</p> <pre><code>&lt;svg&gt; &lt;line x1="5" y1="5" x2="100" y2="100" stroke="#765373" stroke-width="8"/&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basicline.png" alt="Line" /></p> <p><code>x1</code>和<code>y1</code>值确定线的开始坐标,而<code>x2</code>和<code>y2</code>值确定线的结束坐标。</p> <h4>折线</h4> <p><code>&lt;polyline&gt;</code>元素定义了一组相连的直线段,通常构成开放形状(不连接的开始点和结束点)。</p> <pre><code>&lt;svg&gt; &lt;polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" fill="white" stroke="#BBC42A" stroke-width="6" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basicpolyline.png" alt="Polyline" /></p> <p>在整个形状中<code>points</code>的值在<code>x</code>和<code>y</code>轴上建立形状的位置,并且在整个值列表中被分组为<code>x</code>,<code>y</code>。</p> <p>不能使用奇数点。</p> <h4>多边形</h4> <p><code>&lt;polygon&gt;</code>元素定义由连接的线组成的闭合形状。</p> <pre><code>&lt;svg&gt; &lt;polygon points="50,5 100,5 125,30 125,80 100,105 50,105 25,80 25,30" fill="#ED6E46" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/basicpolygon.png" alt="Polygon" /></p> <p>多边形形状的点通过八组的<code>x</code>,<code>y</code>值来定义。</p> <p>该元素还可以根据点的数量产生其他闭合形状。</p> <h3><code>path</code>元素</h3> <p>SVG路径表示形状的轮廓。此形状可以填充,描边,并用于导航文本和/或用作剪切路径。</p> <p>当涉及许多<a href="http://xxysy.com/quot;//www.w3.org/TR/SVG/paths.html#PathDataCurveCommands">曲线</a>时,这个路径会变得非常复杂。然而,理解工作原理和涉及的语法将有助于管理这些特定路径。</p>" <h4><code>path</code>数据</h4> <p>路径数据包含在<code>&lt;path&gt;</code>元素内的<code>d</code>属性中,定义了形状的轮廓:<code>&lt;path d =“&lt;path data specifics&gt;”/&gt;</code>。</p> <p><code>d</code>属性中的这些数据说明了路径的<code>moveto</code>,<code>line</code>,<code>curve</code>,<code>arc</code>和<code>closepath</code>指令。</p> <p>下面的<code>&lt;path&gt;</code>详细信息定义了青柠图形的路径细节:</p> <pre><code>&lt;svg width="258px" height="184px"&gt; &lt;path fill="#7AA20D" stroke="#7AA20D" stroke-width="9" stroke-linejoin="round" d="M248.761,92c0,9.801-7.93,17.731-17.71,17.731c-0.319,0-0.617,0-0.935-0.021c-10.035,37.291-51.174,65.206-100.414,65.206 c-49.261,0-90.443-27.979-100.435-65.334c-0.765,0.106-1.531,0.149-2.317,0.149c-9.78,0-17.71-7.93-17.71-17.731 c0-9.78,7.93-17.71,17.71-17.71c0.787,0,1.552,0.042,2.317,0.149C39.238,37.084,80.419,9.083,129.702,9.083 c49.24,0,90.379,27.937,100.414,65.228h0.021c0.298-0.021,0.617-0.021,0.914-0.021C240.831,74.29,248.761,82.22,248.761,92z" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/pathlime.png" alt="Lime's path" /></p> <h5><code>moveto</code></h5> <p><code>moveto</code>命令(<code>M</code>或<code>m</code>)建立一个新的点,就像提起一支钢笔,并在纸上一个新位置绘制。包括路径数据的代码行必须以<code>moveto</code>命令开始,如上面的例子所示。</p> <p><code>moveto</code>命令跟在初始化路径之后,代表新子路径的开始和复合路径的创建。这里的大写字母<code>M</code>表示绝对坐标,小写字母<code>m</code>表示相对坐标。</p> <h5><code>closepath</code></h5> <p><code>closepath</code>(<code>Z</code>或<code>z</code>)表示当前子路径的结束,并从该点到路径的初始点绘制直线。</p> <p>如果<code>closepath</code>之后紧跟着一个<code>moveto</code>,这些<code>moveto</code>坐标表示下一个子路径的开始。如果这个相同的<code>closepath</code>之后是<code>moveto</code>之外的任何东西,则下一个子路径从当前子路径的点开始。</p> <p>这里大写或小写<code>z</code>没有区别。</p> <h5><code>lineto</code></h5> <p><code>lineto</code>命令从当前点到新点绘制直线。</p> <h6><code>L</code>, <code>l</code></h6> <p><code>L</code>和<code>l</code>命令从当前点绘制一条线到下一个提供的点坐标。这个新点然后变成当前点,以此类推。</p> <p>大写<code>L</code>表示绝对定位,而小写<code>l</code>是相对定位。</p> <h6><code>H</code>, <code>h</code></h6> <p><code>H</code>和<code>h</code>命令从当前点绘制水平线。</p> <p>大写<code>H</code>表示绝对定位,而小写<code>h</code>是相对定位。</p> <h6><code>V</code>, <code>v</code></h6> <p><code>V</code>和<code>v</code>命令从当前点绘制垂直线。</p> <p>大写<code>V</code>表示绝对定位,而小写<code>v</code>是相对定位。</p> <h5>曲线命令</h5> <p>有三组命令绘制曲线路径:<strong>CubicBézier</strong>(<code>C</code>,<code>c</code>,<code>S</code>,<code>s</code>),<strong>二次贝塞尔</strong>(<code>Q</code>,<code>q</code>,<code>T</code>,<code>t</code>)和<strong>椭圆弧</strong>(<code>A</code>,<code>a</code>)。</p> <p>以下曲线部分将介绍每条曲线命令的基本概念,和映射的详细信息,然后提供一个图表供进一步了解。</p> <h6>Cubic Bézier</h6> <p><code>C</code>和<code>c</code> <strong>CubicBézier</strong>命令从当前点绘制曲线,使用<code>(x1,y1)</code>参数作为曲线开始处的控制点,<code>(x2,y2)</code>作为结束处的控制点,定义形状细节曲线。</p> <p><code>S</code>和<code>s</code>命令还绘制立方贝塞尔曲线,但在这种情况下,存在第一控制点是第二控制点的反射的假设。</p> <p><img src="/sites/default/files/blogs/2017/1712/curvecubic.png" alt="Cubic Bézier" /></p> <p>下面的代码绘制了一个基本的CubicBézier曲线:</p> <pre><code>&lt;svg&gt; &lt;path fill="none" stroke="#333333" stroke-width="3" d="M10,55 C15,5 100,5 100,55" /&gt; &lt;/svg&gt; </code></pre> <p>该曲线的第一和最后一组值将影响其开始和结束位置,两个中心值将影响曲线本身在开始和结束时的形状和定位。</p> <p><code>S</code>和<code>s</code>命令也绘制立方贝塞尔曲线,但在这种情况下,假设第一个控制点是前一个<code>C</code>命令的最后一个控制点的反映。则会作为相对于<code>S</code>命令的开始点。</p> <p><img src="/sites/default/files/blogs/2017/1712/scommand.png" alt="S Command Reflection" /></p> <p>大写字母<code>C</code>表示绝对定位,而小写字母<code>c</code>是相对定位。<code>S</code>和<code>s</code>也是一样。</p> <h6>Quadratic Bézier</h6> <p>二次贝塞尔曲线(<code>Q</code>,<code>q</code>,<code>T</code>,<code>t</code>)类似于立方贝塞尔曲线,除了它只有一个控制点。</p> <p><img src="/sites/default/files/blogs/2017/1712/curvequad.png" alt="Quadratic Bézier" /></p> <p>以下代码绘制了一个基本的二次贝塞尔曲线:</p> <pre><code>&lt;svg&gt; &lt;path fill="none" stroke="#333333" stroke-width="3" d="M20,50 Q40,5 100,50" /&gt; &lt;/svg&gt; </code></pre> <p>操作第一个和最后一组值<code>M20,50</code>和<code>100,50</code>会影响曲线起点和终点的位置。中心值集<code>Q40,5</code>定义曲线的控制点,确定其形状。</p> <p><code>Q</code>和<code>q</code>使用<code>(x1,y1)</code>作为控件从初始点到终点绘制曲线。 <code>T</code>和<code>t</code>通过假设控制点是相对于新的<code>T</code>或<code>t</code>命令的开始点的先前列出的命令的控制的反映,从初始点到终点绘制曲线。</p> <p><img src="/sites/default/files/blogs/2017/1712/curvetcontrol.png" alt="T Command Control Point" /></p> <p>大写的<code>Q</code>表示绝对定位,而小写的<code>q</code>是相对定位。<code>T</code>和<code>t</code>也是一样。</p> <h6>Elliptical Arc</h6> <p>椭圆弧(<code>A</code>,<code>a</code>)定义椭圆的线段。这些段通过<code>A</code>或命令创建,通过指定起点,终点,<code>x</code>和<code>y</code>半径,旋转和方向创建弧。</p> <p>下面是一个基本椭圆弧的代码:</p> <pre><code>&lt;svg&gt; &lt;path fill="none" stroke="#333333" stroke-width="3" d="M65,10 a50,25 0 1,0 50,25" /&gt; &lt;/svg&gt; </code></pre> <p>该路径中的第一和最后一组值,<code>M65,10</code>和<code>50,25</code>表示初始和最终坐标,而第二组值定义两个半径。 <code>1,0</code>(大弧标志和顺时针标志)的值确定如何绘制圆弧,因为这里有四个不同的选项。</p> <p>下图显示了四个弧选项以及大弧标志值和顺时针标志值对弧段的最终渲染的影响。</p> <p><img src="/sites/default/files/blogs/2017/1712/curvearc.png" alt="Elliptical Arc" /></p> <h3>矢量软件嵌入</h3> <p>矢量图形软件可以制作更复杂的形状和路径,同时可以导出SVG代码在其他地方使用和操作。</p> <p>一旦图形完成,生成的XML代码可以被复制并嵌入到HTML中,图形越复杂代码越长。分解SVG的每个部分并且运用适当的组织元素可以极大地帮助引导和理解这些复杂和冗长的代码。</p> <p>这里是一些樱桃的SVG代码图像,添加了引导类:</p> <pre><code>&lt;svg width="215px" height="274px" viewBox="0 0 215 274"&gt; &lt;g&gt; &lt;path class="stems" fill="none" stroke="#7AA20D" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" d="M54.817,169.848c0,0,77.943-73.477,82.528-104.043c4.585-30.566,46.364,91.186,27.512,121.498" /&gt; &lt;path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M134.747,62.926c-1.342-6.078,0.404-12.924,5.762-19.681c11.179-14.098,23.582-17.539,40.795-17.846 c0.007,0,22.115-0.396,26.714-20.031c-2.859,12.205-5.58,24.168-9.774,36.045c-6.817,19.301-22.399,48.527-47.631,38.028 C141.823,75.784,136.277,69.855,134.747,62.926z" /&gt; &lt;/g&gt; &lt;g&gt; &lt;path class="r-cherry" fill="#ED6E46" stroke="#ED6E46" stroke-width="12" d="M164.836,193.136 c1.754-0.12,3.609-0.485,5.649-1.148c8.512-2.768,21.185-6.985,28.181,3.152c15.076,21.845,5.764,55.876-18.387,66.523 c-27.61,12.172-58.962-16.947-56.383-45.005c1.266-13.779,8.163-35.95,26.136-27.478 C155.46,191.738,159.715,193.485,164.836,193.136z" /&gt; &lt;path class="l-cherry" fill="#ED6E46" stroke="#ED6E46" stroke-width="12" d="M55.99,176.859 c1.736,0.273,3.626,0.328,5.763,0.135c8.914-0.809,22.207-2.108,26.778,9.329c9.851,24.647-6.784,55.761-32.696,60.78 c-29.623,5.739-53.728-29.614-44.985-56.399c4.294-13.154,15.94-33.241,31.584-20.99C47.158,173.415,50.919,176.062,55.99,176.859z" /&gt; &lt;/g&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/embedcherry.png" alt="Cherries" /></p> <p><code>svg</code>元素中的属性定义工作区,或图形的“画布”。叶和茎在一个<code>g</code>(组)内,而樱桃在另一个。数字字符串定义图形将采用的路径,<code>fill</code>和<code>stroke</code>属性设置背景和边框的颜色。</p> <p>将这个代码复制下来,它会通过一个SVG优化器在被放置在HTML之前,以助于消除不必要的代码和间距,进而大大缩小文件。 关于这个方面<a href="http://xxysy.com/quot;//petercollingridge.appspot.com/svg-optimiser">Pete" Collingridge的SVG Optimiser</a>和<a href="http://xxysy.com/quot;//github.com/svg/svgo">SVGO</a>也是非常有用的工具。</p>" <h2>第3节: 工作区域</h2> <p>或许SVG中最重要的方向是了解它的总结结构,以及如何创建基本图形,然而要掌握这些就需要掌握SVG的工作区,或者换句话说,图形将映射到工作区的坐标系统。</p> <p>理解SVG的工作区有助于帮你更好的,更正确的呈现您的作品,但是一旦进入了高级的SVG特性时,这个就变得非常重要。例如,渐变和图案的映射需要严重的依赖已建立的坐标系统。这个工作区域主要由SVG的<code>viewport</code>和<code>viewBox</code>属性来定义。</p> <p>幸运的是,这个梨图形配置了相应的<code>viewport</code>和<code>viewBox</code>:</p> <pre><code>&lt;svg width="115" height="190" viewBox="0 0 115 190"&gt; &lt;!--&lt;path &lt;pear's drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/viewboxpear1.png" alt="Pear" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/3a8c995a969cbcbc5c589aa9ad7de491">点击这里查看Demo效果</a></em></p>" <p>整个梨在浏览器中都可见,但当<code>viewport</code>发生变更时,这个梨的图形也将想应的会进行绽放。</p> <h3><code>viewport</code></h3> <p><code>viewport</code>是用来设置SVG可见区域。虽然SVG正如你期望的一样设置了<code>width</code>或<code>height</code>属性,但设置了<code>viewport</code>将意味着图像中只有某个部分可以在SVG的工作区域可见。</p> <p>通过<code>&lt;svg&gt;</code>元素的<code>height</code>和<code>width</code>属性可以设置<code>viewport</code>。</p> <p>如果这些值没有显式定义,那么<code>viewport</code>的大小通常由SVG中的其他指标来决定,比如<code>SVG</code>外面元素的宽高。只不过,离开这个不确定的地方(指的是不确定的SVG的<code>viewport</code>),我们的图形(艺术作品)就很容易被截断。</p> <h3><code>viewBox</code></h3> <p><code>viewBox</code>允许你指定一组图形拉伸以适应特定的容器元素。这些值包括由逗号和空格分隔的四个数字:<code>min-x</code>、<code>min-y</code>、<code>width</code>和<code>height</code>,这些数字通常设置为<code>viewport</code>的边界值。</p> <p><code>min</code>值表示在<code>viewBox</code>的图形应该从哪个点开始,而<code>width</code>和<code>height</code>用来确定盒子的大小。</p> <p>如果我们不显式的定义<code>viewBox</code>,那么图形将无法与设置的<code>viewport</code>相匹配。</p> <p>如果<code>viewBox</code>的<code>width</code>和<code>height</code>大小比梨图形各小<code>50px</code>,那么梨的可见部分就会减少,其剩下的部分则会缩放到<code>viewport</code>的边界。</p> <pre><code>&lt;svg width="115px" height="190px" viewBox="0 0 65 140"&gt; &lt;!--&lt;path &lt;pear's drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/viewboxpear2reduced.png" alt="Pear" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/a1f47ea097e886493cf1d483629e655a">点击这里查看Demo效果</a></em></p>" <p><code>viewBox</code>中的<code>min</code>值定义了其父元素中的<code>viewBox</code>的原始值。换句话说,在<code>viewBox</code>中,你希望它匹配<code>viewport</code>的开始点。在上面的梨图形中,<code>min</code>值设置为<code>0</code>(左上角)。让我们把这些值更改变<code>50,30</code>:<code>viewBox= 50 30 115 190</code>。</p> <pre><code>&lt;svg width="115" height="190" viewBox="50 30 115 190"&gt; &lt;!--&lt;path &lt;pear's drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/viewboxpearminval.png" alt="Pear" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/46aaa8d7e8296945def4490ad5fd69d1">点击这里可以查看Demo效果</a></em></p>" <p><code>viewBox</code>现在从<code>x</code>轴的<code>50px</code>处开始,从<code>y</code>轴的<code>30px</code>处开始。在改变这些值时,梨图形的部分已经改变了。</p> <h4>preserveAspectRatio</h4> <p>如果<code>viewport</code>和<code>viewBox</code>不具备相同的宽高比例,则<code>preserveAspectRatio</code>属性将指示浏览器如何显示图形。</p> <p><code>preserveAspectRatio</code>有两个参数,<code>&lt;align&gt;</code>和<code>&lt;meetOrSlice&gt;</code>。第一个参数包含两个部分,并在<code>viewport</code>中引导<code>viewBox</code>的对齐。第二个参数是可选的,并指出如何保持宽高比例。</p> <pre><code>preserveAspectRatio="xMaxYMax meet" </code></pre> <p>这些值将把<code>viewBox</code>的右下角对齐到<code>viewport</code>的右下角。<code>meet</code>将会通过缩放<code>viewBox</code>来适应<code>viewport</code>,从而保持宽高比例。</p> <p><code>&lt;meetOrSlice&gt;</code>有三个选项:<code>meet</code>(默认值)、<code>slice</code>和<code>none</code>。在满足确保图形(尽可能多)的可见性的同时,<code>slice</code>尝试用<code>viewBox</code>填充<code>viewport</code>,然后将图形的任何部分切掉。<code>none</code>不会宽高比,图形会在<code>viewport</code>里扭曲。</p> <p>也许这里最直接的值是<code>none</code>,这表明不会有统一的缩放。如果我们增加<code>viewport</code>的像素值,下面的樱桃图形将会拉伸不均匀,樱桃看起来会扭曲。</p> <pre><code>&lt;svg width="500" height="400" viewBox="0 0 250 600" preserveAspectRatio="none"&gt; &lt;!--&lt;path &lt;cherry drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/preserverationone.png" alt="Cherries" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/8943154485dcb3662f95a6756f1d097b">点击这里可以查看Demo效果</a></em></p>" <p>下图中的<code>preserveAspectRatio</code>属性值设置为<code>xMinYMax meet</code>,它将<code>viewBox</code>的左下角和<code>viewport</code>的左下角对齐。<code>meet</code>是确保图像在<code>viewport</code>中尽可能的缩放。</p> <pre><code>&lt;svg width="350" height="150" viewBox="0 0 300 300" preserveAspectRatio="xMinYMax meet" style="border: 1px solid #333333;"&gt; &lt;!--&lt;path &lt;cherry drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/preserveaspect2.png" alt="Cherries" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/9edd85f9931af23b30726845c184ee9b">点击这里查看Demo效果</a></em></p>" <p>当<code>meet</code>变为<code>slice</code>时,樱桃图形的效果:</p> <pre><code>&lt;svg width="350" height="150" viewBox="0 0 300 300" preserveAspectRatio="xMinYMax slice" style="border: 1px solid #333333;"&gt; &lt;!--&lt;path &lt;cherry drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/preserveslice.png" alt="Cherries" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/2eede68379ac3f2702e5e30342a3ce0b">点击这里可以查看Demo效果</a></em></p>" <p>注意,对象值并无关联。</p> <pre><code>&lt;svg width="350" height="150" viewBox="0 0 300 300" preserveAspectRatio="xMinYMid slice" style="border: 1px solid #333333;"&gt; &lt;!--&lt;path &lt;cherry drawing path&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/preservenocorrelate.png" alt="Cherries" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/63e0bed4bd9b7519da1c2f287963d4f6">点击这里查看Demo效果</a></em></p>" <p>上面的例子中<code>preserveAspectRatio</code>的值为<code>xMinYMid slice</code>,这些樱桃现在没有沿着<code>viewport</code>的<code>y</code>轴的中间方向排列。</p> <h3>坐标系统变换</h3> <p>使用<code>transform</code>可以让SVG的图形做旋转、缩放、位移和扭曲等操作。SVG作者可以将<code>transform</code>应用于单个元素或整个元素组。</p> <p>在元素中使用<code>&lt;transform&gt;</code>属性,将这些变换函数用于SVG元素中。这个属性中包含多个函数,言外之外你可以使用多个变形,例如:<code>transform="translate(&lt;tx&gt;,&lt;ty&gt;) rotate(&lt;rotation angle&gt;)" /&gt;</code>。</p> <p>在操作SVG变形时有一点需要特别注意,它将会影响您的坐标系统或工作区。这是因为<a href="http://www.w3.org/TR/SVG/coords.html#EstablishingANewUserSpace">变形创建了一个新的用户空间</a>,本质上是复制原来的,然后将变形放置在新的系统本身上。</p> rel="nofollow" <p>下图演示了在包含图形的组中进行<code>(100,100)</code>位移变形时发生的坐标系统变换。</p> <p><img src="/sites/default/files/blogs/2017/1712/transformcoord.png" alt="Translated coordinate system" /></p> <p>坐标系统本身已经位移了,而酸橙(lime)和柠檬(lemon)的两个图像在各自的系统中保持了原来的位置。新的用户坐标系统在原来的坐标系统中的<code>(100, 100)</code>位置处。</p> <p>由于坐标系统的关系,这些函数将会移动图形,即使你没有直接在它上面设置<code>transition</code>。例如,将<code>scale</code>的值设置为<code>3</code>,将会试图将图形放大三倍,<code>x</code>和<code>y</code>的坐标都将会乘以<code>3</code>,而图形与它一起缩放,在整个过程中就会移动它。</p> <p>也允许变换嵌套,在这种情况之下,效果将会被累积在一起。因此,子元素的最终变换将基于在它之前的变换的累积。</p> <h4><code>translate</code></h4> <p><code>translate</code>函数指定一个图形的位移细节,两个数值直接指定图形在<code>x</code>和<code>y</code>轴上的位移:<code>transform="translate(&lt;tx&gt;,&lt;ty&gt;)"</code>。这些值可以由空格或逗号分隔。</p> <p>这里的<code>y</code>值是可选的,如果忽略不设置,其值是<code>0</code>。</p> <h4><code>rotate</code></h4> <p><code>rotate</code>的值将指定图形在其原点旋转的度数,而SVG的原点在左上角<code>(0,0)</code>:<code>transform="rotate(&lt;rotation angle&gt;)"</code>。</p> <p>这里还有一个选项,包括<code>x</code>和<code>y</code>的值:<code>transform=rotate(&lt;rotation angle&gt; [&lt;cx&gt;,&lt;cy&gt;])</code>。如果提供了,这些值将建立一个新的旋转中心,而不是默认值<code>(0,0)</code>。</p> <p>下图是一个苹果未做旋转和旋转<code>20deg</code>之后的效果:<code>transform="rotate(20)"</code>。<strong>注意,此图像并不反映该旋转所产生的坐标变换。</strong></p> <p><img src="/sites/default/files/blogs/2017/1712/rotationapple.png" alt="Rotated apple" /></p> <h4><code>scale</code></h4> <p>通过<code>scale</code>函数可以调整SVG图形的缩放。该函数接受一个或两个值,其中指定了元素在<code>x</code>轴和<code>y</code>轴上的缩放值:<code>transform="scale(&lt;sx&gt; [&lt;sy&gt;])"</code>。</p> <p><code>sy</code>的值是可选的,如果未显式设置,它的值为<code>sx</code>,以确保正常调整图形大小。</p> <p><code>scale</code>的值如果是<code>.5</code>,图形将是原图形的一半大小,而<code>3</code>的值将会把原图形放大三倍。如果是一个<code>4,2</code>的值,图形的宽度是原图宽的四倍,高是原图高的两倍。</p> <h4><code>skew</code></h4> <p>通过使用<code>skewX</code>和<code>skewY</code>可以让SVG元素扭曲。这两个函数中包含的值表示沿对应轴做适当的倾斜变换。</p> <p>下图是苹果图莆添加<code>skewX</code>值<code>20</code>:<code>transform="skewX(20)"</code>前后的效果。<strong>注意,此图形不反映该变换所产生的坐标变化。</strong></p> <p><img src="/sites/default/files/blogs/2017/1712/skewapple.png" alt="Skewed apple" /></p> <h2>第4节: 填充和描边</h2> <p><code>fill</code>和<code>stroke</code>允许我们填充SVG和绘制其边框。</p> <p><a href="http://xxysy.com/quot;//www.w3.org/TR/SVG/painting.html#Introduction">绘制(Paint)</a>指的是通过<code>fill</code>和(或)<code>stroke</code>给SVG图形添加颜色、渐变或图案等。</p>" <h3><code>fill</code>属性</h3> <p><code>fill</code>属性就要用来绘制图形元素的内部。这个填充可以是纯色、渐变或图案。</p> <p>图形内部是通过检查<code>fill-rule</code>中列出的所有子路径和规范来确定的。</p> <p>当填充一个形状或路径时,<code>fill</code>将会画出一条开放的路径,就像路径的第一个点连接最后一个点一样,即使路径上的<code>stroke</code>颜色也不会被呈现。</p> <h4><code>fill-rule</code></h4> <p><code>fill-rule</code>属性表示用于确定画布中哪些部分在形状内部的算法。在使用更复杂的交叉或封装路径时,这并不那么简单。</p> <p>其接受的值主要有:<code>nonzero</code>、<code>evenodd</code>和<code>inherit</code>。</p> <h5><code>nonzero</code></h5> <p><code>nonzero</code>的值决定了画布内的一个点,通过这个点的任意方向上绘制一条线,然后再考虑穿过这条线另一个部分形状的位置。这将从零开始,并在每次路径段从左到右的时候添加一个路径,每次路径段从右到左的时候再减去一次。</p> <p>如果在计算和计算这些交集之后得到的结果是零,那么这个点就在路径之外,否则它就在里面。</p> <p><img src="/sites/default/files/blogs/2017/1712/fillrulenonzero.png" alt="nonzero fill-rule" /></p> <p>从本质上讲,如果将内部路径按顺时针方向画,它将被认为是内(<code>inside</code>),但如果按逆时针方向画,则会被讷为是外(<code>outside</code>),因此被排除在绘制之外。</p> <h5><code>evenodd</code></h5> <p><code>evenodd</code>的值决定了画布上一个区域的内部,通过在任何方向上通过整个形状绘制一条线,并计算出线交叉的路径段。如果这个结果是奇数,那么这个点就在里面,如果是偶数,则这个点在外面。</p> <p><img src="/sites/default/files/blogs/2017/1712/fillruleevenodd.png" alt="evenodd fill-rule" /></p> <p>考虑到<code>evenodd</code>的具体算法,内部图形绘制的方向是无关的,这个与非零不同的是,只是在计算它们穿过直线时的路径。</p> <p>虽然这个属性通常不是必需的,但是它将允许更大的<code>fill</code>,用于控制一个复杂的图形,如上所述。</p> <h5><code>inherit</code></h5> <p><code>inherit</code>的值将引导元素接受其父元素指定的<code>fill-rule</code>。</p> <h4><code>fill-opacity</code></h4> <p><code>fill-opacity</code>的值是指内部填充的不透明度。<code>0</code>表示完全透明,<code>1</code>表示不透明,两者之间的值代表了一个基于百分比的不透明度。</p> <h3>描边属性</h3> <p>在SVG中有许多与描边有关的属性,允许你在绘制图形时控制和操作描边的细节。这些属性提供的能力能让你更好的手工编写SVG代码,更好的控制绘制的图形。当需要对嵌入的图形进行编辑时,也能更方便的操作。</p> <p>下面的例子使用了内联的SVG,绘制了一个葡萄。被使用的属性直接在图形元素当中。</p> <h4><code>stroke</code></h4> <p><code>stroke</code>属性定义了特定图形和路径的边框。</p> <p>比如下面的葡萄图形有一个紫色的描边效果:<code>stroke="#765373"</code>:</p> <p><img src="/sites/default/files/blogs/2017/1712/stroke1.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/c54df7a7715a7ca9163df9868c2ee699">点击这里可以查看Demo效果</a></em></p>" <h4><code>stroke-width</code></h4> <p><code>stroke-width</code>值设置了描边的粗累,比如使用此属性设置葡萄描边的粗细,如上图的紫色葡萄,它的值就设置了<code>6px</code>。</p> <p>该属性的默认值为<code>1</code>。如果使用百分比值,将会基于<code>viewport</code>的尺寸来进行计算。</p> <h4><code>stroke-linecap</code></h4> <p><code>stroke-linecap</code>定义了开放路径的终点(也称为线帽),其有四个值:<code>butt</code>、<code>round</code>、<code>square</code>和<code>inherit</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/strokelinecap.png" alt="Grapes" /></p> <p><code>inherit</code>的值将指定元素继承其父元素指定的<code>stroke-linecap</code>。</p> <p>下图是葡萄茎图形的<code>stroke-linecap</code>设置为<code>square</code>的效果:</p> <pre><code>&lt;svg&gt; &lt;!--&lt;path &lt;path for grapes&gt; /&gt;--&gt; &lt;!--&lt;path stroke-linecap="square" &lt;path for stem&gt; /&gt;--&gt; &lt;!--&lt;path &lt;path for leaf&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/strokesquarestem.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/210d9a8a7d3dba61b021c02b94575512">点击这里查看Demo效果</a></em></p>" <h4><code>stroke-linejoin</code></h4> <p><code>stroke-linejoin</code>定义了路径和基本形状连接处的风格。</p> <p><img src="/sites/default/files/blogs/2017/1712/strokelinejoin.png" alt="Grapes" /></p> <p>下面使用<code>stroke-linejoin</code>定义了葡萄形状连接处的风格为<code>bevel</code>:</p> <pre><code>&lt;svg&gt; &lt;!--&lt;path stroke-linejoin="bevel" &lt;path for grapes&gt; /&gt;--&gt; &lt;!--&lt;path &lt;path for stem&gt; /&gt;--&gt; &lt;!--&lt;path &lt;path for leaf&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/strokebevel.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/b2b49681ed92c0a7063123421879d15d">点击这里查看Demo效果</a></em></p>" <h5><code>stroke-miterlimit</code></h5> <p>当两条线相交于成一个角,并设置为<code>stroke-linejoin="miter"</code>,其中<code>stroke-miterlimit</code>属性允许指定这个角延伸的距离。</p> <p>这个连接的长度被称为<code>miter</code>长度,它是从线的内角连接到外端的距离。</p> <p>这个值是指<code>miter</code>长度受<code>stroke-width</code>的限制。</p> <p>这个属性的最小的可能值是<code>1.0</code>。</p> <p>第一个葡萄图形设置了<code>stroke-miterlimit="1.0"</code>,这将产生了一个斜角效果。第二个葡萄的图形设置了<code>stroke-miterlimit="4.0"</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/strokemiterlimit.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/a0afcecca7a8c19a305ff3edb2adddf1">点击这里可以查看Demo效果</a></em></p>" <h4><code>stroke-dasharray</code></h4> <p><code>stroke-dasharray</code>属性把路径变成了破折线,而不是实线。</p> <p>在这个属性中,您可以指定破折线的长度,使用逗号或空格来分隔破折号之间的距离。</p> <p>如果提供的值是奇数值,表示该列表值将会重复,以产生偶数个数值。比如<code>8,6,4</code>将变成<code>8,6,4,8,6,4</code>,如下图所示。</p> <p>在这个值中只放置一个数字,就会在破折线之间的空间中产生等于相同长度的破折线。</p> <p><img src="/sites/default/files/blogs/2017/1712/strokedasharray.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/0e6de428698ed9a202fb05fdac1c806c">点击这里查看Demo效果</a></em></p>" <p>第一个葡萄图形展示了一个偶数值时的葡萄图形效果:<code>stroke-dasharray="20,15,10,8"</code>。</p> <h4><code>stroke-dashoffset</code></h4> <p><code>stroke-dashoffset</code>属性用来指定破折号之间的距离。</p> <pre><code>&lt;svg&gt; &lt;!--&lt;path stroke-dasharray="40,10" stroke-dashoffset="35" &lt;path for grapes&gt; /&gt;--&gt; &lt;!--&lt;path &lt;path for stem&gt; /&gt;--&gt; &lt;!--&lt;path &lt;path for leaf&gt; /&gt;--&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/strokedashoffset.png" alt="Grapes" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/ec8d136c05ac274f3343a7fd64bb2203">点击这里查看Demo效果</a></em></p>" <p>在上面的例子中,破折线设置了<code>40px</code>长度,以及<code>dashoffset</code>的值设置为<code>35px</code>。在路径的起始点,在<code>35px</code>到<code>40px</code>的破折线将不会出现,这就是为什么第一个破折号显得更短。</p> <h4><code>stroke-opacity</code></h4> <p><code>stroke-opacity</code>属性用来设置描边的透明度。</p> <p>他的值是<code>0</code>到<code>1</code>之间,其中<code>0</code>是表示描边完全透明,不可见。</p> <h2>第5节: <code>text</code>元素</h2> <p><code>&lt;text&gt;</code>元素定义了由文本组成的图形。有许多属性选项可以定制文本图形,而且渐变、图案、剪切路径、蒙板和过滤器也可以应用在<code>text</code>元素之上。</p> <p>SVG提供了能力强大的<code>&lt;text&gt;</code>元素,用于创建可伸缩的文本作为图形,而且易于在SVG代码中修改和编辑。</p> <p>在使用本节中提到的示例时,要特别注意<code>viewport</code>尺寸。正如前面提到的,<code>viewport</code>将决定SVG的可见部分,有时有必要根据修改的细节来更改<code>viewport</code>。</p> <h3>基本属性</h3> <p>SVG的文本属性位于<code>&lt;text&gt;</code>元素内,该元素放置在<code>&lt;svg&gt;</code>元素内。通过这些属性,可以控制文本的一些基本样式,并在画布上完全呈现其映射的细节,从而完全控制它在屏幕上的效果。</p> <h4><code>x</code>, <code>y</code>, <code>dx</code>, <code>dy</code></h4> <p><code>&lt;text&gt;</code>元素中的第一个字母是根据已创建的坐标系统中的<code>x</code>和<code>y</code>值来呈现的。<code>x</code>值决定了文本在<code>x</code>轴上开始位置处,而<code>y</code>值决定了文本底部的水平位置。</p> <p><code>x</code>和<code>y</code>在坐标系统中是绝对坐标,而<code>dx</code>和<code>dy</code>是相对坐标。当与<code>&lt;tspan&gt;</code>元素一起使用时,这一点特别方便,这将在接下来的部分中进行讨论。</p> <pre><code>&lt;svg width="620" height="100"&gt; &lt;text x="30" y="90" fill="#ED6E46" font-size="100" font-family="'Leckerli One', cursive"&gt;Watermelon&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/watermelontext1.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/e62394e43969fecb4269036260a3a575">点击这里可以查看Demo效果</a></em></p>" <p>上面的文本距SVG的<code>viewport</code>中左侧距离<code>30px</code>,而文本底部则从<code>viewport</code>顶部<code>90px</code>处。即:<code>x="30" y="90"</code>。</p> <h4><code>rotate</code></h4> <p>可以将旋转放置在单个字母(字符)或者整个元素上。</p> <p><code>rotate</code>属性中的单个值会导致每个符号在该值上旋转。一系列值也可以用于文本的每个字母,并为每个字母分配不同的旋转值。如果没有足够的值来匹配字母的数量,最后一个值将为其他字母设置旋转。</p> <p>下面的文本通过<code>transform</code>给每个文本设置旋转效果,每个字母的旋转的值: <code>rotate="20,0,5,30,10,50,5,10,65,5"</code>。</p> <pre><code>&lt;svg width="600" height="250"&gt; &lt;text x="30" y="80" fill="#ED6E46" font-size="100" rotate="20,0,5,30,10,50,5,10,65,5" transform="rotate(8)" font-family="'Leckerli One', cursive"&gt;Watermelon&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/watermelonrotation.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/d46fe22b170668927920220e13c1093f">点击这里查看Demo效果</a></em></p>" <h4><code>textLength</code>和<code>lengthAdjust</code></h4> <p><code>textLength</code>属性指定文本的长度。文本的长度将通过改变所提供的字符之间的空格来适应该属性中指定的长度。</p> <p>下面的例子有一个<code>textLength</code>值为<code>900px</code>。得注意的是,字符之间的间距增加了,以填充这个空间。</p> <pre><code>&lt;svg width="950" height="100"&gt; &lt;text x="30" y="90" fill="#ED6E46" font-size="100" textLength="900" font-family="'Leckerli One', cursive"&gt;Watermelon&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/watermelonspacing.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/3020091b8dbd6e77c22827d6c31e35fc">点击这里查看Demo效果</a></em></p>" <p>当和<code>lengthAdjust</code>属性一起使用时,可以指定字母间距和字形大小都应该调整以适应这些新的长度值。</p> <p><code>"spacing"</code>的值与上面的例子类似,在上面的例子中,字符的间距扩大到填充空间:<code>lengthAdjust=”spacing”</code>。</p> <p><code>"spacingAndGlyphs"</code>的值指定了间距和字形的大小来做相应的调整:<code>lengthAdjust="spacingAndGlyphs"</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/watermelonlengthadjust.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/dec7865c1584e965742d52151236db65">点击这里查看Demo效果</a></em></p>" <h3><code>tspan</code>元素</h3> <p><code>&lt;tspan&gt;</code>元素很重要,因为SVG目前不支持自动换行。<code>&lt;tspan&gt;</code>允许我们通过将某些单词或字符单独进行操,用来绘制多行文本。</p> <p>而不是为这些额外的行定义一个新的坐标系统,<code>&lt;tspan&gt;</code>元素将这些新的文本行与上一行的文本关联起来。</p> <p><code>&lt;tspan&gt;</code>元素本身并不会输出可见的的东西,但是通过在元素中指定更多的细节,我们可以将该文本单独输出,并对其设计和定位有更多的控制。</p> <p>在下面的示例中,<code>"are"</code>和<code>"delicious"</code>位于<code>&lt;text&gt;</code>元素的<code>&lt;span&gt;</code>元素中。通过在每个<code>span</code>中的<code>dy</code>,可以将这个词沿着<code>y</code>轴与前面的词关联起来。</p> <p>虽然<code>"are"</code>的位置在<code>"Watermelons"</code>的<code>-30px</code>位置处,但<code>"delicious"</code>的位置是<code>50px</code>。</p> <pre><code>&lt;svg width="775" height="500"&gt; &lt;text x="15" y="90" fill="#ED6E46" font-size="60" font-family="'Leckerli One', cursive"&gt; Watermelons &lt;tspan dy="-30" fill="#bbc42a" font-size="80"&gt;are&lt;/tspan&gt; &lt;tspan dy="50"&gt;delicious&lt;/tspan&gt; &lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/watermelontspan.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/ea83c21659cf118df5b5d64b14b2a1c9">点击这里查看Demo效果</a></em></p>" <p>你还可以通过一个列表值单独移二甲双胍每个字母,如下面的示例所示。字母和符号随后根据字母和符号的位置移动,<code>"delicious"</code>现在根据<code>"are"</code>中的<code>"e"</code>位置定位。</p> <p><img src="/sites/default/files/blogs/2017/1712/watermelontspan2.png" alt="Watermelon Text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/943ca861a5154a2e2fbe3394d2031fda">点击这里查看Demo效果</a></em></p>" <p>包含<code>"are"</code>的<code>tspan</code>有以下<code>dy</code>值:<code>dy="-30 30 30"</code>。</p> <h3>间距属性</h3> <p>当在内联SVG中使用<code>&lt;text&gt;</code>元素来控制单词和字母的间距时,可以使用许多属性,类似于矢量图形软件的功能。</p> <p>了解如何使用这些属性有助于确保图形完全按照预期显示。</p> <h4><code>kerning</code>和<code>letter-spacing</code></h4> <p><code>kerning</code>指的是调整字符间距的过程。<code>kerning</code>属性允许我们根据使用的字体中包含的<code>kerning</code>来调整这个空间,或者设置一个独特的长度。</p> <p><code>auto</code>值表示字形间距应该基于所使用的字体中包含的<code>kerning</code>列表。</p> <p>下面的例子中<code>kerning</code>的值为<code>auto</code>,在这个示例中,它没有可见的影响,因为它是默认值。</p> <pre><code>&lt;svg width="420" height="200"&gt; &lt;text x="2" y="50%" fill="#ef9235" font-size="100" font-family="'Raleway', sans-serif" font-weight="bold" kerning="auto"&gt;Oranges&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/orangekerning.png" alt="Oranges Text" /></p> <p>调整这些字符之间的长度可以简单地包括一个数值:<code>kerning="30"</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/orangekerning2.png" alt="Oranges Text" /></p> <p><code>inherit</code>的值也是有效的。</p> <p><code>letter-spacing</code>的值有<code>normal</code>、<code>&lt;length&gt;</code>和<code>inherit</code>。这里的数值与<code>kerning</code>的间距有相同的效果。<code>letter-spacing</code>的属性是已经从<code>kerning</code>生效的补充间距。</p> <h4><code>word-spacing</code></h4> <p><code>word-spacing</code>属性是用来指定单词之间的间距。</p> <pre><code>&lt;svg width="750" height="200"&gt; &lt;text x="2" y="50%" fill="#ef9235" font-size="70" font-family="'Raleway', sans-serif" word-spacing="30"&gt;Oranges are Orange&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/orangewordspace.png" alt="Oranges Text" /></p> <p>其他有效的值还包括<code>normal</code>(默认值)和<code>inherit</code>。</p> <h3><code>text-decoration</code></h3> <p><code>text-decoration</code>属性允许在SVG的文本图形上添加下划线,其值包括:<code>underline</code>、<code>overline</code>和<code>line-through</code>。</p> <p>虽然绘制图形的顺序并不总是会对SVG图形输出产生影响,但是<code>text-decoration</code>方面顺序确实很重要。<code>text-decoration</code>所有值(除了<code>line-throught</code>之外),应该在文本填充和描边之前使用这个属性。</p> <p><code>line-through</code>应该在文本填充或描边后绘制,不然将会在文本的顶部呈现。</p> <p>下面的效果是使用了<code>text-decoration="underline"</code>和<code>text-decoration="line-through"</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/textdecoration.png" alt="Pears Text" /></p> <h3>沿着路径的文本</h3> <p>正如前面提到的,内联SVG为我们提供了与矢量图形软件类似的高级定制选项。在SVG代码中,我们可以准确定位文本,就像我们希望它在屏幕上显示一样。</p> <p>在进一步处理此操作时,SVG的<code>&lt;text&gt;</code>可以根据<code>&lt;path&gt;</code>元素,指定文本根据路径呈现文本。</p> <h4><code>textPath</code>元素</h4> <p><code>textPath</code>元素是这个特性所有魔法所在。虽然SVG的文本在<code>&lt;text&gt;</code>元素内,而<code>&lt;textPath&gt;</code>元素在<code>&lt;text&gt;</code>元素内。</p> <p>这个<code>&lt;textPath&gt;</code>元素将调用所选择的<code>id</code>路径,它在<code>&lt;defs&gt;</code>元素中等待被使用。</p> <p>基本语法如下:</p> <pre><code>&lt;svg&gt; &lt;defs&gt; &lt;path id="testPath" d="&lt;....&gt;"/&gt; &lt;/defs&gt; &lt;text&gt; &lt;textPath xlink:href="http://xxysy.com/quot;#testPath"&gt;Plac" text here&lt;/textPath&gt; &lt;/text&gt; &lt;/svg&gt; </code></pre> <p>下面是代码中使用的向量路径:</p> <p><img src="/sites/default/files/blogs/2017/1712/pathsimple.png" alt="Simple path" /></p> <p>在矢量图形软件中生成此路径后,SVG的<code>&lt;path&gt;</code>元素代码本身(不包括如上所示的颜色),可以在<code>&lt;svg&gt;</code>中复制并放置在<code>&lt;svg&gt;</code>中,同时也显示在上面的代码中。</p> <p><img src="/sites/default/files/blogs/2017/1712/pathsimpletext.png" alt="Simple path with text" /></p> <pre><code>&lt;svg width="620" height="200"&gt; &lt;defs&gt; &lt;path id="testPath" d="M3.858,58.607 c16.784-5.985,33.921-10.518,51.695-12.99c50.522-7.028,101.982,0.51,151.892,8.283c17.83,2.777,35.632,5.711,53.437,8.628 c51.69,8.469,103.241,11.438,155.3,3.794c53.714-7.887,106.383-20.968,159.374-32.228c11.166-2.373,27.644-7.155,39.231-4.449" /&gt; &lt;/defs&gt; &lt;text x="2" y="40%" fill="#765373" font-size="30" font-family="'Lato', sans-serif"&gt; &lt;textPath xlink:href="http://xxysy.com/quot;#testPath"&gt;Ther" are over 8,000 grape varieties worldwide.&lt;/textPath&gt; &lt;/text&gt; &lt;/svg&gt; </code></pre> <h5><code>xlink:href</code></h5> <p><code>xlink:href</code>是<code>&lt;textPath&gt;</code>的属性,允许我们引用文本根据指定的路径呈现。</p> <h5><code>startOffset</code></h5> <p><code>startOffset</code>属性表示从<code>path</code>开始时的文本偏移长度。<code>0%</code>的值表示<code>path</code>的起始点,而<code>100%</code>表示终点。</p> <p>下面的例子有一个<code>20%</code>的<code>startoffset</code>,它推动文本在路径的<code>20%</code>处开始。当移动时,字体大小已经减少,以防止它从<code>viewport</code>中呈现出来。</p> <p>通过<code>&lt;use&gt;</code>元素添加路径的描边颜色,可以帮助我们理解这里发生的事情。</p> <pre><code>&lt;svg width="620" height="200"&gt; &lt;defs&gt; &lt;path id="testPath" d="M3.858,58.607 c16.784-5.985,33.921-10.518,51.695-12.99c50.522-7.028,101.982,0.51,151.892,8.283c17.83,2.777,35.632,5.711,53.437,8.628 c51.69,8.469,103.241,11.438,155.3,3.794c53.714-7.887,106.383-20.968,159.374-32.228c11.166-2.373,27.644-7.155,39.231-4.449" /&gt; &lt;/defs&gt; &lt;use xlink:href="http://xxysy.com/quot;#testPath"" fill="none" stroke="#7aa20d" stroke-width="2"/&gt; &lt;text x="2" y="40%" fill="#765373" font-size="20" font-family="'Lato', sans-serif"&gt; &lt;textPath xlink:href="http://xxysy.com/quot;#testPath"" startOffset="20%"&gt;There are over 8,000 grape varieties worldwide. &lt;/textPath&gt; &lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/pathsimpletext2.png" alt="Simple path with text" /></p> <p><em><a href="http://xxysy.com/quot;//codepen.io/jonitrythall/pen/b60cb49eb60d4db158fc9c81b1b6cd64">点击这里查看Demo效果</a></em></p>" <h2>第6节: 高级特性——渐变,图案,剪辑路径</h2> <h3>渐变</h3> <p>SVG渐变有两种类型:线性渐变和径向渐变。线性渐变是在直线上产生的,而径向渐变是圆形的。</p> <p>一个非常简单的线性渐变就像下面这样:</p> <pre><code>&lt;svg&gt; &lt;defs&gt; &lt;linearGradient id="gradientName"&gt; &lt;stop offset="&lt;%&gt;" stop-color="&lt;color&gt;" /&gt; &lt;stop offset="&lt;%&gt;" stop-color="&lt;color&gt;" /&gt; &lt;/linearGradient&gt; &lt;/defs&gt; &lt;/svg&gt; </code></pre> <p><code>&lt;svg&gt;</code>包含一个<code>&lt;defs&gt;</code>元素,允许我们创建可重用的声明,以便稍后调用。这些定义输出用户并不可见,下到它们在描边或填充中被使用唯一的<code>id</code>时,才会在SVG的图形或<code>&lt;text&gt;</code>中被调用。这些图形或文本在<code>&lt;svg&gt;</code>元素中,但在<code>&lt;defs&gt;</code>元素之外。</p> <p>一旦建立了一个渐变并分配一个<code>id</code>,它就可以通过SVG中的<code>fill</code>或<code>stroke</code>属性来调用。例如:<code>fill= "url(#gradientName)"</code>。</p> <h4>线性渐变</h4> <p>线性渐变沿着一条直线改变颜色,在这个直线上定义的每个点将代表<code>&lt;linearGradient&gt;</code>元素内关联颜色。在每一个点上,颜色都是<code>100%</code>的饱和,中间的空间表示从一种颜色过渡到下一种颜色。</p> <h5>停止节点</h5> <p><code>&lt;stop&gt;</code>节点可以使用<code>stop-opacity="&lt;value&gt;"</code>来设置透明度。</p> <p>下面是一个简单的线性渐变的示例代码,应用于矩形的两个颜色的线性渐变:</p> <pre><code>&lt;svg width="405" height="105"&gt; &lt;defs&gt; &lt;linearGradient id="Gradient1" x1="0" y1="0" x2="100%" y2="0"&gt; &lt;stop offset="0%" stop-color="#BBC42A" /&gt; &lt;stop offset="100%" stop-color="#ED6E46" /&gt; &lt;/linearGradient&gt; &lt;/defs&gt; &lt;rect x="2" y="2" width="400" height="100" fill= "url(#Gradient1)" stroke="#333333" stroke-width="4px" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/gradientpic1.png" alt="Basic Gradient" /></p> <p><code>offset</code>用来指定线性渐变的<code>stop-color</code>的位置。</p> <h5><code>x1</code>, <code>y1</code>, <code>x2</code>, <code>y2</code></h5> <p><code>x1</code>,<code>y1</code>,<code>x2</code>和<code>y2</code>属性值表示渐变停止(颜色变化)映射的开始和结束点。这些百分数将沿适当的轴分别绘制渐变。</p> <p><code>100%</code>的<code>y</code>的值和<code>0</code>的<code>x</code>值将产生水平渐变,反之则会产生垂直渐变。将两个值设置为<code>100%</code>(或<code>0</code>之外的任何值)将会创建一个倾斜的渐变。</p> <h5><code>gradientUnits</code></h5> <p><code>gradientUnits</code>属性定义了<code>x1</code>、<code>x2</code>、<code>y1</code>和<code>y2</code>值的坐标系统。这里有两个选项:<code>userSpaceOnUse</code>或 <code>objectBoundingBox</code>。<code>userSpaceOnUse</code>使用的是坐标系统中的绝对单元值,而<code>objectBoundingBox</code>(默认值)在SVG图形本身的范围建立这个系统(相对坐标值)。</p> <h5><code>spreadMethod</code></h5> <p><code>spreadMethod</code>属性的值指定渐变如何在目标范围内展开或结束。如果渐变不在图形的填充中使用,<code>spreadMethod</code>将会决定渐变应该如何覆盖那个空白区域。这里有三个值可选:<code>pad</code>、<code>repeat</code>和<code>reflect</code>。</p> <p><code>pad</code>(默认值)的值指定渐变的第一个和最后一个颜色在未被发现的目标区域的其余部分展开。<code>repeat</code>的值指定渐变从一开始就重复使用这个模式。<code>reflect</code>的值指定渐变的从开始到结束的渐变模式,连续不断的执行。</p> <p>下面的渐变的开始和结束点是:<code>x1="20%" y1="30%" x2="40%" y2="80%"</code>。</p> <p><img src="/sites/default/files/blogs/2017/1712/gradientspreadmethod.png" alt="Spread method" /></p> <h5><code>gradientTransform</code></h5> <p><code>gradientTransform</code>属性是可选的,并允许给渐变添加旋转等功能。</p> <h5><code>xlink:href</code></h5> <p><code>xlink:href</code>属性允许你调用另一个渐变的<code>id</code>所有的信息,但你也可以包含不同的值。</p> <pre><code>&lt;linearGradient id="repeat" xlink:href="http://xxysy.com/quot;#Gradient-1" spreadMethod="repeat" /&gt; </code></pre> <p>渐变从本节点开始就继承了第一个渐变的细节,但是有一个<code>spreadMethod</code>值。</p> <h4>径向渐变</h4> <p><code>&lt;radialGradient&gt;</code>的大多数属性与<code>&lt;linearGradient&gt;</code>相同,除非有不同的坐标系统。</p> <h5><code>cx</code>, <code>cy</code>, <code>r</code></h5> <p><code>cx</code>,<code>cy</code>和<code>y</code>属性定义了圆的最外层,而渐变的<code>100%</code>的<code>stop-color</code>将这个值映射到圆的周长上。<code>cx</code>和<code>cy</code>定义了径向渐变的圆心,而<code>r</code>则是设置径向渐变的半径。</p> <h5><code>fx</code>, <code>fy</code></h5> <p><code>fx</code>和<code>fy</code>属性代表了渐变的焦点,或者说是最内层圆的坐标。本质上,渐变的中心不需要它的焦点,可以用这些值来改变它。</p> <p>默认情况下,径向渐变的焦点将能圆的中心为中心,焦点属性可以改变这一点。以下图像的焦点值为:<code>fx="95%" fy="70%"</code>:</p> <pre><code>&lt;svg width="850px" height="300px"&gt; &lt;defs&gt; &lt;radialGradient id="Gradient2" cy="60%" fx="95%" fy="70%" r="2"&gt; &lt;stop offset="0%" stop-color="#ED6E46" /&gt; &lt;stop offset="10%" stop-color="#b4c63b" /&gt; &lt;stop offset="20%" stop-color="#ef5b2b" /&gt; &lt;stop offset="30%" stop-color="#503969" /&gt; &lt;stop offset="40%" stop-color="#ab6294" /&gt; &lt;stop offset="50%" stop-color="#1cb98f" /&gt; &lt;stop offset="60%" stop-color="#48afc1" /&gt; &lt;stop offset="70%" stop-color="#b4c63b" /&gt; &lt;stop offset="80%" stop-color="#ef5b2b" /&gt; &lt;stop offset="90%" stop-color="#503969" /&gt; &lt;stop offset="100%" stop-color="#ab6294" /&gt; &lt;/radialGradient&gt; &lt;/defs&gt; &lt;text x="20%" y="75%" fill= "url(#Gradient2)" font-family= "'Signika', sans-serif" font-size="200"&gt;Cherry&lt;/text&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/gradientfocalpoint.png" alt="Focal point" /></p> <p>在这个示例中,焦点转移到图像的右下角。</p> <h3>图案</h3> <p>图案通常被认为是用<code>fill</code>和<code>stroke</code>来给SVG图形来填充或描边更复杂的图形。理解图案的基本语法可以使这些看起来复杂的图案变得更容易。</p> <p>下面是用于图案来填充矩形的基本语法:</p> <pre><code>&lt;svg width="220" height="220"&gt; &lt;defs&gt; &lt;pattern id="basicPattern" x="10" y="10" width="40" height="40" patternUnits="userSpaceOnUse"&gt; &lt;circle cx="20" cy="20" r="20" fill= "#BBC42A" /&gt; &lt;/pattern&gt; &lt;/defs&gt; &lt;rect x="10" y="10" width="200" height="200" stroke="#333333" stroke-width="2px" fill="url(#basicPattern)" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/patternbasic1.png" alt="Basic pattern" /></p> <h4>基本属性</h4> <p>图案的属性和值定义了画布、设计和整体位置。图案可以由路径或图形组成,可以绘制文本,甚至可以嵌套在另一个图案中。</p> <h5><code>x</code>, <code>y</code>, <code>width</code>, <code>height</code></h5> <p><code>&lt;pattern&gt;</code>元素的<code>x</code>和<code>y</code>属性定义了图案从图形哪个位置开始。在<code>&lt;pattern&gt;</code>元素内使用<code>width</code>和<code>height</code>定义了图案的宽度和高度。</p> <p>上面引用的<code>basicPattern</code>包含了<code>x="10" y="10" width="40" height="40"</code>。表示从<code>x</code>轴的<code>10px</code>,<code>y</code>轴的<code>10px</code>处开始,创建一个<code>40px</code>的宽和<code>40px</code>的高的画布。</p> <h5><code>patternUnits</code></h5> <p><code>patternUnits</code>属性定义了<code>x</code>、<code>y</code>、<code>width</code>和<code>height</code>所引用的坐标。这里有两个选项:<code>userSpaceOnUse</code>和<code>objectBoundingBox</code>(默认值)。</p> <p><code>userSpaceOnUse</code>在图案坐标系统由引用<code>&lt;pattern&gt;</code>元素的坐标系统决定,而<code>objectBoundingBox</code>则建立映射坐标系统基于该图案所应用的元素的容器。</p> <h5><code>patternContentUnits</code></h5> <p><code>patternContentUnits</code>属性的值与<code>patternUnits</code>的值相同,只是现在为图案本身的内容定义了坐标系统。</p> <p>与<code>patternUnits</code>不同,这个值默认为<code>userSpaceOnUse</code>,这意味着除非其中一个或两个属性被指定为<code>&lt;pattern&gt;</code>中所绘制的形状,否则它们将被绘制在不同的坐标系统中,而不是<code>&lt;pattern&gt;</code>元素所使用的。</p> <p>在<code>&lt;pattern&gt;</code>元素中定义<code>patternUnits="userSpaceOnUse"</code>简化了这个过程,并确保了一个一致的工作区域。</p> <h4>图案嵌套</h4> <p>图案也可以嵌套,以创建更加独特和详细的设计。</p> <p>下面是图案嵌套的一个基本结构:</p> <pre><code>&lt;svg width="204" height="204"&gt; &lt;defs&gt; &lt;pattern id="circlePattern" x="4" y="4" width="75" height="75" patternUnits="userSpaceOnUse"&gt; &lt;circle cx="12" cy="12" r="8" stroke="#ed6e46" stroke-width="3" fill="#765373" /&gt; &lt;/pattern&gt; &lt;pattern id="rectPattern" x="10" y="10" width="50" height="50" patternUnits="userSpaceOnUse"&gt; &lt;rect x="2" y="2" width="30" height="30" stroke="#bbc42a" stroke-width="3" fill="url(#circlePattern)" /&gt; &lt;/pattern&gt; &lt;/defs&gt; &lt;rect x="2" y="2" width="200" height="200" stroke="#333333" stroke-width="3" fill="url(#rectPattern)" /&gt; &lt;/svg&gt; </code></pre> <p><code>&lt;defs&gt;</code>元素包含两个模式。在<code>&lt;defs&gt;</code>中,矩形的图案是通过<code>fill</code>来调用圆形图案,而主矩形则通过<code>fill</code>来调用矩形图案,并将主矩形的内部绘制成嵌套的图案。</p> <p><img src="/sites/default/files/blogs/2017/1712/patternnest.png" alt="Nested pattern" /></p> <h3>剪切路径</h3> <p>剪切咱径限制了将绘制图形应用到SVG的区域。在剪切路径设置的范围之外的任何区域都不会被渲染。</p> <p>为了演示这个功能的特性,让我们使用一个包含<code>“Apple”</code>文本的裁剪路径,它被应用于一个番茄矩形和绿色圆圈。</p> <p>下面是没有使用剪切路径的图形,设置超出<code>viewport</code>的范围。</p> <p><img src="/sites/default/files/blogs/2017/1712/clippingshapes.png" alt="Shapes before clipping" /></p> <p>现在,我们来看看<code>Apple</code>文本应用于画布的代码:</p> <pre><code>&lt;svg width="400px" height="200px"&gt; &lt;clipPath id="clip-text"&gt; &lt;text x="0" y="50%" fill="#f27678" font-size="120px" font-family=" 'Signika', sans-serif"&gt;Apples&lt;/text&gt; &lt;/clipPath&gt; &lt;rect x="0" y="0" width="200" height="200" fill="#ed6e46" clip-path="url(#clip-text)" /&gt; &lt;circle cx="310" cy="100" r="135" fill="#bbc42a" clip-path="url(#clip-text)" /&gt; &lt;/svg&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/clippingtext.png" alt="Text clipping path" /></p> <p>剪切路径在<code>&lt;clipPath&gt;</code>元素中定义,然后通过引用其唯一的<code>id</code>来调用这两个形状。</p> <h2>总结</h2> <p>编写内联SVG是一个非常有用的编辑功能,并使用我们能够独立地访问所有图形元素。在这段代码中,我们生成的图形在不丢失图像质量的情况下,可以增加搜索功能和增强可访问性。</p> <p>它可能需要我们花一些时间掌握修改SVG的能力,但一旦你掌握了这些能力,并且使你的代码尽可能的短和高效,那么就可以开始去<a href="http://xxysy.com/quot;//www.w3.org/TR/smil-animation">探索SMIL动画</a>和尝试<" href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/SVG_and_CSS">用CSS给SVG元素添加样式</a>。</p>" <p>希望这个指南有一定的参考价值,也能让你理解和操作内联SVG提供一定的灵感。</p> <p>有关于相关的更新,请访问<a href="http://xxysy.com/quot;//svgpocketguide.com">本书的网站</a>,如果你有任何关于这本书的问题和评论,可以在<" href="http://xxysy.com/quot;//twitter.com/JoniTrythall">Twitter</a>上或者通过电子邮件<" href="http://xxysy.com/quot;mailto:info@jonibologna.com">info@jonibologna.com</a>与我沟通。</p>" <p><img src="/sites/default/files/blogs/2017/1712/theend2.png" alt="The End" /></p> <blockquote> <p>特别声明:<a href="http://xxysy.com/quot;#简介">简介</a>、<" href="http://xxysy.com/quot;#第1节-文档组织">第1节" 文档组织</a>和<a href="http://xxysy.com/quot;#第2节-基本图形和路径">第2节:基本图形和路径</a>由<" href="http://xxysy.com/quot;//hujiangtech.github.io/tech/">沪江技术学院</a>翻译整理。</p>" </blockquote> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-pocket-guide.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-pocket-guide.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/svg-tutorial"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG</a></div></div></div> Sun, 10 Dec 2017 13:13:14 +0000 Airen 2321 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-on-the-web.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明:本文转载于《<a href="http://xxysy.com/quot;//svgontheweb.com/zh/">SVG应用指南</a>》一文,如需转载,烦请注明原文出处:<" href="//svgontheweb.com/zh/">https://svgontheweb.com/zh/</a>。</p> rel="nofollow" </blockquote> <h2>前言</h2> <p>我们处于一个用像素来作为度量衡的互联网世界中。 对于一名在互联网世界中工作的设计师和开发者来说, 像素对于我们来说亦敌亦友。 我们希望自己创作出的Web中每一张图片、每一像素都能棱角分明(如网站中的<code>logo</code>,<code>icon</code>以及任何修饰性的图片),清晰的在任何设备上展现给用户的同时, 也能尽可能的保证图片的体积来优化性能。而SVG就是解决上面问题非常棒的一个方案。SVG 意为可缩放矢量图形(Scalable Vector Graphics)与屏幕分辨率无关, 体积上能使用Gzip的方式压缩, 而且修改编辑都很方便。</p> <p>本文是SVG在Web开发中一些常见的应用场景、技巧以及使用方法的一个简单的入门指南。</p> <h2>SVG</h2> <p>SVG是一种用 XML 定义的语言,用来描述二维矢量及矢量/栅格图形。 比如常用的矢量设计软件Illustrator中的形状、路径,或者是用Illustrator创作的任何图形都是矢量图形。 SVG是跟Web中常用的JPEG一样是一种的图形格式。 但是SVG比其它图形格式有一个很突出的特点,就是能使用CSS / JS等Web技术对它进行控制。</p> <ul> <li>与分辨率无关</li> <li>被现代浏览器支持</li> <li>面向未来 (W3C 标准)</li> <li>容易编辑</li> <li>使用CSS 和 JS能很方便的进行控制</li> <li>高度可压缩</li> </ul> <h2>使用和优化SVG</h2> <p>在Web中使用 SVG 就像使用JPEG 或者 PNG一样很简单。 使用常见的矢量设计软件(Illustrator,Sketch,或者是PhotoShop中的形状图层) 就能设计出SVG格式的图形。下面所说的操作都是以Illustrator软件为例的(在其它矢量设计软件中可能有所不同)。如果你想要在你的矢量图形中导出特殊的文字,它可能在Web中不会显示正确的字体,除非你使用CSS3中的Webfont来指定显示特定的字体。在Illustrator中,扩展对象可用来将单一对象分割为若干个对象。具体的来说,如果你想单独的控制每一个对象,那就可以使用扩展对象。并且扩展对象并不会影响导出SVG的文件体积。在Illustrator中每一个图层的名字在导出SVG的时候,都会在 SVG作为元素的ID的名字,这对于使用CSS或者是JS来控制SVG提供了很大的便利,但会增加SVG文件的体积哦。</p> <p>在导出的时候, 需要检查下画布的尺寸(比如,不要出现 <code>23.3px × 86.8px</code>) 这样有小数点的格式,如果这样的话它可能会对画布里的内容进行剪裁。在Illustrator,你可以通过下面的操作来避免这个问题,在菜单栏进行下面的操作<code>Object &gt; Artboards &gt; Fit to Artwork Bounds</code>。然后选择 保存为 命令选择保存为 SVG 格式,选择默认的选项就可以了。 当然,在选择保存SVG选项里,也可以进行一定的优化。后面会就SVG的优化有专门的阐述。</p> <h2>SVG文件体积优化的一些技巧</h2> <p>关于SVG优化,网络上有很多的关于这方面的文章。这里我更愿意来分享我在使用SVG过程中,对于SVG优化的一些技巧。这些技巧不需要花费很多额外的工作,你就能快速的你的工作中使用它。</p> <p>为了使SVGs 的体积尽可能的小,你需要删除SVG中一些不需要的属性。在我看来,这方面<a href="http://xxysy.com/quot;//github.com/svg/svgo">SVGO</a>是一个很棒的优化SVG的脚本工具。它会删除SVG中一切多余的属" —— 这里需要注意的一点的是: 当你打算用CSS / JS来控制SVG,你可能要小心了。因为使用它可能会过度优化SVG,从而影响到使用CSS和JS来控制SVG。你可以使用SVGO来自动处理SVG的优化(或者是你可能更愿意使用可视化的<a href="http://xxysy.com/quot;//github.com/svg/svgo-gui">SVG" GUI</a>来处理SVG的优化。</p> <p>其实,删除SVG中一些多余的属性我们在矢量设计软件中就可以来处理。首先你要确保使用尽可能少的路径或者是形状来设计你想要的图形,并且路径上的控制点也要尽可能的少。并且尽可能的合并你的图层。至于删除路径上的控制点,在Illustrator中,<a href="http://xxysy.com/quot;//www.astutegraphics.com/software/vectorscribe/">VectorScribe</a>这个插件就可以做到这点。它可以删除路径上多余的控制点。</p>" <blockquote> <p>这里推荐一些关于SVG优化的<a href="http://xxysy.com/quot;//svgontheweb.com/zh/#resources">资源</a>。</p>" </blockquote> <p><img src="/sites/default/files/blogs/2017/1712/2point.png" alt="优化前" /></p> <p><em>优化前</em></p> <p><img src="/sites/default/files/blogs/2017/1712/1point.png" alt="优化后" /></p> <p><em>优化后</em></p> <p>如果你想放大来查看图形的一些细节。在Illustrator中,你可以通过下面的操作使用像素预览(Pixel Preview)<code>View &gt; Pixel Preview</code>来查看路径上的控制点。完美像素,是保持作品的高质量必须要关注的一个事情。相信大多数设计师都会因为这个都有过被搞得疲惫不堪的经历。通过下面两张图就可以一目了然:</p> <p><img src="/sites/default/files/blogs/2017/1712/nosnap.png" alt="像素偏移" /></p> <p><em>像素偏移</em></p> <p><img src="/sites/default/files/blogs/2017/1712/snap.png" alt="完美像素" /></p> <p><em>完美像素</em></p> <p>如果你有两个或者是两个以上的形状,你就需要删除多余的重叠的像素。 如果有两个对齐的路径,你会看到在它们之间有一条白色的线条,所有时候你需要避免这种重叠情况的出现。</p> <blockquote> <p>注意: SVG是严格按照定义元素的顺序来渲染的,这个与HTML靠z-index值来控制分层不一样。在SVG中,写在前面的元素先被渲染,写在后面的元素后被渲染。后渲染的元素会覆盖前面的元素,虽然有时候受透明度影响,看起来不是被覆盖的,但是SVG确实是严格按照先后顺序来渲染的。</p> </blockquote> <p><img src="/sites/default/files/blogs/2017/1712/whiteline.png" alt="优化前" /></p> <p>当然,最后一点重要的是要在你的网站启用gzip技术来压缩SVGs。这需要在你网站的<code>htaccess</code>文件中设置一下。</p> <pre><code>AddType image/svg+xml svg svgz &lt;IfModule mod_deflate.c&gt; &lt;IfModule mod_filter.c&gt; AddOutputFilterByType DEFLATE "image/svg+xml" \ "text/css" \ "text/html" \ "text/javascript" ... etc &lt;/IfModule&gt; &lt;/IfModule&gt; </code></pre> <p>上面说的这些优化方法,在 <a href="http://xxysy.com/quot;//breakingborde.rs/">Breakin" Borders</a> 网站上的<code>logo</code>(<code>svg</code>格式)就是这样做的: 尽可能的压缩文件, 删除路径中多余的控制点, 对齐像素, 删除重叠的部分,然后使用 SVGO来优化。</p> <p><strong>Original: 1,413b</strong></p> <p><img src="/sites/default/files/blogs/2017/1712/bblogo.svg" alt="优化前" /></p> <p><strong>Optimised: 409b</strong></p> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="优化前" /></p> <p><strong>文件缩小了<code>~71%</code> smaller (如果使用gzip压缩的话能缩小<code>~83%</code>)</strong></p> <blockquote> <p>小技巧: <a href="http://xxysy.com/quot;//twitter.com/robsterlini">Ro" Sterlini</a>提到<code>logo</code>中的<code>b</code>字母是重复的你可以使用<code>&lt;use&gt;</code>这个元素来重复<code>b</code>这个字幕,这样又可以减小文件的体积。</p> </blockquote> <p><strong>使用<code>&lt;use&gt;</code>元素来优化: 311b</strong></p> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim2.svg" alt="优化前" /></p> <p><strong>~78% smaller</strong></p> <p>如果你一直坚持SVGs 这些优化原则,积少成多网站的性能会稳步提升。</p> <h2>SVG使用方法</h2> <p>在网页上使用SVGs 有不同的使用方法。对于这些使用方法要具体问题具体分析,因地制宜的采用。有些使用方法是要避免使用的。如果,你只是想使用SVG跟分辨率无关和文件体积这两个特性,你可以使用img或者是使用CSS中<code>background-image</code>来引入SVG格式的图形,就像使用其它的图形格式一样简单。</p> <h3>Img</h3> <p>仅仅在<code>img</code>标签中引入<code>svg</code>就可以了。你也可以在<code>&lt;picture&gt;</code>元素中使用SVGs。需要注意的是,使用这种方法在交互性上有很多的限制,如不能使用JS来控制。</p> <pre><code>&lt;img src="bblogo.svg" alt="Breaking Borders Logo" height="65" width="68"&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="Img" /></p> <h3>Background-image</h3> <p>使用背景图片方法需要注意的一点是,最好不要使用<code>base64</code>编码来格式化SVG图片,因为它在加载完前会阻塞其它资源的下载。需要注意的是,使用这种方法在交互性上有很多的限制,如不能使用JS来控制。</p> <pre><code>.logo { background-image: url(bblogo.svg); } </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="Background-image" /></p> <h3>Iframe</h3> <p>使用 <code>&lt;iframe&gt;</code>来加载SVGs。不过,我不确定在未来这是不是还是一种好的使用方法。</p> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="Iframe" /></p> <h3>Embed</h3> <p><code>&lt;embed&gt;</code>标签,大多数浏览器都支持。但最好还是不要使用这种方法。</p> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="Embed" /></p> <h3>Object</h3> <p><code>&lt;object&gt;</code>是SVG使用方法中很好的一个选择,如果你想使用JS来进行交互控制的话。 只需要把它放到HTML中就行了。</p> <pre><code>&lt;object type="image/svg+xml" data="bblogo.svg"&gt;Your browser does not support SVGs&lt;/object&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/bblogo-optim.svg" alt="Object" /></p> <h3>Inline</h3> <p>把 SVG直接插入到<code>html</code>中,可以节省 <code>HTTP</code>请求,而且很方便实用JS来控制。但是,也意味着图片不能被浏览器缓存。同时使用JS来操控SVG也意味着浏览器会发生重绘行为。</p> <pre><code>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"&gt; &lt;path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;/svg&gt; </code></pre> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65" class="bb-logo-example"><path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"></path><path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"></path></svg> </div> <h3>总结</h3> <p>如果你想尽可能使用发挥SVGs的特性,那使用<code>&lt;object&gt;</code>来使用SVG是最好的方法。 当然,你也可以直接把SVG代码直接插入到<code>html</code>文件中来节省<code>HTTP</code> 请求, 要记住的是,它就不能被缓存了哦。 如果仅仅是想像使用其他格式图片的方法来使用SVG,那就要使用<code>&lt;img&gt;</code> 或者是 <code>background-image</code>方法。 也可以使用 <code>&lt;iframe&gt;</code> 和 <code>&lt;embed&gt;</code> 方法来使用SVG,不过我觉得这两个方法不是好的选择。</p> <table> <thead> <tr> <th>&nbsp;</th> <th>Object</th> <th>Inline</th> <th>Img</th> <th>Background-image</th> </tr> </thead> <tbody> <tr> <td>CSS Manipulation</td> <td>Yes</td> <td>Yes</td> <td>Some inline</td> <td>Some inline</td> </tr> <tr> <td>JS Manipulation</td> <td>Yes</td> <td>Yes</td> <td>No</td> <td>No</td> </tr> <tr> <td>SVG Animation</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td>Interactive SVG</td> <td>Animation</td> <td>Yes</td> <td>Yes</td> <td>No | No</td> </tr> </tbody> </table> <blockquote> <p>注意: ‘Some inline’ 意味着使用<code>img</code>和<code>background-image</code>方法来使用SVG的话,CSS方面会有一些限制。 但是,如果直接把CSS写在SVG代码里面情况就不一样了。更多关于CSS与SVG的信息在下一节阐述。</p> </blockquote> <h2>CSS 与SVG</h2> <p>使用SVG 值得庆幸的事情是我们依然可以使用CSS来控制SVG的表现。比如,我们想要一个<code>icon</code>在一些地方显示蓝色,我们只需要改变它的颜色即可而不需要换一张新的蓝色的图片。</p> <p>有两种方法来使用样式 —— 内联样式和外链样式。内联样式,即把样式包裹在 <code>&lt;style&gt;</code> 标签里然后放到<code>&lt;![CDATA[ ... ]]&gt;</code>里面。一定要记得把样式包裹在<code>&lt;![CDATA[ ... ]]&gt;</code>里面,因为有时候 XML在解析一些特殊字符串的时候会有一些问题(比如<code>&gt;</code>)。即使你没有一些特殊的字符串,也建议你使用上面的方法来写SVG的内联样式。即使用<code>CDATA</code>标签来包裹内联样式。</p> <p>使用内联样式来操作SVG是一个非常好的实践。像这种<code>&lt;img&gt;</code> 和 <code>background-image</code>内联插入图片到话是不支持CSS3动画的 (可以看看 <a href="http://xxysy.com/quot;//svgontheweb.com/zh/#animating"><code>animations</code></a>" 部分了解更多的关于动画方面的)。 <code>background-image</code>不支持媒体查询的(关于媒体查询可以先看看 <a href="http://xxysy.com/quot;//svgontheweb.com/zh/#mediaqueries"><code>medi" queries</code></a> 这部分了解更多的关于SVG与媒体查询)。而如果把样式内联在SVG文件中就可以解决这两个问题。</p> <h3>Inline Styles</h3> <pre><code>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"&gt; &lt;style type="text/css"&gt; &lt;![CDATA[ .firstb { fill: yellow; } .secondb { fill: red; } ]]&gt; &lt;/style&gt; &lt;path class="secondb" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;path class="firstb" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;/svg&gt; </code></pre> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <style type="text/css"> <![CDATA[.firstb { fill: yellow; } .secondb { fill: red; }]]> </style> <path class="secondb" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path class="firstb" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <p>如果使用外链样式的话也很容易来操作SVG图形,不过对于 <code>&lt;img&gt;</code> 或者 <code>background-image</code>就无能为力了。 如果你使用 <code>&lt;object&gt;</code>来使用SVG代码,你需要在 SVG 中引入样式表(可以看看下面的代码)。 记住一点: 如果这样使用样式的话SVG可能会识别不了它的父类(比如<code>&lt;object&gt;</code>) 所以在使用<code>object</code>方法的时候,不要使用外链样式。 而直接在<code>html</code>文件中直接插入 SVGs 就不需要这么多顾虑了,想怎么做就怎么做。</p> <h3>外链样式</h3> <pre><code>// Add to very start of SVG file before &lt;svg&gt; &lt;?xml-stylesheet type="text/css" href="style.css"?&gt; // In style.css .firstb { fill: yellow; } .secondb { fill: red; } </code></pre> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65" class="bb-styles"> <path style="fill: red;" class="secondb" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path style="fill: yellow;" class="firstb" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h2>JS与SVG</h2> <p>由于我的JavaScript经验不是很多,所以我这里只是分享一些如何使用使用JS 来控制SVG的小的技巧。如果你想把JS代码嵌入到SVG 文件中, 记住把代码包裹在 <code>&lt;![CDATA[ ... ]]&gt;</code> 中。如果是<code>&lt;img&gt;</code>或者是<code>background-image</code>,就不能用脚本来控制。</p> <p>如果是使用外链 JS,如果你的 SVG 代码是直接插入到<code>html</code>的话,你可以像平常开发中使用JS控制DOM元素一样来控制SVG。如果是使用 <code>&lt;object&gt;</code> 你可以使用 <code>contentDocument</code>来控制它。比如下面:</p> <pre><code>window.onload=function() { var object = document.getElementById("logoObject"); var svgDocument = object.contentDocument; var svgb1 = svgDocument.getElementsByClassName("firstb"); var svgb2 = svgDocument.getElementsByClassName("secondb"); svgb1[0].setAttribute("fill", "yellow"); svgb2[0].setAttribute("fill", "red"); }; </code></pre> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65" class="bb-styles"> <path style="fill: red;" class="secondb" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path style="fill: yellow;" class="firstb" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h2>SVG与响应式</h2> <p>在Web开发中响应式图片有两种方法,一种是制作不同固定尺寸图片,然后使用媒体查询来根据不同尺寸的设备来引用不同尺寸的图片;一种是根据图片父容器尺寸来自动调整图片自身的尺寸来适应设备。</p> <p>如果是使用固定尺寸的图片,需要注意的一点是:如果是使用<code>background-image</code> 来使用SVG你需要使用<code>background-size</code> 属性来指定尺寸。因为浏览器可能不能正确解析它从而导致一些问题出现。</p> <p>使用SVG 有下面几点需要注意:</p> <h3>Object</h3> <p>设置宽度 <code>width: 100%;</code>:</p> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h3>Inline</h3> <p>以前要使用<code>max-height</code>才能正常的显示图片,不过现在不需要了。这里需要注意的是,如果图形很复杂,在浏览器窗口改变大小的时候,Safari可能不会立即调整图形的尺寸。</p> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h3>Img</h3> <p>设置宽度 <code>width: 100%;</code>:</p> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h3>Background-image</h3> <p>需要设置 <code>padding-bottom: #%;</code> 来使图片能正常的显示。</p> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#1A374D" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/> </svg> </div> <h2>动画</h2> <p>SVGs 动画方法给我们的选择很多:比如SVG本身的SVG动画(基于 SMIL)、CSS3动画、或者是JS 动画。使用 SVG 动画和 CSS3 动画就可以做出很多的动画效果,而使用SVG 动画更是CSS3动画不可比拟的。而使用JavaScript则能使我们编写更加复杂的动画效果,比如 <a href="http://xxysy.com/quot;//snapsvg.io/">Snap.svg</a>就是一个专门用来操控SVG的JavaScript库。这里就不详细说这个JS库了,可以去它的官网看看它们的实例。</p>" <p>SVG动画非常的强大。不过这里我并不会展开来说,因为我使用SVG动画的经验也比较少。不过当我了解它到强大之后,我可以想象它能制作出很强大的动画效果。唯一不足的是可能要花费点时间。如果你有兴趣的话,这里推荐一些非常不错的伟德1946网页版 <a href="http://xxysy.com/quot;//svgontheweb.com/zh/#resources">地址</a>" 。 SVG动画简而言之就是在SVG代码中插入 <code>&lt;animate&gt;</code> 元素,从而可以给路径或者是形状添加动画效果。大部分浏览器都支持SVG动画,不过 Internet Explorer不支持 SVG 动画, 当然你如果想在IE上也运行动画效果,可以使用<a href="http://xxysy.com/quot;//leunen.me/fakesmile/">FakeSmile</a>这个JavaScript库来支持IE。</p>" <pre><code>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"&gt; &lt;path fill="#4e86b1" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"&gt; &lt;animate dur="2s" values="#000000; #4e86b1; #000000" keyTimes="0; 0.5; 1" attributeName="fill" repeatCount="indefinite"/&gt; &lt;/path&gt; &lt;path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"&gt; &lt;animate dur="2s" values="#4e86b1; #000000; #4e86b1" keyTimes="0; 0.5; 1" attributeName="fill" repeatCount="indefinite"/&gt; &lt;/path&gt; &lt;/svg&gt; </code></pre> <p>下面有一个简单的实例:两个字母之间的颜色互相切换:</p> <div style="margin-bottom: 20px; border: 1px solid #ccc; padding: 2px"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#4e86b1" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate dur="2s" values="#000000; #4e86b1; #000000" keyTimes="0; 0.5; 1" attributeName="fill" repeatCount="indefinite"/> </path> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate dur="2s" values="#4e86b1; #000000; #4e86b1" keyTimes="0; 0.5; 1" attributeName="fill" repeatCount="indefinite"/> </path> </svg> </div> <p>在Web开发中,会经常遇到一些图标交互动画的场景,比如鼠标滑过图标,触发并执行动画效果。从上面的内容SVG动画支持度可以知道如果使用<code>&lt;img&gt;</code> 或者 <code>background-image</code>来使用SVG的话,是不支持SVG动画的。如果是使用 SVG 动画来编写鼠标滑过动画的话,我们需要使用 <code>begin="mouseover"</code> 和 <code>begin="mouseout"</code> 属性来触发鼠标滑过动画效果。而 CSS3 动画效果就简单多,跟我们平时使用CSS3编写动画效果一样没有什么区别,只需要使用 <code>hover</code>属性就可以了。有一件需要注意的事情的是, 如果你编写的动画效果用的是外链样式的话,对于直接在<code>html</code>文件中插入SVG代码没有什么影响;如果是使用<code>&lt;object&gt;</code>来使用SVG的话,那你也需要在SVG代码中引入你的外部样式。</p> <h3>SVG交互动画</h3> <p>只针对<code>&lt;object&gt;</code> 或者是直接在<code>html</code>中插入SVG代码的方式使用SVG代码有效:</p> <pre><code>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"&gt; &lt;path fill="#4e86b1" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"&gt; &lt;animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseover"/&gt; &lt;animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseout"/&gt; &lt;/path&gt; &lt;path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"&gt; &lt;animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseover"/&gt; &lt;animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseout"/&gt; &lt;/path&gt; &lt;/svg&gt; </code></pre> <div style="margin-bottom: 20px; padding: 2px; border: 1px solid #ccc;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#4e86b1" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseover"/> <animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseout"/> </path> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseover"/> <animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseout"/> </path> </svg> </div> <h3>CSS3 动画</h3> <p>只针对 <code>&lt;object&gt;</code> 或者是直接在<code>html</code>中插入SVG代码的方法使用SVG。使用内联样式的方式来编写动画效果<a href="//svgontheweb.com/zh/#css">previously</a>。</p> <pre><code>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"&gt; &lt;style type="text/css"&gt; &lt;![CDATA[ .firstb { fill: #000; transition: fill 0.1s; } .firstb:hover { fill: #4e86b1; } .secondb { fill: #4e86b1; transition: fill 0.1s; } .secondb:hover { fill: #000; } ]]&gt; &lt;/style&gt; &lt;path class="secondb" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;path class="firstb" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"/&gt; &lt;/svg&gt; </code></pre> <div style="margin-bottom: 20px; padding: 2px; border: 1px solid #ccc;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 65"> <path fill="#4e86b1" d="M42 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v21l12 15-7 15.7c14.5 13.9 35 2.8 35-13.7 0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseover"/> <animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseout"/> </path> <path d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z"> <animate fill="freeze" dur="0.1s" to="#4e86b1" from="#000000" attributeName="fill" begin="mouseover"/> <animate fill="freeze" dur="0.1s" to="#000000" from="#4e86b1" attributeName="fill" begin="mouseout"/> </path> </svg> </div> <h2>SVG与雪碧图</h2> <p>SVG 也能使用雪碧图的技术,就像平时开发中使用的PNGs来制作雪碧图一样。不过使用SVG来做雪碧图的话,一个额外的好处是我们不再需要为高清屏准备额外的2倍图。因为SVG与分辨率无关,也就是说在任何设备上SVG都能清晰的显示。并且使用SVG还能节省HTTP请求。这里有两种方法来达到雪碧图相同的效果。第一种方法是把所有的图标使用<code>&lt;symbol&gt;</code>元素来定义在 SVG 代码中并且隐藏它。然后使用<code>&lt;use&gt;</code>元素来通过<code>&lt;symbol&gt;</code> 的 <code>xlink:href="http://xxysy.com/quot;#id"</code>来引用它。第二种方法是使用SVG的<code>viewbox</code>属性来指定显示SVG画布的区域,跟<code>background-position</code>原理差不多。</p>" <p>如果你想详细的了解SVG雪碧图的技术,可以去看看<a href="http://xxysy.com/quot;//svgontheweb.com/zh/#resources">这几篇伟德1946网页版资源</a>" 特别是 <a href="http://xxysy.com/quot;//twitter.com/SaraSoueidan">Sar" Soueidan’s</a> 在24ways网站上的<a href="http://xxysy.com/quot;//24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/">文章</a>。</p>" <h2>媒体查询</h2> <p>SVGs一个有趣的地方是,如果你在嵌入的SVG文件中的样式中使用来媒体查询,那么SVGs响应的是这些元素建立起来的<code>viewport</code>。也就是说,这些元素的尺寸会生成描绘SVG的<code>viewport</code>,也会生成CSS媒体查询条件应用的<code>viewport</code>。这样我们就可以使用媒体查询来告知SVG 在不同<code>viewport</code>下的样式。</p> <p>想象一下,如果你手头有一个大品牌的<code>logo</code>,你想<code>logo</code>都能清晰的展示出来,无论用户使用的是何种尺寸的设备。使用媒体查询就能做到,根据不同尺寸的设备改变SVG图形的尺寸。这适用于所有的使用SVG的方法,除了使用<code>background-image</code>的方法 (备注: IE9–11只支持一个断点的设置)。滑动下面的滑块试试看会发生什么:</p> <p><img src="/sites/default/files/blogs/2017/1712/web-svg.gif" alt="Object" /></p> <h2>降级使用SVG</h2> <p>大部分的现代浏览器都支持SVGs。如果你还要支持诸如IE8这样的老一代的浏览器你可能需要降级来处理,对不支持SVG的浏览器使用PNGs来显示。这里就不深入讨论了,现在都啥年代了,你可能早就不需要支持像IE8 这类老一代的浏览器了。 不过, 如果你真的需要降级来处理SVG的话,一些本来使用 SVG就相当简单的事情就会变得稍微复杂啦。关于降级使用SVG,建议去读读<a href="http://xxysy.com/quot;//twitter.com/AmeliasBrain">Ameli" Bellamy-Royds</a> 写的<a href="//css-tricks.com/a-complete-guide-to-svg-fallbacks/">CSS-Tricks</a>篇文章。</p> <h2>推荐资源</h2> <h3>SVG基本介绍</h3> <ul> <li><a href="http://xxysy.com/quot;//www.webdesignerdepot.com/2015/01/the-ultimate-guide-to-svg/">Ultimat" guide to SVG</a></li> <li><a href="http://xxysy.com/quot;//www.sitepoint.com/add-svg-to-web-page/">Ho" to Add SVGs to Your Web Page</a></li> <li><a href="http://xxysy.com/quot;//www.w3.org/Graphics/SVG/About.html">W3" About SVG</a></li> <li><a href="http://xxysy.com/quot;//www.smashingmagazine.com/2014/03/05/rethinking-responsive-svg/">Rethinkin" Responsive SVG</a></li> <li><a href="http://xxysy.com/quot;//tympanus.net/Tutorials/ResponsiveSVGs/index6.html">Makin" SVGs Responsive</a></li> <li><a href="//css-tricks.com/using-svg/">Using SVG</a></li> <li><a href="http://xxysy.com/quot;//blogs.adobe.com/webplatform/2013/01/08/svg-styling/">SV" Styling</a></li> </ul> <h3>SVG优化</h3> <ul> <li><a href="http://xxysy.com/quot;//calendar.perfplanet.com/2014/tips-for-optimising-svg-delivery-for-the-web/">Tip" For Optimising SVG Delivery For The Web</a></li> <li><a href="http://xxysy.com/quot;//jaydenseric.com/blog/how-to-optimize-svg">Ho" To Optimize SVG</a></li> <li><a href="//css-tricks.com/understanding-and-manually-improving-svg-optimization/">Understanding and Manually Improving SVG Optimization</a></li> <li><a href="http://xxysy.com/quot;//www.youtube.com/watch?v=1AdX8odLC8M">SV" Optimization Video</a></li> <li><a href="http://xxysy.com/quot;//jakearchibald.github.io/svgomg/">SVGOM" — SVGO GUI in browser</a></li> </ul> <h3>SVG动画</h3> <ul> <li><a href="//css-tricks.com/guide-svg-animations-smil/">A Guide to SVG Animations</a></li> <li><a href="//www.smashingmagazine.com/2014/11/03/styling-and-animating-svgs-with-css/">Styling And Animating SVGs With CSS</a></li> <li><a href="http://xxysy.com/quot;//product.voxmedia.com/2013/11/25/5426880/polygon-feature-design-svg-animations-for-fun-and-profit">SV" animations for fun and profit</a></li> <li><a href="http://xxysy.com/quot;//snapsvg.io/">Snap.svg</a></li>" <li><a href="http://xxysy.com/quot;//svgjs.com/">SVG.js</a></li>" <li><a href="http://xxysy.com/quot;//pablojs.com/">Pablo</a></li>" </ul> <h3>SVG雪碧图</h3> <ul> <li><a href="http://xxysy.com/quot;//24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/">A" Overview of SVG Sprite Creation Techniques</a></li> <li><a href="http://xxysy.com/quot;//sarasoueidan.com/blog/structuring-grouping-referencing-in-svg/">Structuring" Grouping, and Referencing in SVG</a></li> <li><a href="http://xxysy.com/quot;//taye.me/blog/svg/a-guide-to-svg-use-elements/">" guide to SVG <code>&lt;use&gt;</code> elements</a></li> <li><a href="http://xxysy.com/quot;//github.com/filamentgroup/grunticon">Grunticon</a></li>" <li><a href="http://xxysy.com/quot;//github.com/lukewhitehouse/svg-icon-workflow">SV" icon workflow</a></li> <li><a href="http://xxysy.com/quot;//tomhazledine.com/inline-svg-icons/">Inlin" SVG icons</a></li> </ul> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/624.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">转载</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/svg-tutorial"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/646.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG指南</a></div></div></div> Thu, 07 Dec 2017 15:23:50 +0000 Airen 2320 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/simple-asynchronous-infinite-scroll-with-vue-watchers.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>无限滚动(Infinite Scroll)是一种很常见的用户体验模式,它建议用户在Web页面或应用程序加载显示很少的内容。当用户开始向下滚动页面时,会加载更多内容。这些内容是通过向负责提供内容的服务器发出请求来异步加载的。在这篇文章中,我将讨论JavaScript的异步操作以及Vue如何实现无限滚动效果。在这个过程中,我们将看到一个使用无限增发动的简单页面。</p> <h2>理解异步操作</h2> <p>在程序中编写一段同步代码,比如下面的例子,有两行代码:<code>L1</code>和<code>L2</code>。如果<code>L1</code>未结速,<code>L2</code>是不会执行的:</p> <pre><code>console.log('quavo'); console.log('takeoff'); </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-1.png" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>通常情况下,我们会看到上面的代码执行的顺序,那是因为<code>$http.get</code>请求需要一些时间才能从<code>our_url</code>获取<code>data</code>,JavaScript并不会花时间去等,而是在等待<code>$http.get</code>时执行下一行代码。完成它所做的事情,这样就可以在控制台上进行日志记录。异步写代码的方法还包括:</p> <p><code>setTimeout()</code>函数,它可以先执行后面的一些事情,然后再执行<code>setTimeout()</code>中的代码。比如:</p> <pre><code>console.log('我先执行') setTimeout(() =&gt; { console.log('是的,我等待3s后才执行') },3000) console.log('对了,我会第二个执行') </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-2.gif" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>高阶函数(也称为回调函数)是作为参数传递给其他函数的函数。让我们假设有一个名为<code>function X</code>的回调函数,它被当做一个参数传递给另一个函数<code>function Y</code>。最终,函数<code>X</code>被执行或调用内部<code>Y</code>函数。比如下面的代码:</p> <pre><code>function Y(X) { $.get("our_url", X); } </code></pre> <p>来看一个实例:</p> <pre><code>var add = function (a, b) { return a + b; } function math (func, array) { return func(array[0] , array[1]); } console.log(math(add, [1, 2])) // =&gt; 3 </code></pre> <p>上面的例子中传进去的<code>add</code>是一个参数,而在<code>return</code>的时候刚是一个函数。</p> <p>高阶函数存在于不同的模式中,很有可能你在不知道的情况下就使用它们。比如<code>window.onclick</code>、<code>setTimeout()</code>和<code>setInterval()</code>。除此之外,还有一些常见的高阶函数例子。比如<code>jQuery ajax</code>回调函数:</p> <pre><code>$.ajax({ url: '//localhost:8000/api/v1/entry/1', type: 'GET', dataType: 'json', success: function (data) { // success 接收回调函数 console.log(data) } }) </code></pre> <p><code>setTimeout()</code>和<code>setInterval()</code>这样的计时器函数也是高阶函数:</p> <pre><code>setTimeout(function (){ console.log('是的,我会在3s后执行') },3000) var i = 0; setInterval(function (){ i++; console.log(`我现在的值是:${i}`) }, 100) </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-3.gif" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>在数组中的<code>sort()</code>、<code>map()</code>、<code>reduce()</code>和<code>filter()</code>等函数都是高阶函数的示例:</p> <pre><code>var arr = [2, 8, 20, 5, 17, 38, 21]; // 升序 arr.sort(function (x, y) { return x - y }) // 降序 arr.sort(function (x, y) { return y - x }) // 数据所有元素进行求平方得到新数组 arr.map(function (item) { return Math.pow(item, 2) }) // 数组求和 arr.reduce(function (x, y) { return x + y }) // 过滤掉数组中的偶数,只留奇数,返回一个新数组 arr.filter(function (x) { return x % 2 !== 0 }) </code></pre> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-4.png" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>有关于高阶函数更多介绍,可以阅读下面的内容:</p> <ul> <li><a href="http://xxysy.com/quot;//juejin.im/entry/5815876c8ac247004fb6d132/">JavaScrip" 高阶函数介绍</a></li> <li><a href="//jcouyang.gitbooks.io/functional-javascript/content/zh/!higher-order-function.html">高阶函数(Higher-order function)</a></li> <li><a href="http://xxysy.com/quot;//chenyuzuoo.github.io/posts/49352/">JavaScript高阶函数</a></li>" <li><a href="//eloquentjavascript.net/05_higher_order.html">Higher-Order Functions</a></li> <li><a href="//medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99">Higher Order Functions</a></li> <li><a href="//www.sitepoint.com/higher-order-functions-javascript/">Higher-Order Functions in JavaScript</a></li> <li><a href="http://xxysy.com/quot;//learnyouahaskell.com/higher-order-functions">Highe" order functions</a></li> <li><a href="//javascriptissexy.com/understand-javascript-callback-functions-and-use-them/#more-1037">Understand JavaScript Callback Functions and Use Them</a></li> </ul> <h2>什么是观察者</h2> <p><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-watch.html">Vue观察者</a>允许我们在更改数据时执行异步操作。它们就像是在Vue实例中对数据做更改,而<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-reactivity.html">视图做出相应的反应</a>。在我们的Vue实例中,观察者用<code>watch</code>关键词表示,并因此被使用:</p>" <pre><code>let app = new Vue({ el: '#app', data () { return { // 和view绑定的数据 } }, watch: { // 将在app中使用的异步操作 } }) </code></pre> <h2>扩展观察者的异步操作</h2> <p>让我们看看Vue如何使用观察者来监视异步操作。使用Vue构建一个具有无限滚动特性的应用程序,一旦用户到达页面的底部,就会执行<code>GET</code>请求,并检索更多的数据。这篇文章的示例是来自于<a href="http://xxysy.com/quot;//twitter.com/sarah_edo">@Sara" Drasner</a>的原始案例(我是她的超级粉丝)。接下来看它是如何工作的。</p> <p>首先使用<code>&lt;script&gt;</code>标签导入必要的库。在这里,我们将导航Vue和<a href="http://xxysy.com/quot;//www.npmjs.com/package/axios">Axios</a>,这是一个基于HTTP客户端的浏览器。</p>" <pre><code>&lt;head&gt; &lt;script src="https://unpkg.com/vue"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/axios/dist/axios.min.js"&gt;&lt;/script&gt; &lt;/head&gt; </code></pre> <p>如果你在Codepen上写的话,可以直接在JavaScript设置中导入相关的脚本,如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-5.png" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>创建一个新的Vue实例:</p> <pre><code>let app = new Vue({ // el属性是一个挂载器,指向index.html中的#app的DOM元素 el: '#app', }) </code></pre> <p>创建<code>data()</code>函数,并附加需要绑定到DOM的数据属性。最初我们是不会在页面的底部,因此<code>bottom</code>的值设置为<code>false</code>。另外设置<code>beers</code>属性,先设置为一个空数组。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } } }) </code></pre> <p>接下来使用<code>methods</code>属性创建所需要的方法。<code>methods</code>允许我们创建函数,并将事件绑定到这些函数以及处理相关的事件。在<code>bottomVisible()</code>函数中,我们使用三个只读属性手动创建无限滚动相关的特性:</p> <ul> <li><code>scrollY</code>:返回滚动条距离<code>viewport</code>顶部边缘的<code>Y</code>坐标。如果没有离开<code>viewport</code>,返回的值为<code>0</code></li> <li><code>clientHeight</code>:无素可视区高度,包括<code>padding</code>,但不包括水平滚动条高度、<code>border</code>或<code>margin</code></li> <li><code>scrollHeight</code>:元素内容的高度,包括由于溢出在屏幕上不可见的内容</li> </ul> <blockquote> <p>有关于这方面的相关属性的介绍,可以阅读前段时间整理的一篇笔记《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/offset-scroll-client.html">视口宽高、位置与滚动高度</a>》。</p> </blockquote> <pre><code>let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY &gt;= pageHeight return bottomOfPage || pageHeight &lt; visible } } }) </code></pre> <p>在<code>methods</code>中继续添加另一个函数<code>addBeer()</code>,我们使用Axios执行<code>GET</code>请求。使用<code>Promises</code>和<code>callback</code>,创建一个<code>apiInfo</code>对象,并从API中调用检索值传给它。我们的Vue实例中的每个函数都可以使用<code>this</code>访问<code>data</code>属性。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY &gt;= pageHeight return bottomOfPage || pageHeight &lt; visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response =&gt; { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } } }) </code></pre> <blockquote> <p>有关于Vue中的<code>methods</code>相关的知识可以阅读前段时间整理的相关学习笔记《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html">Vue的Methods</a>》、《<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-methods-and-event-handling.html">Vue的Methods和事件处理</a>》和《<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/when-to-use-methods-computed-properties-or-watchers.html">在Vue中何时使用方法、计算属性或观察者</a>》。</p>" </blockquote> <p>在<code>watch</code>属性中添加相应的观察者,用来监视应用程序状态的变化,并相应的更新DOM:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY &gt;= pageHeight return bottomOfPage || pageHeight &lt; visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response =&gt; { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } }, watch: { bottom (bottom) { if (bottom) { this.addBeer() } } } }) </code></pre> <blockquote> <p>有关于Vue中的观察者相关的知识,可以阅读前段时间整理的学习笔记:《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-watch.html">Vue的观察者</a>》。</p>" </blockquote> <p>接下来再使用Vue的生命周期的钩子<code>created</code>添加一个<code>scroll</code>滚动事件,每次调用<code>bottomVisible()</code>函数时触发一个滚动事件。为了实现无限滚动特性,将<code>data</code>函数中的<code>bottom</code>值设置为<code>bottomVisible()</code>函数。<code>created</code>钩子允许我们访问反应性数据和Vue实例中的函数。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { bottom: false, beers: [] } }, methods: { bottomVisible () { const scrollY = window.scrollY const visible = document.documentElement.clientHeight const pageHeight = document.documentElement.scrollHeight const bottomOfPage = visible + scrollY &gt;= pageHeight return bottomOfPage || pageHeight &lt; visible }, addBeer () { axios.get('https://api.punkapi.com/v2/beers/random') .then(response =&gt; { let api = response.data[0] let apiInfo = { name: api.name, desc: api.description, img: api.image_url, tips: api.brewers_tips, tagline: api.tagline, food: api.food_pairing } this.beers.push(apiInfo) if (this.bottomVisible()) { this.addBeer() } }) } }, watch: { bottom (bottom) { if (bottom) { this.addBeer() } } }, created () { window.addEventListener('scroll', () =&gt; { this.bottom = this.bottomVisible() }) this.addBeer() } }) </code></pre> <blockquote> <p>有关于Vue实例和生命周期相关的知识可以阅读前段时间整理的学习笔记《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-instances-and-life-cycles.html">Vue实例和生命周期</a>》。</p>" </blockquote> <p>现在把注意力集中到DOM中,将使用Vue指令让DOM和Vue实例之间实现数据的双向绑定:</p> <ul> <li><code>v-if</code>:根据条件的布尔值,有条件的渲染DOM元素</li> <li><code>v-for</code>:基于数组循环遍历出项目列表,比如<code>beer in beers</code>,其中<code>beer</code>是被迭代的数组元素的别名</li> </ul> <blockquote> <p>有关于Vue的指令相关的介绍,可以阅读:</p> <ul> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-bind.html"><code>v-bind</code></a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-model.html"><code>v-model</code></a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-on.html"><code>v-on</code></a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-text-and-v-html.html"><code>v-text</code>和<code>v-html</code></a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-for.html"><code>v-for</code></a></li>" <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-if-vs-v-show.html"><code>v-if</code>和<code>v-show</code></a></li>" </ul> </blockquote> <p>示例中的DOM这样写:</p> <pre><code>&lt;div id="app"&gt; &lt;section&gt; &lt;h1&gt;Make yourself some Punk Beers&lt;/h1&gt; &lt;!-- beers数组值为空时,显示正在加载中的状态 --&gt; &lt;div class="beer-container"&gt; &lt;div v-if="beers.length === 0" class="loading"&gt;Loading...&lt;/div&gt; &lt;!-- 对beers数组进行迭代 --&gt; &lt;div v-for="beer in beers" class="beer-contain"&gt; &lt;div class="beer-img"&gt; &lt;img :src="beer.img" height="350" /&gt; &lt;/div&gt; &lt;div class="beer-info"&gt; &lt;h2&gt;{{ beer.name }}&lt;/h2&gt; &lt;div class="beer-description"&gt; &lt;p&gt;&lt;span class="bright"&gt;Description:&lt;/span&gt; {{ beer.desc }}&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/section&gt; &lt;/div&gt; </code></pre> <p>这个时候你的页面可以看到这样的结果:</p> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-6.png" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <p>因为还没有添加任何样式,看上去丑丑的。如果添加了样式之后,就可以看到下面这样的效果:</p> <div style="margin-bottom: 20px;"><iframe id="KyLVdM" src="//codepen.io/airen/embed/KyLVdM?height=400&amp;theme-id=0&amp;slug-hash=KyLVdM&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <blockquote> <p>注意,我在@Sarah Drasner的示例上删除了一些字段,只是为了样式上看上去好看一点。原始示例的效果和源码,<a href="http://xxysy.com/quot;//codepen.io/sdras/pen/dRqZOy">点击这里可以看到</a>。</p>" </blockquote> <p>这个时候你滚动到页面的底部的时候就可以无限加载内容。这个效果也就是我们所说的无限滚动效果:</p> <p><img src="/sites/default/files/blogs/2017/1712/infinite-scroll-vue-7.gif" alt="使用Vue观察实现一个简单异步无限滚动效果" /></p> <h2>总结</h2> <p>有人可能会问,为什么我们不直接使用Vue的<code>computed</code>属性呢?原因是<code>computed</code>属性是同步的,必须返回一个值。当执行类似<code>timeout</code>函数之类的异步操作,或者像上面示例中<code>GET</code>请求时,最好使用Vue的<code>watch</code>,因为Vue会侦听函数的返回值。使用事件监听器也很酷,但这些都有手工处理事件和调用方法而不是只监听数据更改的缺点。无论如何,当你看到或想要在Vue中使用它们时,你现在知道如何处理异步操作了吧。</p> <blockquote> <p>特别声明,本文整个思路是跟着<a href="http://xxysy.com/quot;//scotch.io/@codebeast">@Chri" Nwamba</a>的博文《<a href="http://xxysy.com/quot;//scotch.io/tutorials/simple-asynchronous-infinite-scroll-with-vue-watchers">Simpl" Asynchronous Infinite Scroll with Vue Watchers</a>》学习整理的。文章有关于Vue的示例代码,都源于此文。</p> </blockquote> <p>由说作者是Vue相关的初学者,如果文章中有不对之处,还请各路大婶拍正。如果你有更好的建议或者想法,欢迎在下面的评论中与我们一起分享。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/simple-asynchronous-infinite-scroll-with-vue-watchers.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/simple-asynchronous-infinite-scroll-with-vue-watchers.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div> Wed, 06 Dec 2017 15:41:25 +0000 Airen 2319 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/svg/svg-and-css-create-animation.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明:本文转载<a href="http://xxysy.com/quot;//juejin.im/user/58216407da2f60005d10b5f1">@泱泱</a>的《<" href="http://xxysy.com/quot;"></a>》一文,如需转载,烦请注明原文出处:<" href="//juejin.im/post/5a150fc06fb9a0451e3f7042">https://juejin.im/post/5a150fc06fb9a0451e3f7042</a>。</p> rel="nofollow" </blockquote> <p>CSS3的动画相关的基础的属性基本都涉猎过了,个人认为,其中最复杂的是<code>d:path()</code>路径变形动画,超过3D,而位移、轨迹、旋转、缩放、斜切什么的,相对简单一些,但作为非动画设计师而言,灵活的掌握这些基本的动画加以无穷无尽的变换,就已经能做出很多华丽丽的效果了,这篇呢,源于做一个练习时,AI的连续旋转复制功能,试着做了几个动效,简单、省时、高效,最主要的是用到CSS3的<code>transform:rotate()</code>旋转属性,辅以位移和缩放。</p> <h2>最基本的旋转动画</h2> <p>下面这张效果图,粗通AI的设计师小伙伴们一定都不会陌生,在AI里面就是<code>ctrl+D</code>连续复制的体力活。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-1.png" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>如果把连续旋转复制转成CSS3语言,也是极简单的。来分析一下上面的图形,我做的时候每次旋转的角度为<code>10</code>度,就意味着有36朵花瓣,那对应SVG里应该有<code>36</code>个路径<code>&lt;path&gt;</code>,如果是AI直接导出的SVG看一下代码,也是密密麻麻的罗列,因为都是相同的形状,自然有简单的方法来实现,只需定义一个被重复使用的图形,有两种方法<code>&lt;defs&gt;</code>元素和<code>&lt;symbol&gt;</code>元素来定义,<code>&lt;use&gt;</code>元素来引用,那因为<code>&lt;symbol&gt;</code>元素使用范围更宽泛一些,所以我们需要的工作就简化成,在AI里做一片花瓣的基础图形,然后导出路径后,定义如下:</p> <pre><code>&lt;symbol id="single"&gt; &lt;path d=""/&gt; &lt;!--此处为AI导出的单片花瓣的路径--&gt; &lt;/symbol&gt; </code></pre> <p>先来第二片花瓣(也就是第一个旋转的花瓣),CSS部分定义如下:</p> <pre><code>@keyframes leaf1{ 0%{ transform:rotate(0deg); transform-origin:400px 300px } 100%{ transform:rotate(10deg); transform-origin:400px 300px } } #petal1{ animation:leaf1 ease 0.1s both; } </code></pre> <p>DOM部分,只需要用<code>&lt;use&gt;</code>元素引用定义好的花瓣并且赋给它旋转的动效就可以了。</p> <p>好了,剩下的还是体力活,需要把<code>&lt;use&gt;</code>元素部分复制34次,然后CSS动画部分复制<code>34</code>次,当然了,动画那里,需要递增一下时间和旋转角度,比如接下来那片花瓣<code>&lt;use id="leaf2" xlink:href="http://xxysy.com/quot;#single"/&gt;</code>对应如下动画属性:</p>" <pre><code>@keyframes leaf2{ 0%{ transform:rotate(0deg); transform-origin:400px 300px } 100%{ transform:rotate(20deg); /*角度增加10度*/ transform-origin:400px 300px } } /*动画时间增加0.2s*/ #leaf2{ animation:leaf2 ease 0.2s both; } </code></pre> <p>所以在做动效时发现,不会JS绝对是短板,尤其在这种批量的活中,本来就是repeat的工作,用SCSS的话,<code>$deg: $deg + (360deg / 36)</code>和<code>animation: leaf#{$i} 0.2s ease both</code>来代替那一堆罗里吧嗦的动画定义是不是很爽,哎,不说了,不过,这个动效确实瓣瓣有些多,下面我们会简化,另外,相信我,已经试过了,别手抽的话,大概10分钟也就搞完了。现在,如果不出意外,已经能得到下面这朵绽放的花了:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-2.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>似乎还不错,但仍有需要优化的地方,首先,花瓣是带透明度的,一开始未旋转时重复在相同区域,层层叠加导致透明度降低,看上去不像是旋转复制的效果,而是把一大把重叠的花瓣依次展开的效果(脑补一下赌神中一封扑克“唰”的展开的场景),如果仔细看看我们的实现过程,就是如此,那这里想要达到每一瓣都是从上一瓣的位置复制出去,怎么办,改呗。这里实现的思路也是有多种,我是用改透明度的方法。放上前三片旋转花瓣的CSS3定义和上面的对比一下(不是要罗代码,只是太少看不出规律):</p> <pre><code>@keyframes leaf1{ 0%{ opacity:0; /*增加初始透明度的定义0,即初始不可见*/ transform:rotate(0deg); transform-origin:400px 300px } 100%{ transform:rotate(10deg); transform-origin:400px 300px } } #leaf1{ animation:leaf1 ease 0.1s both ; } @keyframes leaf2{ 0%{ opacity:0; transform:rotate(10deg); transform-origin:400px 300px; /*增加初始位置定义,即上一朵花瓣的位置*/ } 100%{ transform:rotate(20deg); transform-origin:400px 300px; } } /*动画时间统一为0.1s并增加动画延迟时间的设置0.1s*/ #leaf2{ animation:leaf2 ease 0.1s both 0.1s; } @keyframes leaf3{ 0%{ opacity:0; transform:rotate(20deg); transform-origin:400px 300px; } 100%{ transform:rotate(30deg); transform-origin:400px 300px; } } /*动画延迟时间0.2s,依次类推*/ #leaf3{ animation:leaf3 ease 0.1s both 0.2s; } </code></pre> <p>在进行一番纯体力运动后,完成了如下优化后的效果:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-3.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>好了,以此为基础,来试试其他效果。(为了好做,我把花瓣数量减半了)。比如换换旋转原点<code>transform-origin</code>的值,改一下颜色,就得到了下面这种:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-4.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>上面效果都是单色的,没有体现设计师小伙伴们那卓越的配色效果对不对?虐心的改造来了,比如每朵花瓣单独定义颜色(对我这种毫无审美的假设计师而言只能用系统的色板取色),再随随便便换换基础图形(即<code>&lt;symbol&gt;</code>定义的图形),就得到了下面这种蝴蝶展翅:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-5.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>好啦,剩下的自己玩吧,各种形状,走起,总之,你在AI里面能实现的此类效果都可以通过这种动画方式来实现。</p> <h2>叠加缩放动画</h2> <p>嫌弃单纯的旋转复制的效果太单调?没有关系,我们来一个个叠加其他动画属性,先叠加个简单的,缩放动画。这个也是在AI中常用的功能之一,缩放和旋转操作后,反复的<code>ctrl+D</code>来复制操作。看下下面这张图,解析一下:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-6.png" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>不过是最里面的圆角矩形先等比例放大后旋转一个固定角度,后面的依次重复这种变换,<strong><code>缩放+旋转→复制</code></strong>,那我们来转成CSS3属性。基于上面的基础,首先把<code>&lt;symbol&gt;</code>定义的基础图形改一下,旋转的那里不用管,现在要增加一个缩放的属性<code>scale()</code>设置。比如在这个例子里,我缩放是按<code>1.2</code>倍来进行的,以第一个进行变化的图形为例,CSS属性定义如下:</p> <pre><code>@keyframes leaf1{ 0%{ opacity:0; transform:rotate(0deg); transform-origin:400px 300px; } 100%{ /*增加缩放的比例设置*/ transform:rotate(30deg) scale(1.2); transform-origin:400px 300px; } } </code></pre> <p>这里比旋转变形略复杂的在于比例的计算,不像角度那样可以<code>30</code>度<code>60</code>度<code>90</code>度……直接叠加,缩放比例则是<code>1.2</code>、<code>1.2*1.2</code>、<code>1.2*1.2*12</code>……需要稍微计算一下。这样我们就得到了下面这个旋转叠加缩放的复制动效:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-7.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>同样,改改形状和变形的原点,可以很轻松的做出下面这种:</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-8.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>这里除了填充颜色不同,还稍微改了一下,用了CSS3的混合模式,增加了一个属性值<code>mix-blend-mode:lighten</code>,也就是我们PS或者AI混合模式中的变亮。<code>transform:scale()</code>属性与旋转不同,是支持两个值的,比如写成这种<code>transform:scale(1,1.3)</code>就意味着宽度不变,高度放大<code>1.3</code>倍,我改了一个三角形的看一下效果。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-9.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>只是简单的示例,效果不是很好,有创意的设计师可以自行发挥,知道可以分开定义就可以啦。</p> <h2>叠加位移动画</h2> <p>有了上面关于叠加缩放动画的尝试,叠加位移动画就简单多了。看一下下面这种动效效果,这是一个很讨巧的动画。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-10.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>之所以说它讨巧,是因为仔细分析动效,所有花瓣的位移都是一致的,也就是说我把位移属性设置到了所有花瓣元素的组合<code>&lt;g&gt;</code>元素上。这样的话,我赋给组合一个位移属性设置<code>transform:translateX(50px) translateY(50px)</code>,就可以实现这种效果了。关于旋转原点的定义,因为每个花瓣都是在一个动态位移的过程中,所以我把旋转原点定义为<code>transform-origin:30% 30%</code>,让每个花瓣都以自己的固定的一个点为基准。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-11.png" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>关于渐变色的配色,这里有个小技巧可以参考一下。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-12.png" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>我们常用的色值,除了<code>RGB</code>和十六进制表示方法,还有一个<code>hsl</code>(色相、饱和度、明度)表示方法。如上图所示,最深色和最浅色的<code>hsl</code>值获取到之后,剩下的颜色可以手动去写。</p> <p>在考虑用什么来展现这种旋转复制的位移动画时,突然想到了一个高逼格的图形,鹦鹉螺的黄金螺旋!来看下下面这张图。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-13.png" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>被复用的是一个<code>1/4</code>扇形,旋转角度为<code>-90</code>度(<code>90</code>度为顺时针旋转),放大的比例有规律可寻,即斐波那契数列。位移值最简单的计算方法是和上一个相比较,比如图形7和图形6相比,垂直方向没有位移,水平方向正向位移为图形5的宽(高)度。因为这里<code>transform</code>设置了<code>scale</code>、<code>rotate</code>、<code>translate</code>三种属性,在书写顺序的时候,一定要把<code>rotate</code>放到<code>scale</code>的后面,防止因为旋转导致坐标系变化,位移值不好推算。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-14.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>这样,我们就得到了一个完美黄金螺旋动效。这里我唯一不能理解的是如果不是填充而是描边属性,描边值会等比例放大。</p> <p><img src="/sites/default/files/blogs/2017/1712/svg-transform-animation-15.gif" alt="不炫技,SVG+CSS3 旋转动画属性就能实现的梦幻效果" /></p> <p>对于此类旋转复制动画,最重要的是<code>&lt;symbol&gt;</code>元素定义重复使用的图形,然后<code>&lt;use&gt;</code>元素去引用。重复几次就引用几次。</p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/624.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">转载</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/svg-tutorial"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">SVG</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/29.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Animation</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/532.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Web动画</a></div></div></div> Tue, 05 Dec 2017 14:38:49 +0000 Airen 2318 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/grid-inspector.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>这篇文章介绍了Firefox DevTools的一些鲜为人知的特性,这些特性可以在你构建和调试新的CSS网格布局时派上用场。</p> <p>你可能在今年听过不少有关于CSS特性的讨论。如果你在同一个句子中听到<strong>CSS</strong>和<strong>网格</strong>这两个词,那么我强烈建议你去看看CSS Grid的这个CSS模块。</p> <p>浏览器以CSS盒模型的方式呈现HTML元素,而CSS Grid则是一种新的布局模式,它为开发者提供了控制这些盒子及其内容大小和位置的能力。该模块引入了一系列属性,允许我们创建网格结构,并使用CSS控制网格项的位置和大小。</p> <p>正如<a href="http://xxysy.com/quot;//rachelandrew.co.uk/">@Rache" Andrew</a>曾经多次说过的那样,<strong>网格从容器中开始工作,而其他布局方法从这个项目开始</strong>。这种思考网格的方式真的让我感到非常的困惑,因为我习惯于直接在浏览器中设计。在CSS网格出之前,人们期待每个HTML元素都能一个接一个呈现,这就是我所确定的<strong>心智模式</strong>。</p> <p>在和网格打了一段时间交道之后,我意识到我设计布局的方法发生了变化。我发现自己在纸上画草图,在整体上思考布局设计。当我开始敲键盘时,我就已经知道我的布局是怎么样的了。</p> <p>我不得不总结的一件事是,我们在网格容器上定义的网格是不可见的。你可以将<code>border</code>应用于网格项,但你不能将<code>border</code>应用于网格线来查看它们。这个时候,网格检查器就这样的开发者工具对于开发人员来说,就显得非常重要,也非常的方便。</p> <h2>网格检查器的简史</h2> <p>当<a href="http://xxysy.com/quot;//jensimmons.com/">@Je" Simmons</a>在2016年9月<a href="http://xxysy.com/quot;//twitter.com/jensimmons/status/775992991253204992">在twitter上发twitter</a>的时候,我才第一次听说有一个网格检查器工具,而事实上,Mozilla的团队早在2015年7月开始就一直在讨论网格检查器工具的开发。<" href="http://xxysy.com/quot;//mozillians.org/en-US/u/potch/">@Mat" Claypotch</a>和<a href="http://xxysy.com/quot;//jensimmons.com">@Je" Simmons</a>在2016年4月发布了一个名为<a href="http://xxysy.com/quot;//bugzilla.mozilla.org/show_bug.cgi?id=1181227">CS" Grid Inspector</a>的<a href="//addons.mozilla.org/nn-NO/firefox/addon/css-grid-inspector/">Firefox附加插件</a>。它为团队提供一些工作代码,以及从更多的开发人员基础上收集相关使用的反馈。</p> <p>虽然Chrome和IE等其他浏览器在当时都有各自的网格实现,但Chrome是一面旗帜,而IE则是最初使用网格布局的规范。Firefox却是唯一个在浏览器开发网格布局的工具。</p> <p>在Mozilla上有关于网格检查器工具的深入讨论,这些讨论包括对同一页面上不同网格的用不同颜色展示、网格间隙的检测、行号的显示等。这就是为什么Firefox的网格检查器工具在一夜之间拥有如此多的高级功能。</p> <p>它们已经被统一地实现为一个独立的布局面板,其中还包括一个选定的HTML元素的盒模型,以及盒模型相关的CSS属性。本文将介绍这些有用的特性,以及如何利用它们来帮助我们排除网格布局中的Bug。</p> <h2>布局面板简介</h2> <p><img src="/sites/default/files/blogs/2017/1712/layout-panel-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <h3>网格面板 (Overlay Grid)</h3> <p>在由局面板中,你将看到的第一部是Overlay Grid,它将显示页面上显示的所有应用<code>display:grid</code>的元素。通过选中各自的复选框,你将能够在每个网格上打开Overlay Grid。目前,只有一个网格Overlay Grid可以在任何时候显示,但是<a href="http://xxysy.com/quot;//bugzilla.mozilla.org/show_bug.cgi?id=1317102">多个Overla" Grid的功能正在开发</a>。</p> <p><img src="/sites/default/files/blogs/2017/1712/name-tooltip.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>每一个额外的网格将会有不同的颜色(默认是紫色),但是你可以自由的改变你的网格颜色,点击在每个网格元素的右边的彩色圆圈。Overlay Grid将显示所选网格的所有网格轨道和网格间隔。</p> <p><img src="/sites/default/files/blogs/2017/1712/grid-colour-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>一旦你选择了一个网格,Overlay Grid的颜色就会出现在选中的网格。此呈现将显示你定义的网格的每个部分,并在任何部上悬停,将突出在实际页面上的相应区域。还将有一个工具提示,向你显式突出显示的网格项的行和列的行号。</p> <p><img src="/sites/default/files/blogs/2017/1712/area-highlight.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>我们大多数人在检查我们网站上的CSS时都是在样式规则面板上,你也可以在那里切换Overlay Grid。选择已应用<code>display:grid</code>的元素,并单击属性上的像华夫(<code>waffle-like</code>)类图标。设置在布局面板上的行号或网格区域名的选项将在Overlay Grid上以这种方式进行切换。</p> <p><img src="/sites/default/files/blogs/2017/1712/waffle-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <h3>网格显示设置</h3> <p>面板的下一部分是网格显示设置(Grid Display Settings),它允许我们在三个选项上进行切换。显示行号、显示区域名称和无限扩展网格线的选项。</p> <p>网格如何工作的基本前提是你要先定义一个网格,然后将网格项放到该网格中。你也可以手动放置这些网格项,或者自动让浏览器来帮你放置网格项。网格项的位置可以通过<code>grid-row</code>和<code>grid-column</code>的值来控制。网格线的索引起始值是从<code>1</code>开始。</p> <p><img src="/sites/default/files/blogs/2017/1712/grid-overlay.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>一旦显示行号是活动的,选中的Overlay Grid将以每个Overlay Grid的颜色显示网格的行号。每个网格都有自已的网格索引值,他们都是从<code>1</code>开始,不同的网格不会共享相同的网格线的索引值。</p> <p><img src="/sites/default/files/blogs/2017/1712/cutoff1-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p><img src="/sites/default/files/blogs/2017/1712/cutoff2-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>如果你的网格扩展了<code>viewport</code>的宽度或高度,你将会看到网格行号在边缘处将会被截断。Mozilla团队意识到了这个问题,并且在<a href="http://xxysy.com/quot;//bugzilla.mozilla.org/show_bug.cgi?id=1396666">Bu" 1396666下进行跟踪</a>。</p> <p>你还可以使用<code>grid-template-areas</code>属性来定义一个网格,改属性使我们能够在网格中命名网格区域。此属性的语法还提供了CSS本身的网格结构的可视化,使你更容易理解代码中的网格布局。</p> <p>比如下面这个示例:</p> <pre><code>.subgrid1 { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-auto-rows: 5em; grid-template-areas: "apple banana pear" "grape watermelon pineapple" "strawberry peach kiwi" } </code></pre> <p>上面的代码创建了一个 <code>3×3</code>的网格,每个部分根据<code>grid-template-areas</code>属性的名称来命名。如果该部分被命名,那么当你悬停在布局面板中的网格时,它们将显示为第二个提示工具。</p> <p><img src="/sites/default/files/blogs/2017/1712/name-tooltip.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>我们还可以通过在网格显示设置中检查选项来切换网格区域名称的显示。根据Mozilla的说法,这个功能是由<a href="http://xxysy.com/quot;//anthonydugois.com/">@Anthon" Dugois</a>创建的<a href="http://xxysy.com/quot;//codepen.io/anthonydugois/full/RpYBmy">CSS网格模板生器</a>得到的启发。</p>" <p><img src="/sites/default/files/blogs/2017/1712/area-name.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>有趣的是,你可以用表情符号来表示网格区域的名称。</p> <p><img src="/sites/default/files/blogs/2017/1712/area-name-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>你也可以切换最后一个选项,用来无限扩展网格线。默认情况下,每个网格上的网格线都被限制在网格容器的范围内。有时候看网格如何在整个页面上下对齐是非常有用的。</p> <p><img src="/sites/default/files/blogs/2017/1712/extend-lines.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <h3>一个更好的盒模型工具</h3> <p>布局面板(Layout Panel)下的盒模型部分显示了所选元素的尺寸、内距、边框和外距等。此外,它还显示了影响所选元素的位置、大小和几何形状的CSS属性。即:<code>box-sizing</code>、<code>display</code>、<code>float</code>、<code>line-height</code>、<code>position</code>和<code>z-index</code>。当涉及到与布局相关的CSS问题的故障排查时,这个工具就非常的方便。</p> <p>所选元素的高度和宽度的计算值及其当前位置值显示在盒模型下。你还可以直接操作元素的边框、外距和内距。</p> <p><img src="/sites/default/files/blogs/2017/1712/box-model.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>如果使用了<code>px</code>之外的CSS长度单位,DevTools将根据计算值自动将值转换为<code>px</code>。这也是非常有用的功能。</p> <h2>使用变换来玩网格检查器</h2> <p>在很多情况下,网格将与其他CSS布局属性结合使用,比如<code>transform</code>。网格检查器工具可以很好的使用CSS转换,Overlay Grid会调整。这样你将看到网格是如何旋转,扭曲、绽放和位移的。</p> <p><img src="/sites/default/files/blogs/2017/1712/transforms.gif" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <h2>如何帮助网格检查器工具变得更好</h2> <p>与浏览器其他任何特性一样,网格检查器工具也不可避免地出现Bug,因此团队正在努力增加新特性并改进现有的特性。如果你遇到类似的问题,请在Mozilla的Bug跟踪工具<a href="http://xxysy.com/quot;//bugzilla.mozilla.org/">Bugzilla</a>中提出相应的issue。</p>" <p>跟踪网格检查器工具的所有问题的metabug是<a href="http://xxysy.com/quot;//bugzilla.mozilla.org/show_bug.cgi?id=1181227">Bu" 1181227</a>。你还可以搜索网格检查器的术语来查看相关的Bug。</p> <p><img src="/sites/default/files/blogs/2017/1712/bugzilla-large-opt.png" alt="使用Firefox 网格检查器调试 CSS网格布局" /></p> <p>如果你对网格检查器工具或Firefox的DevTools有任何建议或反馈,那么可以在<a href="http://xxysy.com/quot;//discourse.mozilla.org/c/devtools">Mozilla上参与讨论</a>。或者也你可以在Twitter上发twiiter,并且<" href="http://xxysy.com/quot;//twitter.com/FirefoxDevTools">@firefoxdevtools</a>。</p>" <h2>扩展阅读</h2> <ul> <li><a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/356.html">CS" Grid Layout Tutorial</a></li> <li><a href="//www.mozilla.org/en-US/developer/css-grid/">CSS Grid and Grid Inspector in Firefox</a></li> <li><a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts">CS" Grid Inspector: Examine grid layouts</a></li> <li><a href="//hacks.mozilla.org/2017/06/new-css-grid-layout-panel-in-firefox-nightly/">Powerful New Additions to the CSS Grid Inspector in Firefox Nightly</a></li> <li><a href="http://xxysy.com/quot;//jensimmons.com/post/jul-26-2017/firefox-grid-inspector-july-2017-edition">Th" Firefox Grid Inspector, July 2017 edition</a></li> </ul> <blockquote> <p>本文根据<a href="http://xxysy.com/quot;//www.smashingmagazine.com/author/huijing-chen">@Che" Hui Jing</a>的《<a href="http://xxysy.com/quot;//www.smashingmagazine.com/2017/12/grid-inspector/">Debuggin" CSS Grid Layouts With Firefox Grid Inspector</a>》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:<a href="//www.smashingmagazine.com/2017/12/grid-inspector/">https://www.smashingmagazine.com/2017/12/grid-inspector/</a>。</p> rel="nofollow" </blockquote> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/grid-inspector.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/css/grid-inspector.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/69.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/589.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">DevTools</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/373.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">tools</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/356.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">CSS3 Grid Layout</a></div><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/355.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Grid</a></div></div></div> Tue, 05 Dec 2017 13:18:07 +0000 Airen 2317 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/a-javascript-router.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>经过《<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/front-end-routing.html">伟德19463331路由一探</a>》的学习,简单的了解了Web路由方面的知识。另外在学习<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/html5/html5-history-api.html">HTML" History API</a>时,知道可以通过这个API来实现Web页面的跳转,而且浏览器不需要刷新。那么今天我们来看如何使用JavaScript写Web路由。</p> <p>从网上找了两个示例,第一个是<a href="http://xxysy.com/quot;//twitter.com/KrasimirTsonev">@KrasimirTsonev</a>用<" href="http://xxysy.com/quot;//krasimirtsonev.com/blog/article/A-modern-JavaScript-router-in-100-lines-history-api-pushState-hash-url">100行代码写的一个示例</a>,另一个是<" href="http://xxysy.com/quot;//joakim.beng.se/">@Joaki" Carlstein</a>用<a href="//joakim.beng.se/blog/posts/a-javascript-router-in-20-lines.html">20行代码写的一个示例</a>。首先来看第一个示例。</p> <h2>示例1:使用100行代码写一个Web路由</h2> <p>单页面现在是一种很流行的应用程序,可以说是到处可见。而单页面中有一个非常重要的概念,那就是<strong>路由机制</strong>,也就是说单页面应用程序要能正常的运行,就意味着需要一个可靠的路由机制。接下来看看@KrasimirTsonev是怎么实现的。</p> <h3>目标</h3> <p>这个路由将会具备:</p> <ul> <li>代码少于100行</li> <li>支持<code>hash</code>类型的<code>URL</code>,比如<code>http://site.com#products/list</code></li> <li>使用HTML History API</li> <li>提供易于使用的API</li> <li>不自动运行,只是需要的改变的时候才运行</li> </ul> <h3>实现思路</h3> <p>这个示例设计的是只有一个路由器实例。当然这可能不是一个很好的选择,那是因为我们在一个应用程序中,特别是在一个复杂的运用程序中,需要多个路由器才能实现。如果我们实现单例的模式,就不需要将路由器从对象传递到对象。所以我们先创建一个对象<code>Router</code>:</p> <pre><code>let Router = { routes: [], mode: null, root: '/' } </code></pre> <p><code>Router</code>对象中设置了三个属性:</p> <ul> <li><code>routes</code>:用于保持当前注册的路由</li> <li><code>mode</code>:可以使用<code>hash</code>或者<code>history</code>模式</li> <li><code>root</code>:应用程序的根<code>URL</code>路径,只有当我们使用了<code>history.pushState()</code>时才需要它</li> </ul> <p>接下来需要创建一个路由器的方法,有两件事情需要处理,可以在一个函数内来处理:</p> <pre><code>let Router = { routes: [], mode: null, root: '/', config: function (options) { this.mode = options &amp;&amp; options.mode &amp;&amp; (options.mode = 'history') &amp;&amp; !!(history.pushState) ? 'history' : 'hash'; this.root = options &amp;&amp; options.root ? '/' + this.clearSlashes(options.root) + '/' : '/' return this } } </code></pre> <p>只有当我们需要和只有在支持<code>pushState</code>的情况下,<code>mode</code>值等于<code>history</code>,否则将会会使用<code>URL</code>中的<code>hash</code>。<code>root</code>默认设置为一个<code>/</code>。</p> <p>路由器中重要的一部分是获取当前<code>URL</code>,因为它会告诉我们此刻在哪里。获取当前URL有两种模式,所以这里使用<code>if</code>语句来处理:</p> <pre><code>getFragment: function () { let fragment = ''; if (this.mode === 'history') { fragment = this.clearSlashes(decodeURI(location.pathname + location.search)); fragment = fragment.replace(/\?(.*)$/, ''); fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment; } else { let match = window.location.href.match(/#(.*)$/); fragment = match ? match[1] : ''; } return this.clearSlashes(fragment); } </code></pre> <p>在这两种情况下,我们都在使用全局的<code>window.location</code>对象。在<code>history</code>的<code>mode</code>中,需要删除<code>URL</code>的根部分。除此之外,还应该删除所有的<code>GET</code>参数,所以用正则<code>(/\?(.*)$/)</code>来完成。正如大家所看到的,<code>hash</code>的值获取就简单多了。注意<code>clearSlashes()</code>函数的使用方法。它的工作就是从字符串的开头和结尾删除<code>/</code>。这一点也是非常必要的,因为我们不想强制开发人员使用特定的<code>url</code>格式。不管开发者传递的是什么,都将处理成同样的值。</p> <pre><code>clearSlashes: function (path) { return path.toString().replace(/\$/, '').replace(/^\//, '') } </code></pre> <p>在实际工作中提供的东西总应该尽量给开发人员提供尽可能多的可控制的功能。在几乎所有的路由器实现中,路由被定义为字符串。不过,我更喜欢直接使用一个正则表达式。因为这样更为灵活。</p> <p>同样的,开发者在使用一个路由器时,他能方便的添加和删除。也就是说,需要加上添加和删除路由的功能。</p> <pre><code>add: function (re, handler) { if (typeof re == 'function') { handler = re; re = ''; } } remove: function (param) { for (let i = 0; i &lt; this.routes.length, r = this.routes[i]; i++) { if (r.handler === param || r.re.toString() === param.toString()) { this.routes.splice(i, 1); return this; } } return this; } </code></pre> <p>有时候,我们可能需要重新初始化类。因此,在这种情况下,可以像下面这样使用<code>flush</code>方法:</p> <pre><code>flush: function () { this.routes = []; this.mode = null; this.root = '/; return this } </code></pre> <p>我们有一个添加和删除<code>url</code>的API。我们也能得到当前的<code>URL</code>。因此,下一步要做的就是比较注册的条目:</p> <pre><code>check: function (f) { let fragment = f || this.getFragment(); for (let i = 0; i &lt; this.routes.length; i++) { let match = fragment.match(this.routes[i].re); if (match) { match.shift(); this.routes[i].handler.apply({}, match); retrun this; } } return this; } </code></pre> <p>我们使用<code>getFragment</code>方法或接受它作为函数的参数来获取片段。在此之后,我们在<code>routes</code>上执行一个正常的循环,并试图找到相匹配的。如果正则表达式不匹配,则有一个值 为<code>null</code>相匹配。否则它的值是这样的:</p> <pre><code>["products/12/edit/22", "12", "22", index: 1, input: "/products/12/edit/22"] </code></pre> <p>像数组一样的对象,它包含匹配的字符串和所有可记住的子字符串。这意味着,如果我们改变第一个元素,将得到一个动态的数组。例如:</p> <pre><code>Router.add(/about/, function (){ console.log(about) }) .add(/products\/(.*)\/edit\/(.*)/, function(){ console.log('products', arguments) }) .add(function(){ console.log('default') }) .check('/products/12/edit/22') </code></pre> <p>输出的结果:</p> <pre><code>products ["12", "22"] </code></pre> <p>这就是如何处理动态<code>url</code>的方法。</p> <p>在实际的项目当中,我们不可能一直运行这个方法来检测。那么就需要一个提供另外的东西,比如说添加一个逻辑,它会通知我们的地址栏的变化,甚至包括点击浏览器的后退或前进按钮等操作。在History API有一个<code>popstate</code>事件。当<code>URL</code>更改时,将会触发这个事件。然而,有一些浏览器,在页面加载时就会发送这个事件。这样一来,我想了另一个解决办法。使用<code>setinterval</code>来写一个监视,即使<code>mode</code>的值设置为<code>hash</code>。</p> <pre><code>listen: function () { let self = this; let current = self.getFragment(); let fn = function () { if (current !== self.getFragment()) { current = self.getFragment(); self.check(current); } } clearInterval(this.interval); this.interval = setInterval(fn, 50); return this; } </code></pre> <p>我们需要保留最新的<code>URL</code>,以便我们能够将它与新的<code>URL</code>进行比较。</p> <p>最后,我们的路由器需要一个能改变当前地址的函数,当然也需要触发路由的处理器。</p> <pre><code>navigate: function (path) { path = path ? path : ''; if (this.mode === 'history') { history.pushState(null, null, this.root + this.clearSlashes(path)); } else { window.location.href="http://xxysy.com/ window.location.href.replace(/#(.*)$/" '') + '#' + path; } return this; } </code></pre> <p>同样,根据<code>mode</code>属性做不同的事情。如果History API可用,我们就使用<code>pushState</code>,否则就使用<code>window.location</code>。</p> <p>到此,一个路由器就完成了,最终的代码如下:</p> <pre><code>let Router = { routes: [], mode: null, root: '/', config: function (options) { this.mode = options &amp;&amp; options.mode &amp;&amp; (options.mode == 'history') &amp;&amp; !!(history.pushState) ? 'history' : 'hash'; this.root = options &amp;&amp; options.root ? '/' + this.clearSlashes(options.root) + '/' : '/' return this; }, getFragment: function () { let fragment = ''; if (this.mode === 'history') { fragment = this.clearSlashes(decodeURI(location.pathname + location.search)); fragment = fragment.replace(/\?(.*)$/, ''); fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment; } else { let match = window.location.href.match(/#(.*)$/); fragment = match ? match[1] : ''; } return this.clearSlashes(fragment); }, clearSlashes: function (path) { return path.toString().replace(/\/$/, '').replace(/^\//, ''); }, add: function (re, handler) { if (typeof re == 'function') { handler = re; re = ''; } this.routes.push({ re: re, handler: handler }); return this; }, remove: function (param) { for (let i = 0; i &lt; this.routes.length, r = this.routes[i]; i++) { if (r.handler === param || r.re.toString() === param.toString()) { this.routes.splice(i, 1); return this; } } return this; }, flush: function () { this.routes = []; this.mode = null; this.root = '/'; return this; }, check: function (f) { let fragment = f || this.getFragment(); for (let i = 0; i &lt; this.routes.length; i++) { let match = fragment.match(this.routes[i].re); if (match) { match.shift(); this.routes[i].handler.apply({}, match); return this; } } return this; }, listen: function () { let self = this; let current = self.getFragment(); let fn = function () { if (current !== self.getFragment()) { current = self.getFragment(); self.check(current); } } clearInterval(this.interval); this.interval = setInterval(fn, 50); return this; }, navigate: function (path) { path = path ? path : ''; if (this.mode === 'history') { history.pushState(null, null, this.root + this.clearSlashes(path)); } else { window.location.href="http://xxysy.com/ window.location.href.replace(/#(.*)$/" '') + '#' + path; } return this; } } // 配置 Router.config({mode: 'history'}); // 返回到初始状态 Router.navigate() // 添加路由 Router.add(/about/, function () { console.log('about'); }) .add(/products\/(.*)\/edit\/(.*)/, function () { console.log('products', arguments); }) .add(function(){ console.log('default'); }) .check('/products/12/edit/22').listen(); // 转发 Router.navigate('/about') </code></pre> <h2>示例2:使用20行代码写一个Web路由</h2> <p>上面我们看完了<a href="http://xxysy.com/quot;//twitter.com/KrasimirTsonev">@KrasimirTsonev</a>用<" href="http://xxysy.com/quot;//krasimirtsonev.com/blog/article/A-modern-JavaScript-router-in-100-lines-history-api-pushState-hash-url">100行代码写的Web路由</a>。接下来,咱位再看看<" href="http://xxysy.com/quot;//joakim.beng.se/">@Joaki" Carlstein</a>是怎么用<a href="//joakim.beng.se/blog/posts/a-javascript-router-in-20-lines.html">20行代码写的一个Web路由</a>。</p> <p>@Joakim Carlstein想出20行代码创建一个简单客户端路由的思路主要来源于<a href="//krasimirtsonev.com/blog/article/Javascript-template-engine-in-just-20-line">用20行代码写一个模板</a>,而这个灵感却又来自于<a href="//ejohn.org/blog/javascript-micro-templating/">John Resig在同一主题上的文章</a>。是不是很有趣,很鼓舞人心。</p> <p>@Joakim Carlstein是怎么用20行代码写一个路由。如果你对这方面感兴趣的话,请继续往下阅读。</p> <p>首先创建一个HTML模板:</p> <pre><code>&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="utf-8" /&gt; &lt;title&gt;创建一个Web路由&lt;/title&gt; &lt;script&gt; // Johe的模板引擎代码放在这里 // http://ejohn.org/blog/javascript-micro-templating/ &lt;/script&gt; &lt;/head&gt; &lt;/html&gt; </code></pre> <p>模板中使用了<code>&lt;script&gt;</code>标签,并且设置<code>type="text/html"</code>。这将使浏览器不解析它们的内容,这也是我们想要的那样。</p> <pre><code>&lt;script type="text/html" id="home"&gt; &lt;h1&gt;Router FTW!&lt;/h1&gt; &lt;/script&gt; &lt;script type="text/html" id="template1"&gt; &lt;h1&gt;Page 1: &lt;%= greeting %&gt;&lt;/h1&gt; &lt;p&gt;&lt;%= moreText %&gt;&lt;/p&gt; &lt;/script&gt; &lt;script type="text/html" id="template2"&gt; &lt;h1&gt;Page 2: &lt;%= heading %&gt;&lt;/h1&gt; &lt;p&gt;Lorem ipsum...&lt;/p&gt; &lt;/script&gt; </code></pre> <p>正如你所看到的,这是非常基础的部分,那是因为我们把主要精力会放在路由器的那部分,所以不想花太多的精力在模板上面。</p> <p>对于这个路由,作者将使用<code>URL</code>的<code>hash</code>,也就是<code>URL</code>中<code>#</code>符号后面的那部分。例如<code>http://example.com/#our/url/here</code>中的<code>our/url/here</code>。本来可以使用HTML的History API,但这个示例中将不采用这个。</p> <p>路由器将使用<code>onhashchange</code>事件来处理页面加载后的路由更改和通常的<code>onload</code>事件,用来处理页面加载<code>url</code>的任何路由。</p> <p>先从注册路由函数开始:</p> <pre><code>// 使用一个hash来存储我们的路由 let routes = {} // 路由注册函数 function route (path, templateId, controller) { routes[path] = { templateId: templateId, controller: controller } } </code></pre> <p>现在我们就可以创建新的路由。请注意,下面的代码模仿了AngularJS的控制器:</p> <pre><code>route('/', 'home', function () {}); route('/page1', 'template1', function () { this.greeting = 'Hello world!'; this.moreText = 'Bacon ipsum...'; }); route('/page2', 'template2', function () { this.heading = 'I\'m page two!'; }); </code></pre> <p>结果上面的代码并没有起任何的作用,那是因为我们还没有处理好路由。要上面的代码能有作用,就需要添加路由的处理程序。也就是说要构建路由器。但是首先需要一个地方来呈现我们的页面。</p> <pre><code>let el = null; function router () { // 延迟加载view元素 el = el || document.getElementById('view'); // 当前路由url, 删除`#` let url = location.hash.clice(1) || '/'; let router = routes[url]; if (el &amp;&amp; route.controller) { // 使用John Resig的模板引擎,渲染路由模板 el.innerHTML = tmpl(route.templateId, new route.controller()); } } // 监听hash的变化 window.addEventListener('hashchange', router); // 监听页面加载 window.addEventListener('load', router); </code></pre> <p>这就是最基本的路由。另外,导航中的链接应该也能工作,也就是说可以通过浏览器直接进入特定的路由。比如<code>path/to/your/router.html#/page1</code>,你应该可以看到<code>page1</code>对应的内容。</p> <p>为了使路由器变得理有用,可以添加单向数据绑定,以便在控制器中数据发生变化时自动更新视图。这需要使用到<a href="http://xxysy.com/quot;//simpl.info/observe/"><code>Object.observe()</code></a>。</p>" <p>在上面的路由函数上添加一个对象观察者,它会得新运行当前视图:</p> <pre><code>let el = null, current = null; function router () { el = el || document.getElementById('view'); if (current) { Object.unobserve(current.controller, current.render); current = null } let url = location.hash.slice(1) || '/'; let route = routes[url]; if (el &amp;&amp; route.controller) { current = { controller: new route.controller, template: tmpl(route.templateId), render: function () { el.innerHTML = this.template(this.controller); } }; current.render(); Object.observe(current.controller, current.render.bind(current)); } } </code></pre> <p>就这些代码了可以帮助我们实现单向数据绑定的功能。为了验证上面的路由是否有效,可以测试一下:</p> <pre><code>route('/page1', 'template1', function () { this.greeting = 'Hello world!'; this.moreText = 'Loading...'; setTimeout(function () { this.moreText = 'Bacon ipsum...'; }.bind(this), 500); }); </code></pre> <p>如果你感兴趣的话,<a href="http://xxysy.com/quot;//gist.github.com/joakimbeng/7918297">可以查阅读最终代码</a>。</p>" <h2>总结</h2> <p>上面两个示例,通过不上一百行的JavaScript代码,写出不同的Web路由,是不是很有意思。虽然这些路由功能还不是非常的强,也有一定的缺陷。但对于帮助我们学习如何使用 JavaScript写Web路由还是很有帮助的。如果你感兴趣,也可以尝试一下,用极少数的代码,写一个Web路由。</p> <p>最后再次感谢<a href="http://xxysy.com/quot;//twitter.com/KrasimirTsonev">@KrasimirTsonev</a>和<" href="http://xxysy.com/quot;//joakim.beng.se/">@Joaki" Carlstein</a>提供了这么优秀的案例。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/a-javascript-router.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/javascript/a-javascript-router.html</a></p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/JavaScript"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">JavaScript</a></div></div></div> Mon, 04 Dec 2017 14:50:03 +0000 Airen 2316 at https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com