使用Vue.js建立一個可重用的SVG元件
使用Vue.js建立一個可重用的SVG元件
SVG影象可以在標記中引用,就像任何其他影象格式一樣,但內聯SVG元素是最健壯的方法,因為它允許動態編輯SVG屬性,而且不需要額外的HTTP請求。然而,對於複雜的影象,內聯SVG程式碼可能會很混亂,並且為多個影象重複這段程式碼不是很DRY。在多個地方使用內聯SVG可能需要複製和貼上冗長的程式碼塊,這很快就會變得難以管理,並可能汙染原本整潔的程式碼庫。
解決方案是使用Vue元件包裝SVG內聯程式碼。這允許您將內聯SVG程式碼與應用程式模板的其餘部分分開,並擁有相同SVG影象的多個例項,每個例項都有自己的動態屬性。
管理Vue應用程式中的自定義圖示集合有時可能是一項挑戰。圖示字型很容易使用,但對於定製,您必須依賴於第三方字型生成器,並且合併衝突可能很難解決,因為字型是二進位制檔案。
而使用SVG檔案可以消除這些問題,但我們如何確保它們在易於使用的同時也易於新增或刪除圖示呢?
以下是我理想中的圖示系統:
要新增圖示,只需將它們放入指定的圖示資料夾。如果你不再需要一個圖示,你只需要刪除它。
要在模板中使用rocket.svg圖示,語法簡單如。
這些圖示可以使用CSS字型和顏色屬性(就像圖示字型一樣)縮放和著色。
如果同一圖示的多個例項出現在頁面上,則SVG程式碼不會每次都重複。
不需要webpack配置編輯。
這就是我們將通過編寫兩個小的單檔案元件來構建的內容。這個實現有一些特定的要求,儘管我相信你們中的許多人可以在其他框架和構建工具中重新設計這個系統:
webpack:如果你使用Vue CLI來構建你的應用,那麼你已經在使用webpack了。
SVG -inline-loader:這允許我們載入所有的SVG程式碼,並清理我們不想要的部分。
繼續,從終端執行開始。
https://www.npmjs.com/package/svg-inline-loader
npm install svg-inline-loader --save-dev
SVG精靈元件
為了滿足不為頁面上的每個圖示例項重複SVG程式碼的要求,我們需要構建一個SVG“精靈”。如果您以前沒有聽說過SVG精靈,可以將其視為包含其他SVG的隱藏SVG。任何需要顯示圖示的地方,我們都可以通過引用標籤中的圖示id將其複製出來,如下所示:
<svg><use xlink:href="#rocket" /></svg>
SvgSprite.vue
<template> <svg width="0" height="0" style="display: none;" v-html="$options.svgSprite" /> </template> <script> const svgContext = require.context( '!svg-inline-loader?' + 'removeTags=true' + // remove title tags, etc. '&removeSVGTagAttrs=true' + // enable removing attributes '&removingTagAttrs=fill' + // remove fill attributes '!@/assets/icons', // search this directory true, // search subdirectories /\w+\.svg$/i // only include SVG files ) const symbols = svgContext.keys().map(path => { // get SVG file content const content = svgContext(path) // extract icon id from filename const id = path.replace(/^\.\/(.*)\.\w+$/, '$1') // replace svg tags with symbol tags and id attribute return content.replace('<svg', `<symbol id="${id}"`).replace('svg>', 'symbol>') }) export default { name: 'SvgSprite', svgSprite: symbols.join('\n'), // concatenate all symbols into $options.svgSprite } </script>
在模板中,我們唯一的元素的內容繫結到$options.svgSprite上。如果您不熟悉$options,它包含直接附加到Vue元件的屬性。我們可以將svgSprite附加到元件的資料上,但我們並不需要Vue來設定響應性,因為我們的SVG載入器只會在應用構建時執行。
在我們的指令碼中,我們使用了require。context來檢索我們所有的SVG檔案並清理它們。我們呼叫svg-inline-loader,並使用非常類似於查詢字串引數的語法向它傳遞幾個引數。為了更容易理解,我把它們分成了幾行。
const svgContext = require.context( '!svg-inline-loader?' + 'removeTags=true' + // remove title tags, etc. '&removeSVGTagAttrs=true' + // enable removing attributes '&removingTagAttrs=fill' + // remove fill attributes '!@/assets/icons', // search this directory true, // search subdirectories /\w+\.svg$/i // only include SVG files )
我們在此所做的基本上是清理位於特定目錄(/assets/icons)中的SVG檔案,以便它們處於良好狀態,可以在任何需要它們的地方使用。
removeTags引數去掉了圖示不需要的標記,比如標題和樣式。我們特別想要刪除標題標籤,因為它們會導致不必要的工具提示。如果您希望在圖示中保留任何硬編碼的樣式,那麼新增removingTags=title作為附加引數,以便只刪除標題標籤。
我們還告訴我們的載入器刪除填充屬性,以便我們以後可以用CSS設定自己的填充顏色。你可能想要保留你的填充顏色。如果是這種情況,那麼只需刪除removeSVGTagAttrs和removingTagAttrs引數。
最後一個載入器引數是SVG圖示資料夾的路徑。然後我們提供需求。context具有另外兩個引數,因此它搜尋子目錄並只加載SVG檔案。
為了將所有SVG元素巢狀到SVG精靈中,我們必須將它們從< SVG >元素轉換為SVG 元素。這很簡單,只需更改標記並給每個標記一個唯一的id,這個id是我們從檔名中提取的。
const symbols = svgContext.keys().map(path => { // extract icon id from filename const id = path.replace(/^\.\/(.*)\.\w+$/, '$1') // get SVG file content const content = svgContext(path) // replace svg tags with symbol tags and id attribute return content.replace('<svg', `<symbol id="${id}"`).replace('svg>', 'symbol>') })
我們怎麼處理這個元件?我們把它放在頁面上任何依賴於它的圖示之前。我建議將其新增到App.vue檔案的頂部。
<!-- App.vue --> <template> <div id="app"> <svg-sprite /> <!-- ... -->
The icon component
現在讓我們構建SvgIcon。vue元件。
<!-- SvgIcon.vue --> <template> <svg class="icon" :class="{ 'icon-spin': spin }"> <use :xlink:href="`#${icon}`" /> </svg> </template> <script> export default { name: 'SvgIcon', props: { icon: { type: String, required: true, }, spin: { type: Boolean, default: false, }, }, } </script> <style> svg.icon { fill: currentColor; height: 1em; margin-bottom: 0.125em; vertical-align: middle; width: 1em; } svg.icon-spin { animation: icon-spin 2s infinite linear; } @keyframes icon-spin { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } </style>
這個元件要簡單得多。如前所述,我們利用標籤來引用精靈中的id。那個id來自我們元件的圖示道具。
我添加了一個旋轉道具在那裡切換。icon-spin類作為一個可選的動畫位,如果我們需要的話。例如,這可能對載入旋轉器圖示很有用。
這個例子是 當載入的時候 圖示在loading 旋轉
<svg-icon v-if="isLoading" icon="spinner" spin />
根據您的需要,您可能希望新增額外的道具,如旋轉或翻轉。如果願意,您可以簡單地將類直接新增到元件中,而不需要使用道具。
我們元件的大部分內容都是CSS。除了旋轉動畫之外,這大部分用於使我們的SVG圖標表現得更像圖示字型¹。為了讓圖示與文字基線對齊,我發現在大多數情況下,應用垂直對齊:中間,加上0.125em的底部邊緣都是可行的。我們還將填充屬性值設定為currentColor,這允許我們像文字一樣為圖示著色。
<p style="font-size: 2em; color: red;"> <svg-icon icon="exclamation-circle" /><!-- This icon will be 2em and red. --> Error! </p>
就是這樣!如果你想在應用的任何地方使用圖示元件,而不需要把它匯入到每個需要它的元件中,請確保在你的main.js檔案中註冊該元件:
// main.js import Vue from 'vue' import SvgIcon from '@/components/SvgIcon.vue' Vue.component('svg-icon', SvgIcon)
文章用翻譯軟體翻譯成中文轉載來自下面:
https://css-tricks.com/a-font-like-svg-icon-system-for-vue/
https://hackwild.com/article/creating-a-reusable-svg-component-with-vue/