第二集: 從零開始實現一套pc端vue的ui組件庫(icon組件)

第二集: 從零開始實現(icon組件)

本集定位:
這套ui組件我原本是先從button作的, 可是我發現每一個組件都要用到icon這個組件, 若是沒有他, 不少組件無法擴展, 並且icon自己不依賴其餘組件, 因此仍是先把它做爲本篇文章的重點吧.
icon組件
讀過element-ui源碼的同窗都知道, 他們選擇的是字體圖標的方式來作icon組件的, 而個人這套ui在寫法與用法上參考了他們的作法, 但組件自己是靠svg來書寫的,其中的區別仍是簡單闡述一下把.
icon font 與 svgcss

  • 1.icon font作爲字體沒法支持多色圖形,這就很尷尬了.
  • 2.icon font主要在頁面用Unicode符號調用對應的圖標,這種方式不論是瀏覽器,搜索引擎和對無障礙方面的能力都沒有SVG好.
  • 3.icon font採用的是字體渲染,icon font在一倍屏幕下渲染效果並很差,在細節部分鋸齒仍是很明顯的,SVG上面我說過它是圖形因此在瀏覽器中使用的是圖形渲染,因此SVG卻沒有這種問題.
  • 4.兼容性較差,支持 ie9+,及現代瀏覽器.
  • 5.瀏覽器渲染svg的性能通常,還不如png。

行動起來
上一集基本環境已經搭建好了, 這裏咱們採用'bem'的思想, 來構建組件的樣式, 全部的樣式抽離在一個文件夾裏面, 作到組件自己沒有樣式代碼,咱們來先書寫組件的代碼.結構以下:
圖片描述html

index.js文件裏面是導出這個組件:vue

import Icon from './main/icon.vue'
// 明白vue.use方法原理的同窗都能明白這段代碼的意義
// 當被use的時候, 進行icon組件的渲染
Icon.install = function(Vue) {
  Vue.component(Icon.name, Icon);
};

export default Icon

這樣單抽出來作一個文件的好處是,更好的工程化, 保證職能的單一性.git

main文件夾
爲何main文件夾裏面只有一個文件還要單獨抽成一個文件夾??, 緣由是有的組件可能要配合本身獨有的容器組件一塊兒使用, 好比一個button的包裹容器, 他可讓內部的每一個button有相同的上下左右距離, 相同的圓角等等...github

icon.vue文件面試

  • 第一步: 使用svg, 固然要去下載svg圖片了, 本篇推薦使用你們都在用的阿里巴巴矢量圖標庫,選擇本身喜歡的圖標放入購物車選項.

圖片描述

  • 第二步: 放入工程,點擊添加入項目, 若是沒有項目要點擊新建項目來完成此操做.

圖片描述

  • 第三步: 複製連接到你的script標籤裏面引入, 在index.html裏面就能夠, 下面會講遇到的問題與優化.

圖片描述

// 使用方法以下:
<svg class="icon">
// 把名字寫在下面的'xxx'處,就能夠正常顯示圖標了;
    <use xlink:href="#icon-xxx"></use>
</svg>
  • 第四步: 開始正式書寫組件.npm

    • 1:先定義一個最簡單的組件模板, 他僅僅支持顏色的調整, 與icon的調整
    • 2:svg的顏色控制, 須要經過fill屬性, 我常常面試遇到說本身用過svg圖片, 可是沒據說過fill屬性的尷尬場面😅
    • 3:不傳顏色的時候,svg默認是原色
<template>
  <div 
    class='cc-icon'
    }">
    <svg :style="{fill:color}">
      <use :xlink:href='`#icon-${name}`'></use>
    </svg>
  </div>
</template>
<script>
export default {
name: "ccIcon",
  props: {
    color: String,
    name: {
      type: String,
      required: true
    }
  }
};
</script>
  • 第五步: 基本的結構已經有了, 如今要考慮的就是咱們的組件還須要什麼功能? .
  • 1:控制圖標的大小, 這個仍是須要的
props: {// 接受一個size屬性
    size: { // 由於用戶可能傳帶單位的與不帶單位的
      type: [Number, String],
      default: "1em"
    }
  },
computed: { // 計算屬性裏面對這個值進行操做, 類型若是是數字, 就咱們來給他加上單位吧,也就是默認單位是'px'
    iconSize() {
      if (typeof this.size === "number") return this.size + "px";
      else return this.size;
    }
  }
