我正试图用JavaScript和为我的网站实现一个字体转换器,但头部迭代部分无法工作。
undefined is not an object (evaluating 'tagElement.style.fontFamily = fontsObj.headerFont')
这是我的代码
HTML:
<select name="font-select" id="font-select">
<option value='{"headerFont":"system-ui, -apple-system","bodyFont":"system-ui, -apple-system"}'>System & System</option>
<option value='{"headerFont":"Lato","bodyFont":"Karla"}' selected="selected">Lato & Karla</option>
<option value='{"headerFont":"Lora","bodyFont":"Lato"}'>Lora & Lato</option>
<option value='{"headerFont":"Philosopher","bodyFont":"Mulish"}'>Philosopher & Muli(sh)</option>
</select>
JS:
function changeFontStyle(fonts) {
const headerTags = ["h1", "h2", "h3", "h4", "h5", "h6"];
var bodyText;
const fontsObj = JSON.parse(fonts.value);
// Update headers' font
for (let headerTag in headerTags) {
var tagElements = document.getElementsByTagName(headerTag);
for (let tagElement in tagElements) {
tagElement.style.fontFamily = fontsObj.headerFont;
}
}
// Update body font
bodyText = document.getElementsByTagName("html")[0];
bodyText.style.fontFamily = fontsObj.bodyFont;
}
var fontSelector = document.getElementById("font-select")
fontSelector.onchange = changeFontStyle(fontSelector);
JSON.parse部分似乎工作正常(与这个答案下面的注释相反(,至少我看不到任何解析错误。
编辑:这里的问题的最新版本
您的onchange
处理程序未正确创建:
fontSelector.onchange = changeFontStyle(fontSelector);
这导致changeFontStyle(fontSelector)
立即被执行,并且返回值被(错误地(用作回调。
您的for (let headerTag in headerTags)
应该是for (let headerTag of headerTags)
(of
,而不是in
(。(in
将为您提供数组索引,而不是您想要的值。(
与for (let tagElement in tagElements)
相同,应该是for (let tagElement of tagElements)
。
请参阅:关于HTMLCollection元素的循环
var fontSelector = document.getElementById("font-select")
fontSelector.onchange = changeFontStyle;
function changeFontStyle() {
fonts = fontSelector
const headerTags = ["h1", "h2", "h3", "h4", "h5", "h6"];
var bodyText;
const fontsObj = JSON.parse(fonts.value);
// Update headers' font
for (let headerTag of headerTags) {
var tagElements = document.getElementsByTagName(headerTag);
for (let tagElement of tagElements) {
tagElement.style.fontFamily = fontsObj.headerFont;
}
}
// Update body font
bodyText = document.getElementsByTagName("html")[0];
bodyText.style.fontFamily = fontsObj.bodyFont;
}
<h1>Foo</h1>
<h2>Bar</h2>
<select name="font-select" id="font-select">
<option value='{"headerFont":"system-ui, -apple-system","bodyFont":"system-ui, -apple-system"}'>System & System</option>
<option value='{"headerFont":"Lato","bodyFont":"Karla"}' selected="selected">Lato & Karla</option>
<option value='{"headerFont":"Lora","bodyFont":"Lato"}'>Lora & Lato</option>
<option value='{"headerFont":"Philosopher","bodyFont":"Mulish"}'>Philosopher & Muli(sh)</option>
</select>
为了保持解决方案的性能,我们将使用querySelectorAll
而不是getElementsByTagName
一次性选择所有H
标记,并仅在它们上循环一次以设置新字体。此外,由于querySelectorAll
返回NodeList
,我们将能够使用forEach
方法而不是嵌套的for..in
循环来遍历返回的元素。
想法很简单:
- 倾听下拉更改
- 使用
querySelectorAll
选择所有H
元素 - 循环遍历返回的元素并更改它们的字体
- 然后更改
body
的字体
这里有一个现场演示:
const fontsDropdown = document.getElementById('font-select'),
headerTags = ["h1", "h2", "h3", "h4", "h5", "h6"],
fontsChanger = () => {
const fontsJson = JSON.parse(fontsDropdown.value);
/** we'll select all the elemnts based on the selector found in the "headerTags" array by concatinating those selector with an "," (we'll have: "h1,h2,h3,h4,h5,h6") */
document.querySelectorAll(headerTags.join(',')).forEach(h => h.style.fontFamily = fontsJson.headerFont);
/** change the body's font also */
document.body.style.fontFamily = fontsJson.bodyFont;
};
/** run on page load so the font change based on the initial selected value in the dropdown */
fontsChanger();
/** listen for the "change" event on the fonts dropdown and call "fontsChanger" function when a change occurs */
fontsDropdown.addEventListener('change', fontsChanger);
<p>Am a P tag</p>
<h1>Am an H1 tag</h1>
<h3>Am an H3 tag</h3>
<h6>Am an H6 tag</h6>
<select name="font-select" id="font-select">
<option value='{"headerFont":"system-ui, -apple-system","bodyFont":"system-ui, -apple-system"}'>System & System</option>
<option value='{"headerFont":"Lato","bodyFont":"Karla"}' selected>Lato & Karla</option>
<option value='{"headerFont":"Lora","bodyFont":"Lato"}'>Lora & Lato</option>
<option value='{"headerFont":"Philosopher","bodyFont":"Mulish"}'>Philosopher & Muli(sh)</option>
</select>
上面的演示仍然可以进一步改进,特别是如果您确信不会处理动态添加的
H
标签。
旁注:并非所有设备都具有您在下拉列表中指定的所有字体。很可能大多数设备都没有安装某些字体,所以在这种情况下不会发生更改。
另一个附带说明:更改
H
标记字体是无用的,因为它们将继承body
的更改。不管怎样,我在上面的演示中保持了你的逻辑不变。