溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式是什么

發(fā)布時(shí)間:2023-02-03 09:13:06 來源:億速云 閱讀:124 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

正文

在項(xiàng)目開發(fā)中,我們經(jīng)常使用可能都是UI組件庫里的圖標(biāo),當(dāng)然由于業(yè)務(wù)需要,可能當(dāng)前圖標(biāo)庫沒有我們需要的圖標(biāo)這時(shí)候就需要引入其它圖標(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)的時(shí)候,需要全局聲明組件。

import * as Icons from '@element-plus/icons';
const app = createApp(App);
// 全局注冊(cè)圖標(biāo),犧牲一點(diǎn)性能
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)建一個(gè)項(xiàng)目目錄,然后把我們需要的圖標(biāo)添加進(jìn)去,然后在項(xiàng)目中引入圖標(biāo)目錄的cdn(三種方式之一:css代碼、css鏈接、js鏈接)就可以使用了,如果沒有特殊處理一般是在項(xiàng)目的index.html中引入相關(guān)鏈接,css代碼可以在根目錄的樣式文件中引入。然后就可以在項(xiàng)目中使用:

<i class="iconfont icon-user"></i>

FontAwesome:一個(gè)比較好用的字體圖標(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),因?yàn)閟vg性能好,相對(duì)于其它格式,它體積更小,可以任意放大圖形顯示,不以犧牲圖標(biāo)質(zhì)量為代價(jià),項(xiàng)目中是不能直接加載svg格式,需要額外插件實(shí)現(xiàn)(后面會(huì)詳細(xì)介紹)。

<svg class="svg-icon icon" >
<use href="#local-vue" rel="external nofollow"  rel="external nofollow"  />
</svg>

為了方便維護(hù)以及擴(kuò)展,我們可以把四種圖標(biāo)封裝為統(tǒng)一組件使用,在封裝前我們需要明確三點(diǎn):

  • 獲取所有圖標(biāo)。

  • 實(shí)現(xiàn)圖標(biāo)可復(fù)制,復(fù)制就可用的原則。

  • 圖標(biāo)使用統(tǒng)一組件。

在學(xué)習(xí)各類的圖標(biāo)庫之前我們先了解一下如何封裝一下圖標(biāo)共用組件,它向外暴露的名稱是Icon:

實(shí)現(xiàn)組件健壯性、易維護(hù):支持圖標(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)實(shí)現(xiàn):通過Vue3的setup的返回值中使用渲染函數(shù)實(shí)現(xiàn),不需要在template中定義標(biāo)簽使用,分三種情況。

createVNode函數(shù):創(chuàng)建虛擬節(jié)點(diǎn),從左到右有三個(gè)參數(shù):html標(biāo)簽名稱或組件(String)、標(biāo)簽屬性(Object)、嵌套標(biāo)簽定義(Array)。

對(duì)于element-plus圖標(biāo)的渲染:官方是通過el-icon標(biāo)簽內(nèi)直接使用圖標(biāo)組件,所以創(chuàng)建虛擬節(jié)點(diǎn)標(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))]
        );
    }
 }

對(duì)于iconfont、fontawesome圖標(biāo)的渲染:由于使用這兩種的圖標(biāo)的標(biāo)簽都是i,它們唯一不同就是圖標(biāo)名稱的命名所以可以共用同一個(gè)渲染函數(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,
    });
  }
}

對(duì)于本地svg圖標(biāo)的渲染:直接引入本地封裝的svg組件,把這個(gè)組件當(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=""/>

其實(shí)上面就已經(jīng)實(shí)現(xiàn)了四種圖標(biāo)的類型統(tǒng)一封裝,一致使用。接下來為了更方便獲取圖標(biāo),我們把所有圖標(biāo)封裝起來就可以直接cv使用了。

點(diǎn)擊實(shí)現(xiàn)cv方式:通過點(diǎn)擊圖標(biāo)傳入我們想要復(fù)制的內(nèi)容,一般都是整個(gè)組件的字符串。

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;
  // 是否采用跨域的方式加載。它可以取兩個(gè)值
  // anonymous(跨域請(qǐng)求時(shí),不發(fā)送用戶憑證,主要是 Cookie)
  // use-credentials(跨域時(shí)發(fā)送用戶憑證)。
  link.crossOrigin = 'anonmous';
  document.getElementsByTagName('head')[0].appendChild(link);
}