<template>
  <div 
    class='cc-icon'
    height: iconSize, // 在此使用
    width: iconSize,  // 在此使用
    }">
    <svg :style="{fill:color}">
      <use :xlink:href='`#icon-${name}`'></use>
    </svg>
  </div>
</template>
  • 2:若是是加載的icon, 咱們須要讓他旋轉一下, 這裏我是這麼作的, 全部的加載圖標, 個人命名都是load加數字, 因此檢測字符串裏面是否有這個關鍵詞就行了
<svg :style="{fill:color}"
         :class="[
          'cc-icon-'+name,
          {  
          //icon-loading這個class名, 只有在icon的name屬性裏面有load字段的時候加上, 這個屬性名裏面的屬性就是旋轉.'~'位運算符是很高效的書寫方式, 也就是對位求反,1變0,0變1,也就是求二進制的反碼, 這裏不懂的話, 先看犀牛書, 簡單的說就是把-1轉成0了, 變成了布爾中的false;
            'icon-loading':~name.indexOf('load')
          }
         ]">
      <use :xlink:href='`#icon-${name}`'></use>
    </svg>
  • 3:實際使用的時候我發現, 不給div加上 display: 'inline-flex',屬性, icon有時候對不整齊, 因此仍是加上爲妙,這個地方之後應該還會弄一弄, 感受還會有一段故事.
<div 
    class='cc-icon'
    :style="{
    display: 'inline-flex',
    height: iconSize,
    width: iconSize,
    }">
  • 4: 接下來就是爲了配合其餘組件的 disabled 狀態 把圖標自己也置爲灰色, 這樣寫很方便
<svg :style="{fill:color}"
         :class="[
          'cc-icon-'+name,
          { 
            'icon-loading':~name.indexOf('load'),
            'is-disabled':disabled // 在這裏進行了定義
          }
         ]">
      <use :xlink:href='`#icon-${name}`'></use>
    </svg>
     props: {
    disabled: Boolean // 固然是布爾類型
  },

小知識點: props裏面定義了默認類型是布爾,則用戶能夠直接在標籤上寫屬性名, 不給屬性值也是能夠表明true的, 可是默認不是布爾, 不給屬性值的話, 組件裏面獲得的就是undefined;element-ui

  • 第六步: 書寫樣式吧

圖片描述

icon.scss文件
1:disabled狀態時禁止點擊
2:icon-loading 時旋轉
@import './common/mixin.scss';
@import "./common/animation.scss";

@include b(icon) {
    .#{$state-prefix}disabled {
        cursor: not-allowed;
        fill: $--color-disabled;
    }
    .icon-loading {
        animation: rotating 1s infinite linear;
    }
}

mixin.scss文件裏面的b方法瀏覽器

抽象出$namespace方便管理
@mixin b($block) {
    $B: $namespace+'-'+$block !global;
    .#{$B} {
        @content;
    }
}

animation.scss文件svg

@keyframes rotating {
    0% {
      transform: rotateZ(0deg);
    }
    100% {
      transform: rotateZ(360deg);
    }
  }

var.scss文件

// lulu的美工很差, 只是想作出點不一樣樣子的東西玩玩
// 基本色
$--color-black:#000000 !default;
$--color-white:#FFFFFF !default;
// 基本色鮮豔
$--color-nomal:#409EFF !default;
$--color-success:#7CCD7C !default;
$--color-warning:#FFB90F !default;
$--color-danger: #FF0000 !default;
$--color-disabled: #bbbbbb !default;
$--color-difference: #F5F7FA !default;
// 字體
$--size-big: 16px;
$--size-nomal: 15px;
$--size-small: 14px;
// 輸入框
$--color-input-placeholder:#aaa
  • 第六步: 上面說的svg文件引用的改良, 能夠把svg文件下載到本地, 在別人由於這個ui組件的時候不會引用index.html文件, 並且大部分組件都引用了icon,咱們能夠去阿里巴巴矢量圖標庫進行操做

點擊下載到本地
圖片描述
取出js文件, 讓在本地
圖片描述

用index.js文件引用這個js文件就完成了!!

結束
icon組件是最小的組件, 其餘組件的代碼量與難道都大的多, 詳細code與用法能夠訪問下面的地址, npm同步更新!
下一期是關於button的,咱們一塊兒交流吧

github:項目地址
我的博客:我的博客

相關文章
相關標籤/搜索