AnitimeJS là một thư viện JavaScript/TypeScript nhẹ và linh hoạt giúp xử lý thời gian, số liệu, và nhiều tác vụ tiện ích khác trong các dự án web của bạn.
Thư viện được tạo ra nhằm tối ưu hóa việc sử dụng số và thời gian. Chúc mọi người thành công!
- Lightweight: Thư viện nhỏ gọn, tối ưu hóa hiệu suất cho ứng dụng của bạn
- Flexible & composable: Các hàm có thể kết hợp với nhau để thực hiện các tác vụ phức tạp
- Accessible: Tuân thủ các tiêu chuẩn mã nguồn mở và dễ dàng tích hợp vào bất kỳ dự án nào
$ yarn add anitimejs
# hoặc
$ npm install --save anitimejs
import { anitimejs, anitimejsGlobalConfig, useTimer } from "anitimejs";
// Khởi tạo với ngày hiện tại
const today = anitimejs();
// Khởi tạo với ngày cụ thể
const birthday = anitimejs("15/04/2025");
// Định dạng thời gian
console.log(birthday.format("DD/MM/YYYY")); // "15/04/2025"
// Lấy danh sách ngày lễ trong năm
console.log(today.getHolidays());
// Chuyển đổi từ ngày âm lịch sang ngày dương lịch
console.log(today.getHolidays());
// Lấy danh sách âm lịch theo khoảng thời gian
const timeRange = anitimejs("01/01/2023", "31/12/2023");
console.log(timeRange.toLunarDateRange());
// Chuyển đổi 1 ngày dương lịch sang âm lịch
console.log(today.toLunarDate());
Lớp Time
là trung tâm của thư viện AnitimeJS, cung cấp nhiều phương thức để làm việc với thời gian.
// Khởi tạo với ngày hiện tại
const time = anitimejs();
// Khởi tạo với ngày cụ thể (các định dạng được hỗ trợ)
const time1 = anitimejs("25/12/2023");
const time2 = anitimejs("2023-12-25");
const time3 = anitimejs("25/12/2023 14:30:00");
const time4 = anitimejs(new Date(2023, 11, 25));
// Khởi tạo với ngày bắt đầu và ngày kết thúc
const timeRange = anitimejs("01/01/2023", "31/12/2023");
const date = anitimejs("15/04/2025");
// Định dạng cơ bản
date.format("DD/MM/YYYY"); // "15/04/2025"
date.format("YYYY-MM-DD"); // "2025-04-15"
date.format("DD/MM/YYYY HH:mm:ss"); // "15/04/2025 00:00:00"
// Định dạng với ngôn ngữ
date.lang("vi").format("L, DD eM tY YYYY"); // "Thứ ba, 15 tháng 04 năm 2025"
date.lang("en").format("L, DD eM YYYY"); // "Tuesday, 15 April 2025"
// Định dạng nhanh
date.format("L"); // "Thứ ba, 15 tháng 04 năm 2025"
date.format("LL"); // "Thứ ba, 15 tháng 04 năm 2025 lúc 00:00"
date.format("F"); // Định dạng thông minh tùy theo khoảng thời gian
const date = anitimejs("15/04/2025");
// Thêm thời gian
date.add(1, "days").format("DD/MM/YYYY"); // "16/04/2025"
date.add(2, "months").format("DD/MM/YYYY"); // "16/06/2025"
date.add(1, "years").format("DD/MM/YYYY"); // "16/06/2026"
// Bớt thời gian
date.subtract(1, "days").format("DD/MM/YYYY"); // "15/06/2026"
date.subtract(2, "hours").format("DD/MM/YYYY HH:mm"); // "15/06/2026 22:00"
const date = anitimejs("15/04/2025");
// Lấy thông tin cơ bản
date.getDay(); // 15
date.getMonth(); // 4
date.getYear(); // 2025
date.getHours(); // 0
date.getMinutes(); // 0
date.getWeekOfYear(); // 16
// Lấy thông tin về tuần
date.getDayInWeek(); // 2 (0: CN, 1: T2, 2: T3, ...)
date.getWeek(); // Mảng các ngày trong tuần
// Lấy ngày kế tiếp/trước đó
const nextDay = date.getNextDay(); // 16/04/2025
const prevDay = date.getPreviousDay(); // 14/04/2025
// Cấu hình cho một đối tượng
const date = anitimejs().setTimeZone("America/New_York").lang("en");
// Cấu hình toàn cục
anitimejsGlobalConfig({
locale: "en",
timezone: "Europe/London",
});
// Tính ngày làm việc trong khoảng thời gian
const workCalendar = anitimejs("01/04/2025", "30/04/2025").calculateWorkingDays(
[0, 6], // loại bỏ chủ nhật và thứ 7
["15/04/2025"] // loại bỏ ngày cố định. Mảng chứa các ngày lễ muốn loại bỏ, có thể ở dạng "DD/MM" hoặc "DD/MM/YYYY"
);
console.log(workCalendar.workingDays); // Mảng các ngày làm việc
console.log(workCalendar.holidaysExcluded); // Mảng các ngày nghỉ
// Đếm ngược
const countdown = anitimejs("31/12/2025 23:59:59").countdown();
console.log(countdown.days); // Số ngày
console.log(countdown.hours); // Số giờ
console.log(countdown.isPast); // false
const date = anitimejs("15/04/2025");
// Lấy thông tin về tháng
const monthDates = date.getMonthStartEndDates();
console.log(monthDates.startDate); // 01/04/2025
console.log(monthDates.endDate); // 30/04/2025
// Lấy tất cả ngày trong tháng
const daysInMonth = date.getDaysInMonth();
// [01/04/2025, 02/04/2025, ..., 30/04/2025]
// Lấy dữ liệu cho view calendar
const calendarView = date.getCalendars();
// Mảng 42 ngày bao gồm ngày trong tháng và ngày của tháng kề
// Lấy danh sách tháng và năm
const monthsYears = date.getMonthsAndYears(1, 12);
// [{month: 4, year: 2025}, {month: 5, year: 2025}, ...]
// Sắp xếp mảng các ngày
const dates = ["15/04/2025", "01/01/2025", "31/12/2025"];
anitimejs().arrangeTime(dates, "asc");
// ["01/01/2025", "15/04/2025", "31/12/2025"]
// Sắp xếp mảng object có chứa ngày
const events = [
{ id: 1, date: "15/04/2025", title: "Meeting" },
{ id: 2, date: "01/01/2025", title: "New Year" },
{ id: 3, date: "31/12/2025", title: "Party" },
];
anitimejs().arrangeTimeObject(events, "desc", "date");
// Kết quả: events được sắp xếp theo date giảm dần
Hàm random
cung cấp nhiều cách để tạo dữ liệu ngẫu nhiên:
import { random } from "anitimejs";
// Random mật khẩu an toàn
const password = random({
length: 12,
includeUppercase: true,
includeLowercase: true,
includeNumbers: true,
includeSpecials: true,
exclude: ["I", "l", "1", "O", "0"], // Loại bỏ các ký tự dễ nhầm lẫn
});
// Random số điện thoại theo định dạng
const phoneNumber = random({
formatTemplate: "###-###-####",
includeNumbers: true,
prefix: "+84 ",
});
// Random các phần tử từ mảng theo phân phối chuẩn
const selections = random({
data: ["Red", "Green", "Blue", "Yellow", "Purple"],
length: 10,
distribution: "normal",
distributionParams: { mean: 2, stdDev: 1 },
});
// Random số chẵn từ 1 đến 100
const evenNumbers = random({
min: 1,
max: 100,
step: 2,
length: 5,
unique: true,
});
// Tạo UUID
const uuid = random({ type: "uuid" });
// Kết quả: "123e4567-e89b-12d3-a456-426614174000"
// Tạo UUID không có dấu gạch ngang
const compactUuid = random({
type: "uuid",
uuidOptions: { dashes: false },
});
// Kết quả: "123e4567e89b12d3a456426614174000"
// Tạo mã màu HEX
const hexColor = random({ type: "color" });
// Kết quả: "#a1b2c3"
// Tạo mã màu RGBA
const rgbaColor = random({
type: "color",
colorOptions: { alpha: true, format: "rgb" },
});
// Kết quả: "rgba(161, 178, 195, 0.75)"
// Tạo tên tệp ngẫu nhiên
const filename = random({
type: "filename",
prefix: "IMG_",
filenameOptions: {
extension: "jpg",
includeTimestamp: true,
},
});
// Kết quả: "IMG_1681546325896-a1b2c3d4.jpg"
Hàm numbers
giúp xử lý và định dạng số:
import { numbers } from "anitimejs";
// Chuyển đổi từ string
numbers("123456"); // 123456
numbers("100.000", { parseOptions: { format: "eu" } }); // 100000
// Định dạng số với dấu phân cách
numbers(1234567, { separator: "." }); // "1.234.567"
numbers(1234567, { separator: ".", decimals: 2 }); // "1.234.567,00"
// Làm tròn và số thập phân
numbers(123.456, { decimals: 2 }); // "123.46"
numbers(123.456, { decimals: 2, rounding: "floor" }); // "123.45"
// Định dạng tiền tệ
numbers(1234.56, { currency: "$", currencyPosition: "prefix" }); // "$1234.56"
numbers(1234.56, {
currency: "đ",
currencyPosition: "suffix",
separator: ".",
}); // "1.234.56đ"
// Chuyển đổi sang chữ
numbers(1234.56, { toWords: true });
// "Một nghìn hai trăm ba mươi bốn phẩy năm sáu"
// Định dạng ngắn gọn
numbers(1234567, { compact: true }); // "1.2M"
Hook useTimer
là giải pháp toàn diện cho việc quản lý thời gian trong ứng dụng React. Hook này cung cấp nhiều tùy chọn linh hoạt và chức năng hữu ích cho việc tạo đồng hồ đếm ngược, đồng hồ bấm giờ, hoặc bất kỳ ứng dụng thời gian nào khác.
- 🕒 Đa chức năng: Hỗ trợ đếm tiến, đếm lùi và đồng hồ hiển thị thời gian thực
- ⚡ Hiệu suất tối ưu: Sử dụng hooks và refs để giảm thiểu render không cần thiết
- 🔄 Tự động cập nhật: Theo dõi nhiều trạng thái thời gian khác nhau
- 🛠️ Tùy biến cao: Nhiều tùy chọn và callback để điều chỉnh theo nhu cầu
interface UseTimerOptions {
initialStartTime?: number; // Thời điểm bắt đầu ban đầu (timestamp, mặc định: Date.now())
autoStart?: boolean; // Tự động bắt đầu timer khi khởi tạo (mặc định: false)
interval?: number; // Khoảng thời gian cập nhật (ms, mặc định: 1000ms)
onTick?: (time: TimerState) => void; // Callback khi timer tick
}
interface UseTimerReturn {
// Trạng thái
elapsedTime: number; // Thời gian đã trôi qua (giây)
offsetTime: number; // Thời điểm hiện tại (giây tính từ epoch)
timeDifference: number; // Chênh lệch thời gian từ lúc bắt đầu (giây)
isRunning: boolean; // Trạng thái đang chạy
startedAt: number | null; // Thời điểm bắt đầu gần nhất
pausedAt: number | null; // Thời điểm tạm dừng gần nhất
// Phương thức
start: () => void; // Bắt đầu timer
stop: () => void; // Dừng timer
reset: (startImmediately?: boolean) => void; // Reset timer
setTime: (newTime: number) => void; // Đặt thời gian mới
toggle: () => void; // Chuyển đổi trạng thái timer
formatTime: (format?: string) => string; // Format thời gian dạng chuỗi
}
import { useTimer } from "anitimejs";
import { useEffect } from "react";
function CountdownComponent() {
const { elapsedTime, isRunning, start, stop, reset, formatTime } = useTimer({
autoStart: true,
interval: 1000,
});
// Giả sử đếm ngược từ 60 giây
const remainingTime = Math.max(0, 60 - elapsedTime);
useEffect(() => {
if (remainingTime === 0 && isRunning) {
stop();
alert("Hết giờ!");
}
}, [remainingTime, isRunning, stop]);
return (
<div>
<div>Thời gian còn lại: {remainingTime} giây</div>
<div>Định dạng: {formatTime("MM:SS")}</div>
<button onClick={isRunning ? stop : start}>
{isRunning ? "Tạm dừng" : "Tiếp tục"}
</button>
<button onClick={() => reset(true)}>Bắt đầu lại</button>
</div>
);
}
import { useTimer } from "anitimejs";
import { useState } from "react";
function StopwatchComponent() {
const [laps, setLaps] = useState([]);
const { elapsedTime, isRunning, start, stop, reset, formatTime } = useTimer({
interval: 100, // Cập nhật mỗi 100ms để hiển thị chính xác hơn
onTick: (time) => {
// Có thể xử lý logic phức tạp tại đây
},
});
const handleLap = () => {
if (isRunning) {
setLaps([...laps, elapsedTime]);
}
};
return (
<div>
<div className="stopwatch">{formatTime("HH:MM:SS")}</div>
<div className="controls">
<button onClick={isRunning ? stop : start}>
{isRunning ? "Dừng" : "Bắt đầu"}
</button>
<button onClick={handleLap} disabled={!isRunning}>
Vòng
</button>
<button
onClick={() => {
reset();
setLaps([]);
}}
>
Đặt lại
</button>
</div>
<div className="laps">
<h3>Các vòng</h3>
<ul>
{laps.map((lap, index) => (
<li key={index}>
Vòng {index + 1}: {Math.floor(lap / 60)}:
{(lap % 60).toString().padStart(2, "0")}
</li>
))}
</ul>
</div>
</div>
);
}
import { useTimer } from "anitimejs";
import { useEffect } from "react";
function RealTimeClock() {
const { offsetTime, start, formatTime } = useTimer({
autoStart: true,
interval: 1000,
});
// Tạo các định dạng thời gian khác nhau
const getTimeFormats = () => {
const date = new Date(offsetTime * 1000);
return {
standard: formatTime("HH:MM:SS"),
date: date.toLocaleDateString(),
time: date.toLocaleTimeString(),
iso: date.toISOString(),
};
};
const formats = getTimeFormats();
return (
<div className="clock-container">
<h2>Đồng hồ thời gian thực</h2>
<div className="time-display">
<div>Định dạng tiêu chuẩn: {formats.standard}</div>
<div>Ngày: {formats.date}</div>
<div>Giờ địa phương: {formats.time}</div>
<div>ISO: {formats.iso}</div>
</div>
</div>
);
}
sortArray
là một hàm tiện ích mạnh mẽ để sắp xếp các mảng với nhiều tùy chọn linh hoạt. Hàm này giúp đơn giản hóa quá trình sắp xếp dữ liệu phức tạp trong các ứng dụng JavaScript hoặc React.
- 🔄 Sắp xếp linh hoạt: Hỗ trợ tất cả các kiểu dữ liệu JavaScript phổ biến
- 🌳 Sắp xếp đa cấp: Xử lý được cả thuộc tính lồng nhau và mảng con
- 🧰 Nhiều tùy biến: Cho phép định nghĩa vị trí của giá trị null, thứ tự sắp xếp và hàm so sánh tùy chỉnh
- 🛡️ An toàn: Xử lý các trường hợp đặc biệt và tránh các lỗi phổ biến
type SortOrder = "asc" | "desc";
interface SortOptions<T = any> {
key?: string; // Key để sắp xếp (cho object cấp cao nhất)
order?: SortOrder; // "asc" hoặc "desc" (mặc định là "asc")
deepKeys?: {
// Thông tin mảng con cần xử lý
deepKey: string;
sortKey?: string;
order?: SortOrder;
}[];
customCompare?: (a: any, b: any) => number; // Hàm so sánh tùy chỉnh
nullsPosition?: "first" | "last"; // Vị trí của giá trị null/undefined (mặc định: 'last')
}
function sortArray<T = any>(array: T[], options?: SortOptions<T>): T[];
import { sortArray } from "anitimejs";
// Sắp xếp mảng số
sortArray([3, 1, 4, 2], { order: "asc" });
// Kết quả: [1, 2, 3, 4]
// Sắp xếp mảng chuỗi
sortArray(["banana", "apple", "cherry", "date"], { order: "desc" });
// Kết quả: ['date', 'cherry', 'banana', 'apple']
// Sắp xếp mảng ngày tháng
const dates = [
new Date("2023-05-15"),
new Date("2023-01-10"),
new Date("2023-12-25"),
];
sortArray(dates);
// Kết quả: [Date('2023-01-10'), Date('2023-05-15'), Date('2023-12-25')]
import { sortArray } from "anitimejs";
// Mảng người dùng
const users = [
{ name: "Alice", age: 30, active: true },
{ name: "Bob", age: 25, active: false },
{ name: "Charlie", age: 35, active: true },
{ name: "Dave", age: null, active: true },
];
// Sắp xếp theo tuổi (tăng dần)
sortArray(users, { key: "age" });
// Kết quả: [Bob, Alice, Charlie, Dave] (null ở cuối)
// Sắp xếp theo tuổi (giảm dần) với null ở đầu
sortArray(users, {
key: "age",
order: "desc",
nullsPosition: "first",
});
// Kết quả: [Dave, Charlie, Alice, Bob]
// Sắp xếp theo tên và xử lý giá trị active
sortArray(users, {
key: "name",
customCompare: (a, b) => {
// So sánh active trước, sau đó đến tên
if (a.active === b.active) {
return a.name.localeCompare(b.name);
}
return a.active ? -1 : 1; // Active lên đầu
},
});
// Kết quả: [Alice, Charlie, Dave, Bob]
import { sortArray } from "anitimejs";
// Danh sách sản phẩm theo danh mục
const inventory = [
{
category: "Điện tử",
items: [
{ name: "Laptop", price: 1200, stock: 5 },
{ name: "Điện thoại", price: 800, stock: 10 },
{ name: "Tai nghe", price: 100, stock: 15 },
],
},
{
category: "Thời trang",
items: [
{ name: "Áo phông", price: 20, stock: 50 },
{ name: "Quần jean", price: 50, stock: 30 },
{ name: "Giày", price: 80, stock: 25 },
],
},
];
// Sắp xếp danh mục và sắp xếp sản phẩm theo giá trong mỗi danh mục
const sortedInventory = sortArray(inventory, {
key: "category",
order: "asc",
deepKeys: [
{
deepKey: "items",
sortKey: "price",
order: "desc",
},
],
});
// Kết quả:
// [
// {
// category: "Điện tử",
// items: [
// { name: "Laptop", price: 1200, stock: 5 },
// { name: "Điện thoại", price: 800, stock: 10 },
// { name: "Tai nghe", price: 100, stock: 15 }
// ]
// },
// {
// category: "Thời trang",
// items: [
// { name: "Giày", price: 80, stock: 25 },
// { name: "Quần jean", price: 50, stock: 30 },
// { name: "Áo phông", price: 20, stock: 50 }
// ]
// }
// ]
import { sortArray } from "anitimejs";
// Dữ liệu sản phẩm với chi tiết lồng nhau
const products = [
{ id: 1, details: { price: 200, stock: { warehouse: 10, store: 5 } } },
{ id: 2, details: { price: 100, stock: { warehouse: 5, store: 15 } } },
{ id: 3, details: { price: 300, stock: { warehouse: 2, store: 0 } } },
];
// Tạo hàm truy cập thuộc tính lồng nhau
function getNestedValue(obj, path) {
return path
.split(".")
.reduce((o, p) => (o && o[p] !== undefined ? o[p] : null), obj);
}
// Sắp xếp theo giá (đường dẫn lồng nhau)
const sortedByPrice = sortArray(products, {
customCompare: (a, b) => {
const priceA = getNestedValue(a, "details.price");
const priceB = getNestedValue(b, "details.price");
return priceA - priceB;
},
});
// Kết quả: [{ id: 2, ... }, { id: 1, ... }, { id: 3, ... }]
// Sắp xếp theo tổng kho hàng
const sortedByTotalStock = sortArray(products, {
customCompare: (a, b) => {
const stockA = getNestedValue(a, "details.stock");
const stockB = getNestedValue(b, "details.stock");
const totalA = stockA ? stockA.warehouse + stockA.store : 0;
const totalB = stockB ? stockB.warehouse + stockB.store : 0;
return totalB - totalA; // Giảm dần
},
});
// Kết quả: [{ id: 2, ... }, { id: 1, ... }, { id: 3, ... }]
Hàm RegexHelper
cung cấp các tiện ích xử lý chuỗi, validate và mã hóa:
import { RegexHelper } from "your-library-name";
// Validate email
RegexHelper.validate("email", "example@gmail.com"); // true
RegexHelper.validate("email", "invalid-email"); // false
// Validate mật khẩu với tùy chọn
RegexHelper.validate("password", "P@ssw0rd123", {
minLength: 10,
requireSpecial: true,
}); // true
// Ẩn thông tin email
RegexHelper.mask("email", "nhantgn123@gmail.com");
// Kết quả: n**********@***.com
// Ẩn số điện thoại
RegexHelper.mask("phone", "0912345678", 3);
// Kết quả: 091****678
// Loại bỏ HTML
RegexHelper.process("stripHtml", "<p>Hello <strong>world</strong></p>");
// Kết quả: "Hello world"
// Trích xuất URLs từ văn bản
RegexHelper.process(
"extractUrls",
"Truy cập https://example.com và https://test.com"
);
// Kết quả: ["https://example.com", "https://test.com"]
// Phân tích URL
const urlInfo = RegexHelper.process(
"parseUrl",
"https://example.com/path?query=123#hash"
);
/* Kết quả:
{
protocol: "https:",
host: "example.com",
hostname: "example.com",
port: "",
pathname: "/path",
search: "?query=123",
hash: "#hash",
params: { query: "123" }
}
*/
// Băm chuỗi đơn giản
RegexHelper.crypto("hash", "Secret message");
// Kết quả: chuỗi băm
// Mã hóa đơn giản
const encrypted = RegexHelper.crypto("encrypt", "Secret message", "mykey");
// Kết quả: chuỗi đã mã hóa
// Giải mã
const original = RegexHelper.crypto("decrypt", encrypted, "mykey");
// Kết quả: "Secret message"
Hàm animate
cung cấp các hiệu ứng animation:
- 🚀 API trực quan, dễ sử dụng
- 🔄 Hỗ trợ Timeline để điều phối nhiều animation
- ⏱️ Stagger animations cho hiệu ứng tuần tự
- 🎢 Nhiều hàm easing và hiệu ứng physics
- 🎨 Hỗ trợ keyframes và màu sắc
- 📱 Hỗ trợ đầy đủ cho CSS, SVG và thuộc tính JavaScript
- 🎮 API điều khiển đầy đủ (play, pause, seek, reverse...)
import { animate } from "anitimejs";
// Animation đơn giản
animate({
targets: ".box",
props: {
translateX: ["0px", "200px"],
opacity: [0, 1],
},
duration: 1000,
easing: "easeOutQuad",
});
Timeline cho phép bạn điều phối nhiều animation theo thứ tự:
import { timeline } from "anitimejs";
const tl = timeline()
.add({
targets: ".circle",
props: { scale: [0, 1] },
duration: 500,
})
.add(
{
targets: ".square",
props: { rotate: ["0deg", "45deg"] },
duration: 600,
},
"+=200"
) // Thêm delay 200ms sau animation trước
.add(
{
targets: ".text",
props: { opacity: [0, 1] },
duration: 400,
},
"-=300"
); // Bắt đầu sớm hơn 300ms so với kết thúc animation trước
// Phát timeline
tl.play();
Tạo hiệu ứng chuyển động tuần tự cho nhiều phần tử:
import { animate, stagger } from "anitimejs";
animate({
targets: ".item",
props: {
translateY: ["-20px", "0px"],
opacity: [0, 1],
},
delay: stagger(100, { from: "center" }), // Phát từ phần tử giữa ra ngoài
duration: 600,
easing: "easeOutQuad",
});
Keyframes cho phép định nghĩa nhiều trạng thái chuyển tiếp:
animate({
targets: ".box",
props: {
translateX: {
"0%": "0px",
"25%": "100px",
"50%": "50px",
"100%": "200px",
},
rotate: ["0deg", "90deg", "45deg", "180deg"],
},
duration: 2000,
easing: "linear",
});
Tạo animation với vật lý lò xo tự nhiên:
import { physics } from "anitimejs";
physics({
targets: ".ball",
props: {
translateY: ["0px", "300px"],
},
duration: 800,
physics: {
mass: 1,
stiffness: 100,
damping: 10,
velocity: 0,
},
});
Thư viện cung cấp các hiệu ứng thông dụng:
import { effects } from "anitimejs";
// Hiệu ứng fade in
effects.fadeIn(".element", 500);
// Hiệu ứng slide in từ bên trái
effects.slideIn(".card", "left", "100%", 800);
// Hiệu ứng zoom
effects.zoom(".image", 0.5, 1, 1000);
// Hiệu ứng bounce
effects.bounce(".button", "20px", 800);
Hàm chính để tạo animation:
animate({
// Element(s) hoặc selector để áp dụng animation
targets: string | HTMLElement | HTMLElement[] | Record<string, any>,
// Các thuộc tính cần thay đổi
props: {
[property: string]: number | string | object
},
// Thời gian chạy (ms)
duration: number,
// Độ trễ trước khi bắt đầu (ms hoặc function)
delay?: number | ((el: any, i: number, total: number) => number),
// Độ trễ sau khi kết thúc (ms)
endDelay?: number,
// Hàm easing
easing?: ((t: number) => number) | keyof typeof easingFunctions,
// Làm tròn số
round?: number | boolean,
// Lặp lại
loop?: number | boolean,
// Hướng chạy animation
direction?: "normal" | "reverse" | "alternate" | "alternate-reverse",
// Callback khi animation cập nhật
update?: (currentState: any, progress: { completed: number, remaining: number }) => void,
// Callback khi animation bắt đầu
begin?: () => void,
// Callback khi animation kết thúc
complete?: () => void,
// Tự động phát
autoplay?: boolean
});
Tạo timeline để điều phối nhiều animation:
timeline({
// Tự động phát
autoplay?: boolean,
// Hướng chạy timeline
direction?: "normal" | "reverse" | "alternate" | "alternate-reverse",
// Lặp lại
loop?: number | boolean,
// Callback khi timeline cập nhật
update?: (progress: { completed: number, remaining: number }) => void,
// Callback khi timeline kết thúc
complete?: () => void
});
Các phương thức của Timeline:
-
add(animationConfig, timePosition)
: Thêm animation vào timeline -
play()
: Phát timeline -
pause()
: Tạm dừng timeline -
restart()
: Phát lại từ đầu -
seek(progress)
: Nhảy đến vị trí cụ thể (0-1) -
reverse()
: Đảo ngược hướng chạy
Tạo các độ trễ theo tuần tự:
stagger(value, {
// Độ trễ ban đầu
start?: number,
// Phần tử bắt đầu
from?: number | 'center' | 'edges' | 'first' | 'last',
// Hướng stagger
direction?: 'normal' | 'reverse',
// Lưới (rows, cols) cho stagger 2D
grid?: [rows: number, cols: number],
// Trục áp dụng với grid
axis?: 'x' | 'y',
// Easing cho phân phối độ trễ
easing?: (t: number) => number
});
Thư viện cung cấp nhiều hàm easing:
linear
-
easeInQuad
,easeOutQuad
,easeInOutQuad
-
easeInCubic
,easeOutCubic
,easeInOutCubic
-
easeInQuart
,easeOutQuart
,easeInOutQuart
-
easeInExpo
,easeOutExpo
,easeInOutExpo
-
easeInElastic
,easeOutElastic
,easeInOutElastic
-
easeInBounce
,easeOutBounce
,easeInOutBounce
spring
effects.fadeIn(targets, duration, options);
effects.fadeOut(targets, duration, options);
effects.slideIn(targets, direction, distance, duration, options);
effects.slideOut(targets, direction, distance, duration, options);
effects.zoom(targets, start, end, duration, options);
effects.pulse(targets, scale, duration, options);
effects.shake(targets, intensity, duration, options);
effects.flipIn(targets, axis, duration, options);
effects.bounce(targets, height, duration, options);
Hỗ trợ tất cả các thuộc tính transform CSS:
-
translateX
,translateY
,translateZ
-
rotate
,rotateX
,rotateY
,rotateZ
-
scale
,scaleX
,scaleY
,scaleZ
-
skew
,skewX
,skewY
Hàm tiện ích để tạo chuỗi transform:
import { createTransform } from "anitimejs";
const transformString = createTransform({
translateX: "100px",
rotate: "45deg",
scale: 1.5,
});
// => "translateX(100px) rotate(45deg) scale(1.5)"
Thư viện tự động hỗ trợ chuyển đổi giữa các định dạng màu khác nhau (HEX, RGB):
animate({
targets: ".element",
props: {
backgroundColor: ["#FF0000", "rgb(0, 0, 255)"],
},
duration: 1000,
});
Animation cho các thuộc tính SVG:
animate({
targets: "svg path",
props: {
d: [path1, path2],
fill: ["#FFF", "#000"],
},
duration: 1000,
});
// Animation khi phần tử xuất hiện trong viewport
const elements = document.querySelectorAll(".fade-in");
const observerCallback = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
effects.fadeIn(entry.target, 800);
}
});
};
const observer = new IntersectionObserver(observerCallback);
elements.forEach((el) => observer.observe(el));
document.querySelector(".button").addEventListener("click", () => {
const card = document.querySelector(".card");
animate({
targets: card,
props: {
scale: [1, 1.05, 1],
boxShadow: [
"0 2px 5px rgba(0,0,0,0.2)",
"0 15px 25px rgba(0,0,0,0.3)",
"0 2px 5px rgba(0,0,0,0.2)",
],
},
duration: 800,
easing: "easeOutElastic",
});
});
const buttons = document.querySelectorAll(".fancy-button");
buttons.forEach((button) => {
button.addEventListener("mouseenter", () => {
animate({
targets: button.querySelector(".background"),
props: { width: ["0%", "100%"] },
duration: 500,
easing: "easeOutCubic",
});
});
button.addEventListener("mouseleave", () => {
animate({
targets: button.querySelector(".background"),
props: { width: ["100%", "0%"] },
duration: Plot500,
easing: "easeOutCubic",
});
});
});
Animate được thiết kế để đạt hiệu suất cao với các chiến lược tối ưu hóa:
- Sử dụng
requestAnimationFrame
để đồng bộ với chu kỳ render của trình duyệt - Cache các giá trị được tính toán để giảm thiểu reflow và repaint
- Phân tích và áp dụng transform để sử dụng GPU acceleration khi có thể
- Tối ưu hóa các phép tính nội suy để giảm thiểu tiêu thụ CPU
- Modern browsers (Chrome, Firefox, Safari, Edge)
- IE11 với polyfill phù hợp
import React, { useEffect, useRef } from "react";
import { animate } from "anitimejs";
function FadeInComponent() {
const elementRef = useRef(null);
useEffect(() => {
animate({
targets: elementRef.current,
props: { opacity: [0, 1], translateY: ["20px", "0px"] },
duration: 800,
easing: "easeOutQuad",
});
}, []);
return <div ref={elementRef}>Content to fade in</div>;
}
<template>
<div ref="element">Content to animate</div>
</template>
<script>
import { animate } from "anitimejs";
export default {
mounted() {
animate({
targets: this.$refs.element,
props: { opacity: [0, 1], translateY: ["20px", "0px"] },
duration: 800,
easing: "easeOutQuad",
});
},
};
</script>
Bộ công cụ xử lý và tạo slug cho các ứng dụng web, đặc biệt hỗ trợ tốt cho nội dung tiếng Việt.
- 🔄 Tạo slug từ chuỗi bất kỳ: Chuyển đổi tiêu đề, câu văn thành định dạng URL thân thiện
- 🇻🇳 Hỗ trợ tiếng Việt: Tự động loại bỏ dấu, xử lý ký tự đặc biệt tiếng Việt
- ✅ Kiểm tra tính hợp lệ: Xác minh định dạng slug theo các tiêu chuẩn tùy biến
- 📋 Tạo slug độc nhất: Thêm hậu tố số khi cần để đảm bảo độc nhất
- 🧩 Phân tích slug: Trích xuất các thành phần từ chuỗi slug phức tạp
Tạo slug từ chuỗi với nhiều tùy chọn cấu hình.
function createSlug(input: string, options?: SlugOptions): string;
interface SlugOptions {
separator?: string; // Ký tự phân cách (mặc định: "-")
lowercase?: boolean; // Chuyển đổi sang chữ thường (mặc định: true)
removeAccents?: boolean; // Loại bỏ dấu tiếng Việt (mặc định: true)
maxLength?: number; // Giới hạn độ dài (mặc định: 0 - không giới hạn)
removeNonAlphanumeric?: boolean; // Loại bỏ ký tự đặc biệt (mặc định: true)
replaceWhitespace?: boolean; // Thay khoảng trắng bằng dấu phân cách (mặc định: true)
customReplacements?: Record<string, string>; // Thay thế ký tự tùy chỉnh
}
import { createSlug } from "anitimejs";
// Tạo slug cơ bản
createSlug("Hello World");
// => "hello-world"
// Xử lý tiếng Việt
createSlug("Chào Thế Giới");
// => "chao-the-gioi"
// Tùy chỉnh cấu hình
createSlug("Product Name (Version 2.0)", {
separator: "_",
maxLength: 20,
customReplacements: { "2.0": "2-0" },
});
// => "product_name_version"
Kiểm tra xem một chuỗi có phải là slug hợp lệ không.
function isValidSlug(slug: string, pattern?: RegExp): boolean;
import { isValidSlug } from "anitimejs";
// Kiểm tra với mẫu mặc định (chữ thường, số, dấu gạch ngang)
isValidSlug("hello-world"); // => true
isValidSlug("hello world"); // => false
isValidSlug("HELLO-WORLD"); // => false
// Kiểm tra với mẫu tùy chỉnh
isValidSlug("product_123", /^[a-z0-9_]+$/); // => true
Tạo slug độc nhất không trùng với các slug đã tồn tại.
function createUniqueSlug(
input: string,
existingSlugs?: string[],
options?: SlugOptions
): string;
import { createUniqueSlug } from "anitimejs";
// Tạo slug độc nhất
const existingSlugs = ["hello-world", "hello-world-1"];
createUniqueSlug("Hello World", existingSlugs);
// => "hello-world-2"
// Với tùy chỉnh
createUniqueSlug("Hello World", existingSlugs, { separator: "_" });
// => "hello_world_1"
Trích xuất một phần cụ thể từ chuỗi slug.
function getSlugPart(
slug: string,
position?: "first" | "last" | number,
separator?: string
): string;
import { getSlugPart } from "anitimejs";
// Trích xuất phần cuối (mặc định)
getSlugPart("blog/2023/post-title", "last", "/");
// => "post-title"
// Trích xuất phần đầu
getSlugPart("blog/2023/post-title", "first", "/");
// => "blog"
// Trích xuất theo vị trí
getSlugPart("blog/2023/post-title", 1, "/");
// => "2023"
// Tạo đường dẫn URL thân thiện với SEO từ tiêu đề bài viết
const articleTitle = "10 Cách Học Tiếng Anh Hiệu Quả (Phiên bản 2025)";
const slug = createSlug(articleTitle);
// => "10-cach-hoc-tieng-anh-hieu-qua-phien-ban-2025"
const articleUrl = `https://example.com/articles/${slug}`;
// => "https://example.com/articles/10-cach-hoc-tieng-anh-hieu-qua-phien-ban-2025"
// Tạo slug cho bài viết mới, đảm bảo độc nhất
function createArticleSlug(title, existingArticles) {
const existingSlugs = existingArticles.map((article) => article.slug);
return createUniqueSlug(title, existingSlugs);
}
const articles = [
{ id: 1, title: "Bài viết đầu tiên", slug: "bai-viet-dau-tien" },
{ id: 2, title: "Bài viết thứ hai", slug: "bai-viet-thu-hai" },
];
const newArticle = {
id: 3,
title: "Bài viết đầu tiên", // Trùng tiêu đề
slug: createArticleSlug("Bài viết đầu tiên", articles),
};
// => { id: 3, title: "Bài viết đầu tiên", slug: "bai-viet-dau-tien-1" }
// Xử lý đường dẫn phân cấp
const fullPath = "blog/technology/javascript/new-features";
// Trích xuất danh mục
const category = getSlugPart(fullPath, 1, "/"); // => "technology"
// Trích xuất chủ đề
const topic = getSlugPart(fullPath, 2, "/"); // => "javascript"
// Kiểm tra tính hợp lệ của URL
const allParts = fullPath.split("/");
const allValid = allParts.every((part) => isValidSlug(part));
Tham gia vào GitHub repository của AnitimeJS để đóng góp ý kiến, báo cáo lỗi hoặc yêu cầu tính năng mới.
Tài liệu chi tiết sẽ được cập nhật tại trang tài liệu AnitimeJS.
MIT © AnitimeJS Contributors