如何遍历所有元素<tag>并更改其字体?



我正试图用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 &amp; System</option>
<option value='{"headerFont":"Lato","bodyFont":"Karla"}' selected>Lato &amp; Karla</option>
<option value='{"headerFont":"Lora","bodyFont":"Lato"}'>Lora &amp; Lato</option>
<option value='{"headerFont":"Philosopher","bodyFont":"Mulish"}'>Philosopher &amp; Muli(sh)</option>
</select>

上面的演示仍然可以进一步改进,特别是如果您确信不会处理动态添加的H标签。

旁注:并非所有设备都具有您在下拉列表中指定的所有字体。很可能大多数设备都没有安装某些字体,所以在这种情况下不会发生更改。

另一个附带说明:更改H标记字体是无用的,因为它们将继承body的更改。不管怎样,我在上面的演示中保持了你的逻辑不变。

最新更新