- 【序】今天想為vue封裝一個(gè)可以通過(guò)name就生成一個(gè)icon的組件,平時(shí)我們都是通過(guò)class來(lái)添加一個(gè)字體icon顽铸,但是看到ant-design-vue 中是使用的svg-icon的垫竞,并且配合阿里的iconfont庫(kù)迅耘,使用起來(lái)非常方便酗电,令我心動(dòng),讓我們一起研究一下這個(gè)組件是怎么做到的典徊。
問題一
- 【疑惑】:為什么要使用svg的圖片格式?
- 【解答】:
常用的兩種icon的用法優(yōu)缺點(diǎn)對(duì)比:
font-class
- 兼容性良好恩够,支持ie8+卒落,及所有現(xiàn)代瀏覽器。
- 相比于unicode語(yǔ)意明確蜂桶,書寫更直觀儡毕。可以很容易分辨這個(gè)icon是什么。
- 因?yàn)槭褂胏lass來(lái)定義圖標(biāo)腰湾,所以當(dāng)要替換圖標(biāo)時(shí)雷恃,只需要修改class里面的unicode引用。
- 不過(guò)因?yàn)楸举|(zhì)上還是使用的字體费坊,所以多色圖標(biāo)還是不支持的倒槐。
svg
- 支持多色圖標(biāo)了,不再受單色限制附井。
- 通過(guò)一些技巧讨越,支持像字體那樣,通過(guò)font-size,color來(lái)調(diào)整樣式永毅。
- 兼容性較差把跨,支持 ie9+,及現(xiàn)代瀏覽器。
- 瀏覽器渲染svg的性能一般沼死,還不如png着逐。
- 方便做高性能的動(dòng)畫效果
總結(jié)起來(lái):
沒有動(dòng)畫需求,沒有多色圖標(biāo)的需求意蛀,還是使用font-class會(huì)更好耸别,反之使用svg更好
問題二
- 【疑惑】:怎么樣引入svg的項(xiàng)目呢?
- 【解惑】:
-
在阿里iconfont中創(chuàng)建一個(gè)項(xiàng)目浸间,并收藏一些icon
a. 進(jìn)入到一個(gè)icon項(xiàng)目中后屯吊,將需要的icon添加到項(xiàng)目中
b. 點(diǎn)擊右上角
c. 添加到項(xiàng)目
-
進(jìn)入到自己的項(xiàng)目
a. 打開自己收藏的項(xiàng)目
b. 生成js導(dǎo)入鏈接
好的,現(xiàn)在就得到了該項(xiàng)目中所有收藏的icon的js項(xiàng)目了猖吴,接下來(lái)我們就可以將該js引入到項(xiàng)目中烁挟! 引入自己的項(xiàng)目
a. 最簡(jiǎn)單的辦法就是生成一個(gè)script標(biāo)簽,并將地址賦值給src
我們可以在public/index.html中直接添加
b. 本地引入兜看,將地址放到瀏覽器地址欄就能夠得到這段js的內(nèi)容锥咸,將它復(fù)制到一個(gè)本地文件
然后給一個(gè)plugin,require這一段代碼就可以了
c. 接下來(lái)可以在component下的任意位置寫一個(gè),并將#icon-xxx中的icon-xxx替換成你需要的icon名即可
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>
問題三
- 【疑惑】:阿里iconfont引入的原理是什么细移?
- 【解惑】:我們將這段js的原理拆開來(lái)看:
!function(t){var l,h,c,a,p,C,i,d=`
<svg><symbol id="icon-gengduo" viewBox="0 0 1024 1024"></symbol></svg>
`,o=(l=document.getElementsByTagName("script"))[l.length-1].getAttribute("data-injectcss");
if(o&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;
try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}
catch(t){console&&console.log(t)}}function L(){C||(C=!0,a())}h=function(){var t,l,h,c,a,p=document.createElement("div");p.innerHTML=d,d=null,(t=p.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",l=t,(h=document.body).firstChild?(c=l,(a=h.firstChild).parentNode.insertBefore(c,a)):h.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),h()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(a=h,p=t.document,C=!1,(i=function(){try{p.documentElement.doScroll("left")}catch(t){return void setTimeout(i,50)}L()})(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,L())})}(window);
建議復(fù)制到IDE中格式化后再看[dog/]
總的來(lái)說(shuō)主要最關(guān)鍵的有兩部分:
- 給body內(nèi)部的最頂上添加一個(gè)svg元素
- 給svg元素添加上style搏予,style給position:absolute 并且隱藏起來(lái)
其它的就是這段腳本的執(zhí)行時(shí)機(jī),再dom加載完成
如果腳本加載完畢后此時(shí)你的dom元素大概是這樣的:
<body>
<div>
<svg style="aria-hidden:true;position:absolute;width:0;height:0;overflow:hidden">
<symbol id="icon-gengduo" viewBox="0 0 1024 1024"></symbol>
</svg>
</div>
</body>
在使用時(shí)你在任意位置使用dom就是這個(gè)樣子
<body>
<div>
<svg style="aria-hidden:true;position:absolute;width:0;height:0;overflow:hidden">
<symbol id="icon-gengduo" viewBox="0 0 1024 1024"></symbol>
</svg>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-gengduo"></use>
</svg>
</div>
</body>
總結(jié):其中原理就是當(dāng)svg脫離文檔流后symbol就能夠在任意位置被svg進(jìn)行引用弧轧,多么奇妙的技巧