起因, 目的:
想查看某个字体,对中英文的支持情况。
效果图:
完整项目见这里, 需要积分下载,不然的话,显得太水了。
过程:
- AI 对话, 生成代码。
- 我检查运行, 来回修改。
- 写个博客,记录过程。
核心代码 App.js
import React, { useState, useEffect, useCallback } from 'react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import './App.css';
import Header from './components/Header';
import FontSelector from './components/FontSelector';
import TextDisplay from './components/TextDisplay';
const fonts = [
{ name: 'Arial' },
{ name: 'Noto Sans' },
{ name: 'SimSun' },
{ name: 'Roboto' },
{ name: 'Times New Roman' },
{ name: 'Microsoft YaHei' },
{ name: 'Consolas' },
{ name: 'Open Sans' },
{ name: 'Noto Sans SC' },
{ name: 'Lora' },
];
const defaultFont = 'Arial';
function App() {
const [selectedFont, setSelectedFont] = useState(defaultFont);
const [englishFont, setEnglishFont] = useState(defaultFont);
const [chineseFont, setChineseFont] = useState(defaultFont);
const [searchTerm, setSearchTerm] = useState('');
const checkFontSupport = async (fontName, text) => {
try {
const normalizedFontName = fontName.trim();
if (['Arial', 'Microsoft YaHei', 'SimSun', 'Consolas', 'Times New Roman'].includes(normalizedFontName)) {
if (normalizedFontName === 'Arial' || normalizedFontName === 'Consolas' || normalizedFontName === 'Times New Roman') {
return text === 'A';
}
if (normalizedFontName === 'Microsoft YaHei') {
return true;
}
if (normalizedFontName === 'SimSun') {
return text === '中';
}
}
await document.fonts.load(`20px "${normalizedFontName}"`);
const isFontAvailable = document.fonts.check(`20px "${normalizedFontName}"`);
if (!isFontAvailable) {
console.log(`字体 ${normalizedFontName} 不可用`);
return false;
}
return true;
} catch (error) {
console.error(`检测字体 ${fontName} 失败:`, error);
return false;
}
};
const handleFontChange = useCallback((fontName) => {
const timer = setTimeout(async () => {
setSelectedFont(fontName);
const supportsEnglish = await checkFontSupport(fontName, 'A');
const supportsChinese = await checkFontSupport(fontName, '中');
const warnings = [];
if (!supportsEnglish) {
warnings.push('英文');
setEnglishFont(defaultFont);
} else {
setEnglishFont(fontName);
}
if (!supportsChinese) {
warnings.push('中文');
setChineseFont(defaultFont);
} else {
setChineseFont(fontName);
}
if (warnings.length > 0) {
toast.warn(`字体 ${fontName} 不支持${warnings.join('和')},将使用默认字体 ${defaultFont}`);
}
}, 100);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
const link = document.createElement('link');
link.href =
'https://fonts.font.im/css2?family=Noto+Sans&family=Roboto&family=Open+Sans&family=Noto+Sans+SC&family=Lora&display=swap';
link.rel = 'stylesheet';
document.head.appendChild(link);
return () => document.head.removeChild(link);
}, []);
const filteredFonts = fonts.filter((font) =>
font.name.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="App">
<Header />
<FontSelector
fonts={filteredFonts}
selectedFont={selectedFont}
onFontChange={handleFontChange}
searchTerm={searchTerm}
onSearchChange={setSearchTerm}
/>
<TextDisplay englishFont={englishFont} chineseFont={chineseFont} />
<ToastContainer />
</div>
);
}
export default App;
过程简述
初始:4 种字体,静态检测,单行文本。
扩展:10 种字体,动态检测(checkFontSupport),添加搜索框、Google Fonts 链接、中英文各 3 行。
问题:
- 字体检测失败:改进 checkFontSupport,本地字体特殊处理。
- Google Fonts 加载:切换到 fonts.font.im。
- 重复警告:合并为单一警告。
运行:
npm install react-toastify
npm start
然后访问:http://localhost:3001
结论 + todo
- 大体效果还可以。
- 搜索框,还是有点问题。