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/vàjs/. - SVG: Icon vector phân loại theo
brands,regular,solidtrong thư mụcsvgs/. - Web Fonts: Font icon dạng
.woff2trong thư mụcwebfonts/.
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-fwhoặc điều chỉnh CSS tùy ý.