獲取當(dāng)前頁面中從指定域名加載到的樣式表內(nèi)容:在調(diào)用這個(gè)函數(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)用這個(gè)函數(shù)之后就可以獲取到當(dāng)前圖標(biāo)庫相關(guān)樣式表內(nèi)容,我們的目的就是拿到圖標(biāo)名稱,可以提取rules數(shù)組內(nèi)的樣式名稱就可以拿到所有圖標(biāo)名稱了。

buildAdmin開源項(xiàng)目引入四種圖標(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 之外的任何單字符
          // *表示單個(gè)字符匹配任意次
          if (
            rules[k].selectorText &&
            /^\.icon-(.*)::before$/g.test(rules[k].selectorText)
          ) {
            // 去掉樣式的.符號(hào)以及::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)容:如下圖所示。

buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式是什么

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里有多個(gè)圖標(biāo),只提取第一個(gè)
              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)知識(shí):

什么是svg?

svg:即 Scalable Vector Graphics,是一種用來繪制矢量圖的 HTML5 標(biāo)簽,與canvas有點(diǎn)類似,它可以像HTML畫布一樣用于制作圖形和動(dòng)畫。

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)簽:繪制一個(gè)矩形。

  • <polygon> 標(biāo)簽:繪制一個(gè)多邊形。

  • <circle> 標(biāo)簽:繪制一個(gè)圓形。

  • <ellipse> 標(biāo)簽:繪制一個(gè)橢圓。

  • <path> 標(biāo)簽:于繪制路徑,其是 svg 基本形狀中最強(qiáng)大的一個(gè),你可以用它創(chuàng)建線條,曲線,弧形,圓等各種形狀,其具有 d 屬性,用于指定一系列繪制的命令,命令后面接坐標(biāo)。

???? 如何加載svg?

在html中如何定義svg:在svg標(biāo)簽內(nèi)定義繪制圖形的標(biāo)簽。

// 方式一:只能定義一個(gè)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 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>
/* 方式二:可定義多個(gè)svg圖標(biāo),需要symbol標(biāo)簽配合,把繪制標(biāo)簽定義在symbol標(biāo)簽內(nèi) */
/* 一般是在index.html文件中body標(biāo)簽下定義 */
<svg>
   // 一個(gè)symbol定義代表一個(gè)圖標(biāo)
   <symbol id="local-vue"></symbol>
   <symbol id="local-logo"></symbol>
   ...
</svg>
/* 然后就可以在組件中實(shí)例化使用 */
<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,返回一個(gè)包含“指定目錄下所有文件名稱”的數(shù)組對(duì)象
  // [ 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表示的是一個(gè)目錄則返回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}"`;
          }
          // 去掉擴(kuò)展名
          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;
  // 每個(gè)圖標(biāo)都是symbol標(biāo)簽,去掉了svg標(biāo)簽,只包含的svg內(nèi)部嵌套標(biāo)簽,res是一個(gè)數(shù)組,每個(gè)元素就是一個(gè)圖標(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" 
        >
        ${res.join('')}
        </svg>
        `
      );
      /* eslint-enable */
    },
  };
};

獲取所有本地圖標(biāo)名稱通過定義id,由于封裝插件的時(shí)候已經(jīng)定義了元素id="local-icon",所以可以全局定義獲取。下面獲取到的svgEl值如圖所示。

buildAdmin開源項(xiàng)目引入四種圖標(biāo)方式是什么

export function getLocalIconfontNames() {
  return new Promise<string[]>((resolve, reject) => {
    nextTick(() => {
      let iconfonts: string[] = [];
      const svgEl = document.getElementById('local-icon');
      // 判斷DOMStringMap對(duì)象內(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開源項(xiàng)目引入四種圖標(biāo)方式是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI