buildAdmin開源項目引入四種圖標(biāo)方式詳解
正文
在項目開發(fā)中,我們經(jīng)常使用可能都是UI組件庫里的圖標(biāo),當(dāng)然由于業(yè)務(wù)需要,可能當(dāng)前圖標(biāo)庫沒有我們需要的圖標(biāo)這時候就需要引入其它圖標(biāo)庫的圖標(biāo),比如iconfont、FontAweSome、本地圖標(biāo)庫。在了解引入這些圖標(biāo)庫之前,我們先學(xué)習(xí)一下各種圖標(biāo)庫的引入使用:
Element-Plus:由于elemen官方已經(jīng)把圖標(biāo)封裝成了組件,所以當(dāng)我們引入圖標(biāo)的時候,需要全局聲明組件。
import * as Icons from '@element-plus/icons'; const app = createApp(App); // 全局注冊圖標(biāo),犧牲一點性能 for (let i in Icons) { // 官方圖標(biāo)名稱首字母都是大寫,所以轉(zhuǎn)為小寫,并命名組件未el-icon-圖標(biāo)名 app.component(`el-icon-${toLine(i)}`, (Icons as any)[i]); } // 組件中使用圖標(biāo) <el-icon-user />
Iconfont:阿里巴巴圖標(biāo)庫,通過創(chuàng)建一個項目目錄,然后把我們需要的圖標(biāo)添加進去,然后在項目中引入圖標(biāo)目錄的cdn(三種方式之一:css代碼、css鏈接、js鏈接)就可以使用了,如果沒有特殊處理一般是在項目的index.html中引入相關(guān)鏈接,css代碼可以在根目錄的樣式文件中引入。然后就可以在項目中使用:
<i class="iconfont icon-user"></i>
FontAwesome:一個比較好用的字體圖標(biāo)庫,可以直接通過cdn引入,也可以通過安裝package包引入,然后就可以使用了:
英文官網(wǎng):fontawesome.com/search
中文網(wǎng):fontawesome.com.cn/
<i class="fa fa-user"></i>
引用本地圖標(biāo):一般使用svg格式圖標(biāo),因為svg性能好,相對于其它格式,它體積更小,可以任意放大圖形顯示,不以犧牲圖標(biāo)質(zhì)量為代價,項目中是不能直接加載svg格式,需要額外插件實現(xiàn)(后面會詳細(xì)介紹)。
<svg class="svg-icon icon" style="width: 1em;height: 1em;color: black;"> <use href="#local-vue" rel="external nofollow" rel="external nofollow" /> </svg>
為了方便維護以及擴展,我們可以把四種圖標(biāo)封裝為統(tǒng)一組件使用,在封裝前我們需要明確三點:
- 獲取所有圖標(biāo)。
- 實現(xiàn)圖標(biāo)可復(fù)制,復(fù)制就可用的原則。
- 圖標(biāo)使用統(tǒng)一組件。
在學(xué)習(xí)各類的圖標(biāo)庫之前我們先了解一下如何封裝一下圖標(biāo)共用組件,它向外暴露的名稱是Icon:
實現(xiàn)組件健壯性、易維護:支持圖標(biāo)名稱(name)、圖標(biāo)顏色(color)、圖標(biāo)大?。╯ize)三要素的自定義。四種圖標(biāo)格式引入為element-plus(el-icon-iconName
)、iconfont(iconfont iconName
)、fontawesome(fa fa-iconName
)、本地圖標(biāo)(local-iconName
),iconName是圖標(biāo)名稱。
props: { name: { type: String, required: true, }, size: { type: String, default: '30px', }, color: { type: String, default: '#00000', }, }, // 處理樣式,去掉多余px命名 const iconStyle = computed((): CSSProperties => { const { size, color } = props; let s = `${size.replace('px', '')}px`; return { fontSize: s, color: color, }; });
兼容上面四種圖標(biāo)實現(xiàn):通過Vue3的setup的返回值中使用渲染函數(shù)實現(xiàn),不需要在template中定義標(biāo)簽使用,分三種情況。
createVNode函數(shù):創(chuàng)建虛擬節(jié)點,從左到右有三個參數(shù):html標(biāo)簽名稱或組件(String)、標(biāo)簽屬性(Object)、嵌套標(biāo)簽定義(Array)。
對于element-plus圖標(biāo)的渲染:官方是通過el-icon標(biāo)簽內(nèi)直接使用圖標(biāo)組件,所以創(chuàng)建虛擬節(jié)點標(biāo)簽就是el-icon,由于圖標(biāo)組件是嵌套的,所以需要用到第三參數(shù)。
setup(props) { // 當(dāng)前引入的是element-plus圖標(biāo) if (props.name.indexOf('el-icon-') === 0) { return () => createVNode( 'el-icon', { class: 'icon el-icon', style: iconStyle.value }, [createVNode(resolveComponent(props.name))] ); } }
對于iconfont、fontawesome圖標(biāo)的渲染:由于使用這兩種的圖標(biāo)的標(biāo)簽都是i,它們唯一不同就是圖標(biāo)名稱的命名所以可以共用同一個渲染函數(shù)。
setup(props){ // 當(dāng)前引入的是iconfont或fontawesome圖標(biāo) if (props.name.indexOf('local-') === 0 || isExternal(props.name)) { return () => createVNode('i', { class: [props.name, 'icon'], style: iconStyle.value, }); } }
對于本地svg圖標(biāo)的渲染:直接引入本地封裝的svg組件,把這個組件當(dāng)作渲染標(biāo)簽,這里圖標(biāo)命名以local-iconName格式引入的。
setup(props){ // 當(dāng)前引入的是本地svg圖標(biāo) if (props.name.indexOf('local-') === 0 || isExternal(props.name)) { return () => createVNode(svg, { name: props.name, size: props.size, color: props.color, }); } }
最終就可以通過這樣使用圖標(biāo):
<Icon name="" color="" size=""/>
其實上面就已經(jīng)實現(xiàn)了四種圖標(biāo)的類型統(tǒng)一封裝,一致使用。接下來為了更方便獲取圖標(biāo),我們把所有圖標(biāo)封裝起來就可以直接cv使用了。
點擊實現(xiàn)cv方式:通過點擊圖標(biāo)傳入我們想要復(fù)制的內(nèi)容,一般都是整個組件的字符串。
export const useCopy = (text: string) => { let input = document.createElement('input'); // 創(chuàng)建輸入框 input.value = text; // 給輸入框value賦值 document.body.appendChild(input); // 追加到body里面去 input.select(); // 選擇輸入框的操作 document.execCommand('Copy'); // 執(zhí)行復(fù)制操作 document.body.removeChild(input); // 刪除加入的輸入框 ElMessage.success('復(fù)制成功!'); };
引入Element-Plus圖標(biāo)庫
import * as elIcons from '@element-plus/icons-vue'; // 獲取所有Element-Plus圖標(biāo)組件名稱,如搜索圖標(biāo)Search export function getElementPlusIconfontNames() { return new Promise<string[]>((resolve, reject) => { nextTick(() => { const iconfonts = []; const icons = elIcons as any; // 遍歷添加icons組件名稱 for (const i in icons) { iconfonts.push(icons[i].name); } if (iconfonts.length > 0) { resolve(iconfonts); } else { reject('No ElementPlus Icons'); } }); }); }
引入Iconfont圖標(biāo)庫
先加載圖標(biāo)樣式表:
const cssUrls: Array<string> = [ '//at.alicdn.com/t/c/font_3846007_vf3shrhbpya.css', // 阿里圖標(biāo)庫cs,每添加一次圖標(biāo)都需要更換 '//cdn.bootcdn.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css', // font-awesome的css ]; export default function init() { // 遍歷加載圖標(biāo)鏈接樣式 if (cssUrls.length > 0) { cssUrls.map((v) => { loadCss(v); }); } } // 通過創(chuàng)建link標(biāo)簽引入樣式鏈接 export function loadCss(url: string): void { const link = document.createElement('link'); // 創(chuàng)建link標(biāo)簽 link.rel = 'stylesheet'; link.href = url; // 是否采用跨域的方式加載。它可以取兩個值 // anonymous(跨域請求時,不發(fā)送用戶憑證,主要是 Cookie) // use-credentials(跨域時發(fā)送用戶憑證)。 link.crossOrigin = 'anonmous'; document.getElementsByTagName('head')[0].appendChild(link); }
獲取當(dāng)前頁面中從指定域名加載到的樣式表內(nèi)容:在調(diào)用這個函數(shù)之前必須要先引入樣式。
// 獲取樣式表內(nèi)容 function getStylesFromDomain(domain: string) { const sheets = []; const styles: StyleSheetList = document.styleSheets; for (const key in styles) { if (styles[key].href && (styles[key].href as string).indexOf(domain) > -1) { sheets.push(styles[key]); } } return sheets; }
調(diào)用這個函數(shù)之后就可以獲取到當(dāng)前圖標(biāo)庫相關(guān)樣式表內(nèi)容,我們的目的就是拿到圖標(biāo)名稱,可以提取rules數(shù)組內(nèi)的樣式名稱就可以拿到所有圖標(biāo)名稱了。
// 獲取所有iconfont圖標(biāo)庫圖標(biāo)名稱 export function getIconfontNames() { init(); return new Promise<string[]>((resolve, reject) => { nextTick(() => { const iconfonts = []; const sheets = getStylesFromDomain('at.alicdn.com'); for (const key in sheets) { const rules: any = sheets[key].cssRules; for (const k in rules) { // .表示匹配除換行符 \n 之外的任何單字符 // *表示單個字符匹配任意次 if ( rules[k].selectorText && /^\.icon-(.*)::before$/g.test(rules[k].selectorText) ) { // 去掉樣式的.符號以及::before iconfonts.push( `${rules[k].selectorText .substring(1, rules[k].selectorText.length) .replace(/\:\:before/gi, '')}` ); } } } if (iconfonts.length > 0) { resolve(iconfonts); } else { reject('No Iconfont style sheet'); } }); }); }
引入FontAwesome圖標(biāo)庫
先加載圖標(biāo)樣式表:也就是直接調(diào)用init函數(shù),加載相應(yīng)的樣式鏈接。
獲取當(dāng)前頁面中從指定域名加載到的樣式表內(nèi)容:如下圖所示。
export function getAwesomeIconfontName() { init(); return new Promise<string[]>((resolve, reject) => { nextTick(() => { const iconfonts = []; // 獲取所有圖標(biāo)名稱 const sheets = getStylesFromDomain( 'cdn.bootcdn.net/ajax/libs/font-awesome/' ); for (const key in sheets) { const rules: any = sheets[key].cssRules; // 處理方法與iconfont一致,只不過名稱不一樣 for (const k in rules) { if ( rules[k].selectorText && /^\.fa-(.*)::before$/g.test(rules[k].selectorText) ) { if (rules[k].selectorText.indexOf(', ') > -1) { // selectorText里有多個圖標(biāo),只提取第一個 const iconNames = rules[k].selectorText.split(', '); iconfonts.push( `${iconNames[0] .substring(1, iconNames[0].length) .replace(/\:\:before/gi, '')}` ); } else { iconfonts.push( `${rules[k].selectorText .substring(1, rules[k].selectorText.length) .replace(/\:\:before/gi, '')}` ); } } } } if (iconfonts.length > 0) { resolve(iconfonts); } else { reject('No AwesomeIcon style sheet'); } }); }); }
引入本地svg圖標(biāo)
在引入本地svg圖標(biāo)之前,我們先了解一下svg標(biāo)簽的相關(guān)知識:
?? 什么是svg?
svg:即 Scalable Vector Graphics,是一種用來繪制矢量圖的 HTML5 標(biāo)簽,與canvas有點類似,它可以像HTML畫布一樣用于制作圖形和動畫。
svg標(biāo)簽常見屬性有:
svg標(biāo)簽內(nèi)部常見的繪制標(biāo)簽有:
x:
x軸協(xié)調(diào)圖像的位置。y:
y軸協(xié)調(diào)圖像的位置。width:
圖像的寬度。height:
圖片的高度。viewBox:
SVG元素的界限。id、class屬性
。fill
:svg元素的填充顏色。stroke
:svg 元素的描邊顏色,例如線條、文本等描邊顏色。- ....
<line>
標(biāo)簽:繪制一條直線。<rect>
標(biāo)簽:繪制一個矩形。<polygon>
標(biāo)簽:繪制一個多邊形。<circle>
標(biāo)簽:繪制一個圓形。<ellipse>
標(biāo)簽:繪制一個橢圓。<path>
標(biāo)簽:于繪制路徑,其是 svg 基本形狀中最強大的一個,你可以用它創(chuàng)建線條,曲線,弧形,圓等各種形狀,其具有d
屬性,用于指定一系列繪制的命令,命令后面接坐標(biāo)。
?? 如何加載svg?
在html中如何定義svg:在svg標(biāo)簽內(nèi)定義繪制圖形的標(biāo)簽。
// 方式一:只能定義一個svg圖標(biāo) <svg class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"> <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> </svg>
/* 方式二:可定義多個svg圖標(biāo),需要symbol標(biāo)簽配合,把繪制標(biāo)簽定義在symbol標(biāo)簽內(nèi) */ /* 一般是在index.html文件中body標(biāo)簽下定義 */ <svg> // 一個symbol定義代表一個圖標(biāo) <symbol id="local-vue"></symbol> <symbol id="local-logo"></symbol> ... </svg> /* 然后就可以在組件中實例化使用 */ <svg><use href="#local-vue" rel="external nofollow" rel="external nofollow" ></use></svg>
?? 封裝加載svg插件?
去掉svg標(biāo)簽,只取svg標(biāo)簽內(nèi)部的繪制內(nèi)容。
let idPrefix = ''; const iconNames: string[] = []; const svgTitle = /<svg([^>+].*?)>/; const clearHeightWidth = /(width|height)="([^>+].*?)"/g;// 清空寬高 const hasViewBox = /(viewBox="[^>+].*?")/g;// 是否有ViewBox屬性 const clearReturn = /(\r)|(\n)/g; // 清空換行符 const clearFill = /(fill="[^>+].*?")/g; // 清理 svg 的 fill // 查找svg所有文件 function findSvgFile(dir: string = '../../../assets/icons/'): string[] { const svgRes = []; // readdirSync,返回一個包含“指定目錄下所有文件名稱”的數(shù)組對象 // [ Dirent { name: 'vue.svg', [Symbol(type)]: 1 } ] const dirents = readdirSync(dir, { withFileTypes: true, }); console.log(dirents); for (const dirent of dirents) { iconNames.push(`${idPrefix}-${dirent.name.replace('.svg', '')}`); // [ 'local-vue' ] // 如果path表示的是一個目錄則返回true if (dirent.isDirectory()) { svgRes.push(...findSvgFile(dir + dirent.name + '/')); } else { const svg = readFileSync(dir + dirent.name) .toString().replace(clearReturn, '').replace(clearFill, 'fill=""'.replace(svgTitle, ($1, $2) => { let width = 0; let height = 0; let content = $2.replace(clearHeightWidth, (s1: string, s2: string, s3: number) => { if (s2 === 'width') { width = s3; } else if (s2 === 'height') { height = s3; } return ''; } ); if (!hasViewBox.test($2)) { content += `viewBox="0 0 ${width} ${height}"`; } // 去掉擴展名 return `<symbol id="${idPrefix}-${dirent.name.replace( '.svg', '' )}" ${content}>`; }) .replace('</svg>', '</symbol>');// 替換尾部標(biāo)簽 svgRes.push(svg); } } return svgRes; }
轉(zhuǎn)化為真正渲染的html,在vite.config中的plugin插件屬性中引入svgBuilder并傳入存放svg圖標(biāo)的路徑。
/** * * @param path // 所有svg圖標(biāo)存放地址 * @param perfix // 圖標(biāo)自定義前綴 * @returns */ export const svgBuilder = (path: string, perfix = 'local') => { if (path === '') return; idPrefix = perfix; // 每個圖標(biāo)都是symbol標(biāo)簽,去掉了svg標(biāo)簽,只包含的svg內(nèi)部嵌套標(biāo)簽,res是一個數(shù)組,每個元素就是一個圖標(biāo) const res = findSvgFile(path); return { name: 'svg-transform', transformIndexHtml(html: string) { /* eslint-disable */ return html.replace( '<body>', ` <body> <svg id="local-icon" data-icon-name="${iconNames.join(',')}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0"> ${res.join('')} </svg> ` ); /* eslint-enable */ }, }; };
獲取所有本地圖標(biāo)名稱通過定義id,由于封裝插件的時候已經(jīng)定義了元素id="local-icon",所以可以全局定義獲取。下面獲取到的svgEl值如圖所示。
export function getLocalIconfontNames() { return new Promise<string[]>((resolve, reject) => { nextTick(() => { let iconfonts: string[] = []; const svgEl = document.getElementById('local-icon'); // 判斷DOMStringMap對象內(nèi)的iconName屬性是否有值 if (svgEl?.dataset.iconName) { iconfonts = (svgEl?.dataset.iconName as string).split(','); } if (iconfonts.length > 0) { resolve(iconfonts); } else { reject('No Local Icons!'); } }); }); }
參考資料
以上就是buildAdmin開源項目引入四種圖標(biāo)方式詳解的詳細(xì)內(nèi)容,更多關(guān)于buildAdmin引入圖標(biāo)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue3簡單封裝input組件和統(tǒng)一表單數(shù)據(jù)詳解
最近有一個需求是很多個表單添加,編輯等操作,會用到很多input輸入框,所以就想把input進行簡單封裝,這篇文章主要給大家介紹了關(guān)于vue3簡單封裝input組件和統(tǒng)一表單數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2022-05-05vue與django(drf)實現(xiàn)文件上傳下載功能全過程
最近簡單的學(xué)習(xí)了django和drf上傳文件(主要是圖片),做一個記錄,下面這篇文章主要給大家介紹了關(guān)于vue與django(drf)實現(xiàn)文件上傳下載功能的相關(guān)資料,需要的朋友可以參考下2023-02-02