您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“buildAdmin開源項目引入四種圖標方式是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“buildAdmin開源項目引入四種圖標方式是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
在項目開發中,我們經常使用可能都是UI組件庫里的圖標,當然由于業務需要,可能當前圖標庫沒有我們需要的圖標這時候就需要引入其它圖標庫的圖標,比如iconfont、FontAweSome、本地圖標庫。在了解引入這些圖標庫之前,我們先學習一下各種圖標庫的引入使用:
Element-Plus:由于elemen官方已經把圖標封裝成了組件,所以當我們引入圖標的時候,需要全局聲明組件。
import * as Icons from '@element-plus/icons'; const app = createApp(App); // 全局注冊圖標,犧牲一點性能 for (let i in Icons) { // 官方圖標名稱首字母都是大寫,所以轉為小寫,并命名組件未el-icon-圖標名 app.component(`el-icon-${toLine(i)}`, (Icons as any)[i]); } // 組件中使用圖標 <el-icon-user />
Iconfont:阿里巴巴圖標庫,通過創建一個項目目錄,然后把我們需要的圖標添加進去,然后在項目中引入圖標目錄的cdn(三種方式之一:css代碼、css鏈接、js鏈接)就可以使用了,如果沒有特殊處理一般是在項目的index.html中引入相關鏈接,css代碼可以在根目錄的樣式文件中引入。然后就可以在項目中使用:
<i class="iconfont icon-user"></i>
FontAwesome:一個比較好用的字體圖標庫,可以直接通過cdn引入,也可以通過安裝package包引入,然后就可以使用了:
英文官網:fontawesome.com/search
中文網:fontawesome.com.cn/
<i class="fa fa-user"></i>
引用本地圖標:一般使用svg格式圖標,因為svg性能好,相對于其它格式,它體積更小,可以任意放大圖形顯示,不以犧牲圖標質量為代價,項目中是不能直接加載svg格式,需要額外插件實現(后面會詳細介紹)。
<svg class="svg-icon icon" > <use href="#local-vue" rel="external nofollow" rel="external nofollow" /> </svg>
為了方便維護以及擴展,我們可以把四種圖標封裝為統一組件使用,在封裝前我們需要明確三點:
獲取所有圖標。
實現圖標可復制,復制就可用的原則。
圖標使用統一組件。
在學習各類的圖標庫之前我們先了解一下如何封裝一下圖標共用組件,它向外暴露的名稱是Icon:
實現組件健壯性、易維護:支持圖標名稱(name)、圖標顏色(color)、圖標大小(size)三要素的自定義。四種圖標格式引入為element-plus(el-icon-iconName
)、iconfont(iconfont iconName
)、fontawesome(fa fa-iconName
)、本地圖標(local-iconName
),iconName是圖標名稱。
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, }; });
兼容上面四種圖標實現:通過Vue3的setup的返回值中使用渲染函數實現,不需要在template中定義標簽使用,分三種情況。
createVNode函數:創建虛擬節點,從左到右有三個參數:html標簽名稱或組件(String)、標簽屬性(Object)、嵌套標簽定義(Array)。
對于element-plus圖標的渲染:官方是通過el-icon標簽內直接使用圖標組件,所以創建虛擬節點標簽就是el-icon,由于圖標組件是嵌套的,所以需要用到第三參數。
setup(props) { // 當前引入的是element-plus圖標 if (props.name.indexOf('el-icon-') === 0) { return () => createVNode( 'el-icon', { class: 'icon el-icon', style: iconStyle.value }, [createVNode(resolveComponent(props.name))] ); } }
對于iconfont、fontawesome圖標的渲染:由于使用這兩種的圖標的標簽都是i,它們唯一不同就是圖標名稱的命名所以可以共用同一個渲染函數。
setup(props){ // 當前引入的是iconfont或fontawesome圖標 if (props.name.indexOf('local-') === 0 || isExternal(props.name)) { return () => createVNode('i', { class: [props.name, 'icon'], style: iconStyle.value, }); } }
對于本地svg圖標的渲染:直接引入本地封裝的svg組件,把這個組件當作渲染標簽,這里圖標命名以local-iconName格式引入的。
setup(props){ // 當前引入的是本地svg圖標 if (props.name.indexOf('local-') === 0 || isExternal(props.name)) { return () => createVNode(svg, { name: props.name, size: props.size, color: props.color, }); } }
最終就可以通過這樣使用圖標:
<Icon name="" color="" size=""/>
其實上面就已經實現了四種圖標的類型統一封裝,一致使用。接下來為了更方便獲取圖標,我們把所有圖標封裝起來就可以直接cv使用了。
點擊實現cv方式:通過點擊圖標傳入我們想要復制的內容,一般都是整個組件的字符串。
export const useCopy = (text: string) => { let input = document.createElement('input'); // 創建輸入框 input.value = text; // 給輸入框value賦值 document.body.appendChild(input); // 追加到body里面去 input.select(); // 選擇輸入框的操作 document.execCommand('Copy'); // 執行復制操作 document.body.removeChild(input); // 刪除加入的輸入框 ElMessage.success('復制成功!'); };
import * as elIcons from '@element-plus/icons-vue'; // 獲取所有Element-Plus圖標組件名稱,如搜索圖標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'); } }); }); }
先加載圖標樣式表:
const cssUrls: Array<string> = [ '//at.alicdn.com/t/c/font_3846007_vf3shrhbpya.css', // 阿里圖標庫cs,每添加一次圖標都需要更換 '//cdn.bootcdn.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css', // font-awesome的css ]; export default function init() { // 遍歷加載圖標鏈接樣式 if (cssUrls.length > 0) { cssUrls.map((v) => { loadCss(v); }); } } // 通過創建link標簽引入樣式鏈接 export function loadCss(url: string): void { const link = document.createElement('link'); // 創建link標簽 link.rel = 'stylesheet'; link.href = url; // 是否采用跨域的方式加載。它可以取兩個值 // anonymous(跨域請求時,不發送用戶憑證,主要是 Cookie) // use-credentials(跨域時發送用戶憑證)。 link.crossOrigin = 'anonmous'; document.getElementsByTagName('head')[0].appendChild(link); }
獲取當前頁面中從指定域名加載到的樣式表內容:在調用這個函數之前必須要先引入樣式。
// 獲取樣式表內容 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; }
調用這個函數之后就可以獲取到當前圖標庫相關樣式表內容,我們的目的就是拿到圖標名稱,可以提取rules數組內的樣式名稱就可以拿到所有圖標名稱了。
// 獲取所有iconfont圖標庫圖標名稱 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'); } }); }); }
先加載圖標樣式表:也就是直接調用init函數,加載相應的樣式鏈接。
獲取當前頁面中從指定域名加載到的樣式表內容:如下圖所示。
export function getAwesomeIconfontName() { init(); return new Promise<string[]>((resolve, reject) => { nextTick(() => { const iconfonts = []; // 獲取所有圖標名稱 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里有多個圖標,只提取第一個 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圖標之前,我們先了解一下svg標簽的相關知識:
什么是svg?
svg:即 Scalable Vector Graphics,是一種用來繪制矢量圖的 HTML5 標簽,與canvas有點類似,它可以像HTML畫布一樣用于制作圖形和動畫。
svg標簽常見屬性有:
svg標簽內部常見的繪制標簽有:
x:
x軸協調圖像的位置。
y:
y軸協調圖像的位置。
width:
圖像的寬度。
height:
圖片的高度。
viewBox:
SVG元素的界限。
id、class屬性
。
fill
:svg元素的填充顏色。
stroke
:svg 元素的描邊顏色,例如線條、文本等描邊顏色。
....
<line>
標簽:繪制一條直線。
<rect>
標簽:繪制一個矩形。
<polygon>
標簽:繪制一個多邊形。
<circle>
標簽:繪制一個圓形。
<ellipse>
標簽:繪制一個橢圓。
<path>
標簽:于繪制路徑,其是 svg 基本形狀中最強大的一個,你可以用它創建線條,曲線,弧形,圓等各種形狀,其具有 d
屬性,用于指定一系列繪制的命令,命令后面接坐標。
???? 如何加載svg?
在html中如何定義svg:在svg標簽內定義繪制圖形的標簽。
// 方式一:只能定義一個svg圖標 <svg class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"> <path d="M408 442h580c4.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 8h580c4.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圖標,需要symbol標簽配合,把繪制標簽定義在symbol標簽內 */ /* 一般是在index.html文件中body標簽下定義 */ <svg> // 一個symbol定義代表一個圖標 <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標簽,只取svg標簽內部的繪制內容。
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,返回一個包含“指定目錄下所有文件名稱”的數組對象 // [ 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>');// 替換尾部標簽 svgRes.push(svg); } } return svgRes; }
轉化為真正渲染的html,在vite.config中的plugin插件屬性中引入svgBuilder并傳入存放svg圖標的路徑。
/** * * @param path // 所有svg圖標存放地址 * @param perfix // 圖標自定義前綴 * @returns */ export const svgBuilder = (path: string, perfix = 'local') => { if (path === '') return; idPrefix = perfix; // 每個圖標都是symbol標簽,去掉了svg標簽,只包含的svg內部嵌套標簽,res是一個數組,每個元素就是一個圖標 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" > ${res.join('')} </svg> ` ); /* eslint-enable */ }, }; };
獲取所有本地圖標名稱通過定義id,由于封裝插件的時候已經定義了元素id="local-icon",所以可以全局定義獲取。下面獲取到的svgEl值如圖所示。
export function getLocalIconfontNames() { return new Promise<string[]>((resolve, reject) => { nextTick(() => { let iconfonts: string[] = []; const svgEl = document.getElementById('local-icon'); // 判斷DOMStringMap對象內的iconName屬性是否有值 if (svgEl?.dataset.iconName) { iconfonts = (svgEl?.dataset.iconName as string).split(','); } if (iconfonts.length > 0) { resolve(iconfonts); } else { reject('No Local Icons!'); } }); }); }
讀到這里,這篇“buildAdmin開源項目引入四種圖標方式是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。