一、使用<use>标簽實作圖形的引用
當我們在使用SVG繪制圖形時,有時候會出現大量重複圖形,這個時候我們就可以使用<use>标簽進行圖形引用,相當于圖形的克隆。
<use>标簽
在SVG文檔内取得目标節點,并在别的地方複制它們。它的效果等同于這些節點被深克隆到一個不可見的DOM中,然後将其粘貼到
use
元素的位置,很像HTML5中的克隆模闆元素。因為克隆的節點是不可見的,是以當使用CSS樣式化一個
use
元素以及它的隐藏的後代元素的時候,必須小心注意。隐藏的、克隆的DOM不能保證繼承CSS屬性,除非你明文設定使用CSS繼承。
假如我們現在想繪制滿天繁星圖,首先我們可以先繪制出一顆星星然後再多次引用這顆星星即可。
-
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 7 <title>星空</title> 8 <meta name="description" content=""> 9 <meta name="keywords" content=""> 10 <link href="" rel="stylesheet"> 11 <style type="text/css"> 12 html, 13 body { 14 margin: 0; 15 padding: 0; 16 width: 100%; 17 height: 100%; 18 background: #001122; 19 line-height: 0; 20 font-size: 0; 21 /*svg标簽是内聯元素,防止撐滿後會有滾動條出現*/ 22 } 23 </style> 24 </head> 25 <body> 26 <svg width="100%" height="100%" 27 viewBox="-400 -300 800 600" 28 preserveAspectRatio="xMidYMid slice" 29 xmlns="http://www.w3.org/2000/svg"> 30 <!--一顆星星--> 31 <s> 32 <polygon id="star" points="0 -10 2 -2 10 0 2 2 0 10 -2 2 -10 0 -2 -2" fill="inhert" /> 33 </> 34 <!--引用出很多星星--> 35 <use x="0" y="0" xlink:href="#star" fill="red" /> 36 <use x="-100" y="-100" xlink:href="#star" fill="white" /> 37 <use x="100" y="100" xlink:href="#star" fill="blue" /> 38 <use x="-100" y="100" xlink:href="#star" fill="green" /> 39 <use x="100" y="-100" xlink:href="#star" fill="yellow" /> 40 </svg> 41 </body> 42 </html>

現在有一個問題就是我們希望漫天繁星的效果,那麼我們就不能通過手動添加<user>标簽,下面我們使用js腳本來幫助我們完成這種效果:
-
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 7 <title>浪漫星空</title> 8 <meta name="description" content=""> 9 <meta name="keywords" content=""> 10 <link href="" rel="stylesheet"> 11 <style type="text/css"> 12 html, 13 body { 14 margin: 0; 15 padding: 0; 16 width: 100%; 17 height: 100%; 18 background: #001122; 19 line-height: 0; 20 font-size: 0; 21 /*svg标簽是内聯元素,防止撐滿後會有滾動條出現*/ 22 } 23 </style> 24 </head> 25 <body> 26 <svg width="100%" height="100%" 27 viewBox="-400 -300 800 600" 28 preserveAspectRatio="xMidYMid slice" 29 xmlns="http://www.w3.org/2000/svg"> 30 <!--一顆星星--> 31 <defs> 32 <polygon id="star" points="0 -10 2 -2 10 0 2 2 0 10 -2 2 -10 0 -2 -2" fill="white" /> 33 </defs> 34 <!--引用出很多星星--> 35 <g id="star-group"></g> 36 </svg> 37 </body> 38 <script type="text/javascript"> 39 var SVG_NS = \'http://www.w3.org/2000/svg\'; 40 var XLINK_NS = \'http://www.w3.org/1999/xlink\'; 41 42 renderStart(); 43 //建立user标簽 44 function use(origin){ 45 var _use = document.createElementNS(SVG_NS,\'use\'); 46 _use.setAttributeNS(XLINK_NS,\'xlink:href\',\'#\'+origin.id); 47 return _use; 48 } 49 //建立若幹顆星星 50 function renderStart(){ 51 var starRef = document.getElementById(\'star\'); 52 var starGroup = document.getElementById(\'star-group\'); 53 var starCount = 500;//星星數量 54 console.log(starGroup);//友善調試js 55 var star; 56 while (starCount--) { 57 star = use(starRef); 58 star.setAttribute(\'opacity\', random(0.1, 0.8));//随機透明度 59 star.setAttribute(\'transform\', \'translate(\' + random(-400, 400) + \',\' + random(-300, 50) + \') scale(\' + random(0.1, 0.6) + \')\');//随機位移/縮放 60 starGroup.appendChild(star); 61 } 62 } 63 //産生随機數字 64 function random(min, max) { 65 return min + (max - min) * Math.random(); 66 } 67 </script> 68 </html>
二、使用<clipPath>标簽實作圖形的剪切
clip即剪切的意思,我們使用clipPath标簽來描述剪切路徑,然後在圖形中使用clip-path屬性來使用。很容易了解,我們一定都見過這樣的頭像:
這就是剪切的效果,我們使用<clipPath>标簽來定義剪切路勁,比如上圖的剪切路徑就是一個圓,然後我們在需要被剪切的圖像中使用clip-path屬性進行使用就可以了,來看具體的例子:
-
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>clipPath</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="600px"> <image xlink:href="https://cdn.duitang.com/uploads/item/201508/30/20150830105732_nZCLV.jpeg" x="0" y="0" height="300px" width="400px" clip-path="url(#header)"></image> <circle cx="100" cy="100" r="71" stroke="red" stroke-width="2px" fill="none" transform="translate(94,62)"></circle> </svg> </body> </html>
這是一個圖形和一個矩形構成的圖檔,如果我們需要使用圓圈作為剪切路勁,我們需要使用<clipPath>來建立,并在圖形中引用:SVG之圖形的引用use、剪切clipPath和蒙闆mask -
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>clipPath</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="600px"> <image xlink:href="https://cdn.duitang.com/uploads/item/201508/30/20150830105732_nZCLV.jpeg" x="0" y="0" height="300px" width="400px" clip-path="url(#header)"></image> <defs> <clipPath id="header"> <circle cx="100" cy="100" r="71" transform="translate(94,62)"></circle> </clipPath> </defs> </svg> </body> </html>
SVG之圖形的引用use、剪切clipPath和蒙闆mask
三、使用<mask>标簽實作圖形的蒙闆
mask的意思是“面具”,而蒙闆的意思是“蒙在上面的闆子”,都是遮擋的意思。之前看過很多mask的使用說明和案例,都覺得不好了解,是以在這裡我盡量簡單明了。首先看一個圖形:
-
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>mask</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="600px"> <circle cx="240" cy="90" r="80" fill="red" opacity="0.7"></circle> <circle cx="200" cy="130" r="80" fill="yellow" opacity="0.7"></circle> </svg> <div></div> </body> </html>
SVG之圖形的引用use、剪切clipPath和蒙闆mask 很簡單的兩個透明矩形重疊的效果,假設現在我有一個需求,就是畫一個月牙,也就是圖中黃色未遮擋的那部分(當然你可以使用<path>或其他标簽來畫),如果我們能讓黃色未遮擋部分顯示而其餘部分完全透明,那麼我們就可以實作這個效果。
很明顯,現在要說的mask就有這個功能,mask是遮罩、蒙闆的意思,而且可以讓蒙闆中的一部分透明而其餘部分完全顯示。如果你覺得抽象我們直接看執行個體,我們先畫一個圓月:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>mask</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="600px"> <circle cx="200" cy="130" r="80" fill="yellow"></circle> </svg> <div></div> </body> </html>
然後我們定義一個蒙闆,就是剛才畫的那兩個圓:SVG之圖形的引用use、剪切clipPath和蒙闆mask
即我們讓剛才紅色圓的位置不顯示,黃色位置的圓顯示,然後我們在上面這個圓月中使用這個蒙闆:<s> <mask id="myMask"> <!--mask中使用顔色來控制透明度:white表示透明度為0,即完全顯示;black表示透明度為1,即完全透明--> <circle cx="200" cy="130" r="80" fill="white"></circle> <circle cx="240" cy="90" r="80" fill="balck"></circle> </mask> </s>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>clip</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="600px"> <!--預定義蒙闆--> <defs> <mask id="myMask"> <!--mask中使用顔色來控制透明度:white表示透明度為0,即完全顯示;black表示透明度為1,即完全透明--> <circle cx="200" cy="130" r="80" fill="white"></circle> <circle cx="240" cy="90" r="80" fill="balck"></circle> </mask> </defs> <!--使用蒙闆--> <circle cx="200" cy="130" r="80" fill="yellow" mask="url(#myMask)"></circle> </svg> <div></div> </body> </html>
可能還是有些抽象,是以我們應該多嘗試,以此來驗證自己想法的正确性。
ps:當然mask不隻是一部分透明一部分不透明,我們還可以使用半透明等蒙闆,根據實際需要來調整蒙闆中的fill即可。
四、綜合運用
結合我們之前畫的星星月亮,我們可以畫出一幅星空圖,圖中除了燈塔的動畫效果,其餘都是前面用過的知識點,這裡就不在贅述,之後的筆記中我會總結一些SVG動畫效果,歡迎移步:
-
SVG之圖形的引用use、剪切clipPath和蒙闆mask SVG之圖形的引用use、剪切clipPath和蒙闆mask
start sky<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Star Sky</title> <style> html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #001122; line-height: 0; font-size: 0; } </style> </head> <body> <svg width="100%" height="100%" viewBox="-400 -300 800 600" preserveAspectRatio="xMidYMid slice"> <!--預定義一顆星星--> <defs> <polygon id="star" points="0 -10 2 -2 10 0 2 2 0 10 -2 2 -10 0 -2 -2" fill="white"></polygon> </defs> <!--實景--> <g id="real"> <!--滿天繁星(動态生成)--> <g id="star-group"></g> <g id="moon-group" transform="translate(0 50)"> <mask id="moon-mask"> <circle cx="-250" cy="-150" r="100" fill="white"></circle> <circle cx="-200" cy="-200" r="100" fill="black"></circle> </mask> <circle mask="url(#moon-mask)" cx="-250" cy="-150" r="100" fill="yellow"></circle> </g> <!--燈塔--> <g id="light-tower" transform="translate(250, 0)"> <defs> <linearGradient id="tower" x1="0" y1="0" x2="1" y2="0"> <stop offset="0" stop-color="#999"></stop> <stop offset="1" stop-color="#333"></stop> </linearGradient> <radialGradient id="light" cx="0.5" cy="0.5" r="0.5"> <stop offset="0" stop-color="rgba(255, 255, 255, .8)"></stop> <stop offset="1" stop-color="rgba(255, 255, 255, 0)"></stop> </radialGradient> <clipPath id="light-mask"> <polygon transform="rotate(10)" points="0 0 -300 -15 -300 15"> <!--SVG動畫效果--> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite"> </animateTransform> </polygon> <circle cx="0" cy="0" r="2"></circle> </clipPath> </defs> <polygon points="0 0 5 50 -5 50" fill="url(#tower)"></polygon> <ellipse cx="0" cy="0" rx="300" ry="100" clip-path="url(#light-mask)" fill="url(#light)"></ellipse> </g> </g> <!--虛景:使用use标簽複制實景,使用mask等設定相關效果--> <g id="reflact" mask="url(#fading)" transform="translate(0 50)"> <defs> <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1"> <stop offset="0" stop-color="rgba(255,255,255,.3)"></stop> <stop offset="0.5" stop-color="rgba(255,255,255,0)"></stop> </linearGradient> <mask id="fading"> <rect x="-800" y="0" width="1600" height="400" fill="url(#fade)"></rect> </mask> </defs> <use xlink:href="#real" transform="scale(1, -1) translate(0 -40)"></use> </g> <rect x="-800" y="50" width="1600" height="400" opacity="0.2" fill="url(#fade)"></rect> </svg> </body> <script> /* jshint browser: true */ var SVG_NS = \'http://www.w3.org/2000/svg\'; var XLINK_NS = \'http://www.w3.org/1999/xlink\'; var paper = document.querySelector(\'svg\'); var defs = document.querySelector(\'svg defs\'); renderStar(); function use(origin) { var _use = document.createElementNS(SVG_NS, \'use\'); _use.setAttributeNS(XLINK_NS, \'xlink:href\', \'#\' + origin.id); return _use; } function random(min, max) { return min + (max - min) * Math.random(); } function renderStar() { var starRef = document.getElementById(\'star\'); var starGroup = document.getElementById(\'star-group\'); var starCount = 500; var star; while (starCount--) { star = use(starRef); star.setAttribute(\'opacity\', random(0.1, 0.4)); star.setAttribute(\'transform\', \'translate(\' + random(-400, 400) + \',\' + random(-300, 50) + \') \' + \'scale(\' + random(0.1, 0.6) + \')\'); starGroup.appendChild(star); } } </script> </html>