Skip to content
    在 Opshell 的 Blog 中:
  • 目前已分享 70 篇文章
  • 還有 114 個坑正在填補中
  • 已有: Loading 次觀看
  • 已有: Loading 個人來過
✍️ Opshell
📆 Last Updated:8/23/2024Created:2022/09/29
👀 已被閱讀: Loading

[Day29]:喜歡的都裝一起 - svg sprite

Day 28 Banner

喜歡的都裝在一起

我才不要別人喜歡的我要自己喜歡的───────────────── By Opshell


目標: vite-plugin-svg-icons

因為想要隨時可以增減icon, 然後挑自己喜歡的Icon來用, 所以原先在Vue_clil的時候有使用svg-sprite-loader, 但svg-sprite-loader是基於webpack打包的, 現在換到Vite我們需要換一套:


過程:

  • 安裝 & 設定

  • 1. 安裝

     yarn add vite-plugin-svg-icons -D

  • 2. 設定

    修改vite.comfig.ts

    typescript
     // vite.comfig.ts
     import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
    
     export default () => {
       return {
          plugins: [
             createSvgIconsPlugin({
                iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], // 指定需要占存的Icon目錄
                symbolId: '[name]', // 指定symbolId格式 預設:'icon-[dir]-[name]
    
                inject: 'body-last', // | 'body-first' sprite插入位置
                customDomId: '__svg__icons__dom__', // 自訂 Dom ID
             }),
    
     //... 以下省略

  • 3. src/main.ts

    src/main.ts內引用:

    typescript
     // src/main.ts
     import 'virtual:svg-icons-register';

  • 4. tsconfig.json

    用Typescript,還需要在tsconfig.json内新增:

    typescript
     // tsconfig.json
     {
       "compilerOptions": {
          "types": ["vite-plugin-svg-icons/client"]
       }
     }

  • 基本使用

  • 1. 新增

    把要用的svg都丟到src/assets/icon

  • 2. 使用

    src/components裡新增 el-svgIcon.vue 這個部分不太需要改什麼,使用方式沒啥區別, 畢竟原理一樣

    vue
     <div v-if="href == ''" class="icon">
         <svg class="svg">
             <use :xlink:href="`#${name}`" />
         </svg>
     </div>

  • 番外

  • 1. 在src/views裡新增 IconList.vue

    做一個icon列表,圖像化的方式, 之後後台使用更方便,原碼:

    javascript
     // IconList.vue(Javascript)
     import { onMounted, ref } from "vue";
     import { useStore } from "vuex";
    
     import elSvgIcon from "../components/el-svgIcon.vue";
    
     export default {
         components: { elSvgIcon },
         setup() {
             const store = useStore();
             const states = useState(["userData"]);
             const iconList = ref([]);
    
             onMounted(() => {
                 iconList.value = [];
    
                 let spriteSvg = [...document.getElementById('__SVG_SPRITE_NODE__').children];
                 spriteSvg.forEach(svgDom => {
                     iconList.value.push(svgDom.id);
                 });
             });
    
             store.commit('endLoading');
    
             return {
                 ...states,
                 iconList
             };
         },
     };

    Script 標籤改成這樣<script setup lang="ts"> 並且修改下面這些部分:

    typescript
     import { useStore } from '@/store';
     import { Ref } from '@vue/reactivity'; // Ref的型別
    
     const store = useStore();
     const iconList: Ref<string[]> = ref([]);
    
     onMounted(() => {
         const spriteSvg = document.getElementById('__svg__icons__dom__');
    
         if (spriteSvg != null) {
             let svgList = Array.from(spriteSvg.children); // 2488
    
             svgList.forEach((svgDom) => {
                 iconList.value.push(svgDom.id);
             });
         }
     });
    
     store.commit('route/endLoading');

    這次的改寫過程遇到了好多問題:

    1. Ref型別:

    這個還行,看官方文件就可以解決了。

    1. 型別檢測:

    用型別檢測做個導流。

    1. Array-like轉換:

    錯誤代碼(TS2488), 這個實在很奇怪,理論上來說Array.from(spriteSvg.children) 等價於[...spriteSvg.children] 但是就是會報錯,打死解不開,求有解的大大解惑。 alt

    1. iconList在Tamplate中型別錯誤

    這個錯誤也是很奇怪,各種寫法都一樣的結果, 猜測是莫名地抓不到暴露的vue,但是該有的設定都跑了, 也查不到相關的錯誤,雖然能成功執行就是了。 alt

    ※ 3和4的錯誤一直沒有其他想法, 不過編譯的時候根本不會報錯, Ops甚至覺得根本是Error Len在亂叫, 期待有大大解惑,或者哪天我懂了再回來改文章。


小結:

這邊遇到了好多神奇的問題, 雖然大部分都沒有解開, 只是找了個方法繞過去, 但過程中學到了很多東西, 也算是獲益良多。

Released under the MIT License.