最近在找日本顏文字(kaomoji)的時候,覺得現有的網站不是分類太雜就是手機上不太好用,就順手做了一個簡單的版本。
開發過程中有兩個前端技巧覺得蠻實用的,不管做什麼類型的網站應該都用得到,分享一下。
網站裡每個分類頁面都有大量的顏文字卡片,如果一次全部渲染,手機上會明顯卡卡的。最初用了 react-virtualized 之類的滾動方案,但因為每張卡片寬度不固定(顏文字長度不一樣),算起來很麻煩。
後來換了一個更簡單的方式——把顏文字按子分類分組,初始只渲染前幾組,用 Intersection Observer 偵測用戶滾動到底部時再載入下一批:
const INITIAL_GROUPS_TO_SHOW = 3;
const GROUPS_TO_LOAD_MORE = 2;
useEffect(() => {
if (!hasMoreGroups || !loadMoreRef.current) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
setVisibleGroups(prev => prev + GROUPS_TO_LOAD_MORE);
}
},
{ rootMargin: '400px' }
);
observer.observe(loadMoreRef.current);
return () => observer.disconnect();
}, [hasMoreGroups]);
rootMargin: '400px' 是關鍵——讓載入在用戶看到之前就觸發content-visibility: auto 效果更好,瀏覽器會自動跳過畫面外的元素渲染<div style={{ contentVisibility: 'auto' }}>
{categoryItems.map((item, index) => (
<KaomojiCard key={index} item={item} />
))}
</div>
顏文字網站最核心的互動就是「點一下就複製到剪貼簿」,用 navigator.clipboard 就能做到:
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(item.kaomoji);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
} catch (error) {
console.error("Failed to copy:", error);
}
};
功能本身很簡單,但幾個小細節加上去之後體驗差很多:
視覺回饋:複製成功時蓋一層半透明綠色背景 + 勾勾,1.5 秒後自動消退。讓用戶確認「有複製到」。
{copied && (
<div className="absolute inset-0 flex items-center justify-center
bg-green-100/90 rounded-xl">
<span className="text-green-700 font-medium">✓ コピー</span>
</div>
)}
點擊回彈動畫:加一個 active:scale-95 就有按鈕按下去的觸感,成本極低但效果明顯。
<div className="cursor-pointer active:scale-95 transition-all duration-300"
onClick={handleCopy}>
{item.kaomoji}
</div>
最近使用紀錄:用 React Context + localStorage 追蹤用戶最近複製過的顏文字,下次進來直接顯示在最上面。這個功能對回訪率幫助很大。
以上兩個技巧(Intersection Observer 漸進式載入、複製的 UX 回饋)是開發過程中覺得最值得分享的部分,應該不只限於顏文字網站,做電商、部落格、作品集都用得到。
網站目前用 Next.js 14 + Tailwind CSS 開發,部署在 Cloudflare Pages 上,有興趣的話歡迎玩看看:
有任何問題歡迎留言交流!
這兩個都是很實用的 pattern ,我自己也會用,不過通常我會用套件 https://github.com/streamich/react-use
這裡面有
兩個都很好用,另外虛擬捲動我推 https://tanstack.com/virtual/latest