Cách tích hợp Font Awesome vào Vue 3 với Composition API

Việc quản lý icon trong dự án Vue 3 thường gây phiền toái: thư viện cồng kềnh, logic rối rắm, hiệu năng kém. Bài viết này hướng dẫn bạn xây dựng hệ thống icon gọn nhẹ bằng Font Awesome kết hợp Composition API — từ tích hợp đến tối ưu hiệu suất.

Cấu trúc Font Awesome cơ bản

Font Awesome v7 cung cấp nhiều định dạng icon: SVG, font chữ và CSS. Các thành phần chính gồm:

  • CSS/JS: Tệp kiểu dáng và script nằm trong thư mục css/js/.
  • SVG: Icon vector phân loại theo brands, regular, solid trong thư mục svgs/.
  • Web Fonts: Font icon dạng .woff2 trong thư mục webfonts/.

Tích hợp nhanh chóng

Dùng CDN (cho prototype)

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6/css/all.min.css">

Dùng NPM (cho production)

npm install @fortawesome/fontawesome-free

Sau đó import từng phần cần thiết để giảm kích thước bundle.

Thiết kế component icon với Composition API

Tạo component Icon.vue linh hoạt:

<template>
  <span :class="computedClasses" :style="computedStyles"></span>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  name: String,
  scale: { type: [String, Number], default: 1 },
  tint: { type: String, default: 'inherit' }
});

const computedClasses = computed(() => [
  'fa',
  `fa-${props.name}`
]);

const computedStyles = computed(() => ({
  fontSize: typeof props.scale === 'number' ? `${props.scale}em` : props.scale,
  color: props.tint
}));
</script>

Sử dụng:

<Icon name="vuejs" scale="1.5" tint="#42b883" />

Logic nâng cao với Composable

Tạo hook useSwitchableIcon.js:

export function useSwitchableIcon(defaultState = false, icons = { active: 'check', inactive: 'times' }) {
  const isActive = ref(defaultState);
  
  const currentIcon = computed(() => isActive.value ? icons.active : icons.inactive);
  
  const switchState = () => {
    isActive.value = !isActive.value;
  };
  
  return { isActive, currentIcon, switchState };
}

Sử dụng trong component:

<template>
  <button @click="switchState">
    <Icon :name="currentIcon" />
  </button>
</template>

<script setup>
import { useSwitchableIcon } from '@/composables/useSwitchableIcon';

const { currentIcon, switchState } = useSwitchableIcon(false, {
  active: 'check-circle',
  inactive: 'circle'
});
</script>

Icon thích ứng với màn hình và theme

Phản hồi theo kích thước cửa sổ:

import { useWindowSize } from '@vueuse/core';
import { computed } from 'vue';

const { width } = useWindowSize();

const sizeClass = computed(() => {
  if (width.value < 768) return 'fa-sm';
  if (width.value < 1280) return 'fa-lg';
  return 'fa-xl';
});

Chuyển đổi theme toàn cục:

// composable/useIconTheme.js
import { provide, inject, ref } from 'vue';

const THEME_KEY = Symbol('iconTheme');

export function createIconTheme() {
  const mode = ref('light');
  const toggleMode = () => mode.value = mode.value === 'light' ? 'dark' : 'light';
  provide(THEME_KEY, { mode, toggleMode });
  return { mode, toggleMode };
}

export function useIconTheme() {
  return inject(THEME_KEY);
}

Tối ưu hiệu năng

Chỉ import icon cần dùng:

import { faVuejs } from '@fortawesome/free-brands-svg-icons/faVuejs';

Preload icon thường dùng:

import { library } from '@fortawesome/fontawesome-svg-core';
import { faVuejs, faGithub } from '@fortawesome/free-brands-svg-icons';

library.add(faVuejs, faGithub); // Dùng sau này không cần import lại

Cấu trúc dự án đề xuất

src/
├── components/
│   └── ui/
│       └── Icon.vue
├── composables/
│   ├── useIcon.js
│   └── useIconTheme.js
└── plugins/
    └── icons.js

Xử lý lỗi thường gặp

  • Icon không hiển thị: Kiểm tra tên icon trong tài liệu chính thức hoặc file icons.yml.
  • Bundle quá lớn: Dùng webpack-bundle-analyzer để phát hiện icon không dùng đến.
  • Canh hàng lệch: Thêm class fa-fw hoặc điều chỉnh CSS tùy ý.

Thẻ: Vue3 fontawesome composition-api

Đăng vào ngày 8 tháng 6 lúc 17:30