ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

The JavaScript Way 实战:遍历与查询 DOM——掌握元素选择、CSS 选择器与信息获取

The JavaScript Way 实战:遍历与查询 DOM——掌握元素选择、CSS 选择器与信息获取 教程文档【免费下载链接】thejswayThe JavaScript Way book项目地址https://gitcode.com/gh_mirrors/th/thejsway点击查看免费下载本篇技术指南以开源图书The JavaScript Way仓库 manuscript/chapter14.md中“Traverse the DOM”一章为骨架系统讲解如何在浏览器中用 JavaScript 定位页面元素按标签、类、ID、CSS 选择器以及读取元素的 HTML 内容、文本内容、属性与类名。读者学完后将能够在实际页面中快速、可靠地“抓到”任意 DOM 节点并为后续的动态页面修改见 chapter15.md打下基础。本书正文位于仓库manuscript/目录由 mkdocs.yml 配置的 Material for MkDocs 构建chapter14 归属于 “Create interactive web pages创建交互式网页” 章节板块承接 chapter13.md 的 DOM 基础发现是通往交互式网页开发的关键一环。本章示例页面全章示例围绕一张“世界七大奇迹”网页展开。页面包含古代与现代两组奇迹列表并带有一个参考文献链接列表。后续所有选择与信息获取示例都基于这段 HTMLh1Seven wonders of the world/h1 pDo you know the seven wonders of the world?/p div idcontent h2Wonders from Antiquity/h2 pThis list comes to us from ancient times./p ul classwonders idancient li classexistsGreat Pyramid of Giza/li liHanging Gardens of Babylon/li liLighthouse of Alexandria/li liStatue of Zeus at Olympia/li liTemple of Artemis at Ephesus/li liMausoleum at Halicarnassus/li liColossus of Rhodes/li /ul h2Modern wonders of the world/h2 pThis list was decided by vote./p ul classwonders idnew li classexistsPetra/li li classexistsGreat Wall of China/li li classexistsChrist the Redeemer/li li classexistsMachu Picchu/li li classexistsChichen Itza/li li classexistsColosseum/li li classexistsTaj Mahal/li /ul h2References/h2 ul lia hrefhttps://en.wikipedia.org/wiki/Seven_Wonders_of_the_Ancient_WorldSeven Wonders of the Ancient World/a/li lia hrefhttps://en.wikipedia.org/wiki/New7Wonders_of_the_WorldNew Wonders of the World/a/li /ul /div选择元素逐节点遍历的局限在上一章 chapter13.md 中我们学会了从document根节点出发借助childNodes属性在页面结构中逐层向下移动。例如要选中标题 “Wonders from Antiquity” 的h2元素必须考虑元素之间的文本节点它是body元素第 6 个子节点的第 2 个子节点于是写出如下晦涩的代码// Show the Wonders from Antiquity h2 element console.log(document.body.childNodes[5].childNodes[1]);这种逐节点遍历的方式既笨拙又极易出错代码可读性差一旦页面中插入新元素就必须同步更新索引。幸好DOM 提供了一系列远为优雅的解决方案——选择方法selection methods它们让你能够直接“按需索取”元素而无需关心节点在树中的精确位置。按 HTML 标签选择getElementsByTagName()所有 DOM 元素都拥有getElementsByTagName()方法它接收一个标签名作为参数返回一个NodeList对象其中包含所有匹配该标签的子元素。注意搜索范围覆盖调用该方法的节点之下的全部后代元素而不仅是直接子元素。借助它选中页面中第一个h2变得非常简单// Get all h2 elements into an array const titleElements document.getElementsByTagName(h2); console.log(titleElements[0]); // Show the first h2 console.log(titleElements.length); // 3 (total number of h2 elements in the page)命名约定给 DOM 元素节点相关的变量加上Element或复数Elements后缀是社区流行的命名习惯。本书全程沿用这一约定例如上文用titleElements命名保存多个h2节点的变量让读者一眼看出它装着“元素集合”。按类名选择getElementsByClassName()类似的getElementsByClassName()方法按类名返回元素的 NodeList。搜索同样覆盖调用节点的所有后代元素// Show all elements that have the class exists const existingElements Array.from(document.getElementsByClassName(exists)); existingElements.forEach(element { console.log(element); });这里有一个关键细节NodeList 对象并不是真正的 JavaScript 数组因此并非所有数组方法都适用于它。例如在较旧的浏览器环境中forEach()可能无法直接调用。为了对 NodeList 使用数组方法如forEach()、map()、filter()需要先用Array.from()将其转换为真正的数组——这正是上面代码第一行所做的工作。按 ID 选择getElementById()document变量还提供getElementById()方法在整个文档范围内返回具有指定 ID 的元素如果找不到任何匹配元素则返回null。// Show element with the ID new console.log(document.getElementById(new));易错点注意getElementById()中Element一词之后没有字母s与其他两个getElements...方法getElementsByTagName()、getElementsByClassName()不同。这一字之差是最常见的拼写错误来源。通过 CSS 选择器选择querySelectorAll() 与 querySelector()对于更复杂的场景可以使用CSS 选择器来访问 DOM 元素。先看一个“组合查询”需求找出既属于古代奇迹、又依然存在的所有li元素。用前面学到的方法可以这样写// All ancient wonders that still exist console.log(document.getElementById(ancient).getElementsByClassName(exists).length); // 1这种链式写法略显笨拙。为此 DOM 提供了两个基于 CSS 选择器的方法。第一个是querySelectorAll()它可以接受任意 CSS 选择器字符串并返回所有匹配元素。上面的复杂查询瞬间变得简洁清晰// All paragraphs console.log(document.querySelectorAll(p).length); // 3 // All paragraphs inside the content ID block console.log(document.querySelectorAll(#content p).length); // 2 // All elements with the exists class console.log(document.querySelectorAll(.exists).length); // 8 // All ancient wonders that still exist console.log(document.querySelectorAll(#ancient .exists).length); // 1第二个是querySelector()工作方式与querySelectorAll()一致但只返回第一个匹配元素若没有匹配项则返回null。// Show the first paragraph console.log(document.querySelector(p));掌握 CSS 选择器语法是高效使用这两个方法的前提除了本例用到的p标签、#content p后代组合、.exists类、#ancient .exists父子组合之外还包括属性选择器、伪类等更丰富的语法。从规范与实现角度看querySelectorAll()返回的是静态 NodeList——在调用时一次性计算匹配结果之后对 DOM 的增删不会影响该集合这一点与getElementsByTagName()等返回动态live集合的方法形成鲜明对比在“先查询、后修改页面”的代码中值得留意。如何选择合适的选择方法本章共介绍了五种选择方法它们的适用场景各不相同。由于querySelectorAll()和querySelector()基于 CSS 选择器理论上可以覆盖所有需求但它们可能比其他方法执行得稍慢。因此一般遵循以下经验法则需要获取的元素数量选择依据推荐方法多个按标签getElementsByTagName()多个按类名getElementsByClassName()多个既不按类也不按标签querySelectorAll()单个按 IDgetElementById()单个第一个不按 IDquerySelector()在绝大多数实际页面中上述方法的性能差异微乎其微当代码运行在超高频率的循环中、且对性能极为敏感时才值得优先考虑前四种“定向”方法。获取元素的信息选中元素之后下一步通常是读取它们携带的信息。DOM 为元素提供了读取 HTML 内容、文本内容、属性与类名的标准途径。读取 HTML 内容innerHTMLinnerHTML属性返回 DOM 元素的HTML 内容——即元素内部所有标记与文本的原始字符串// The HTML content of the DOM element with ID content console.log(document.getElementById(content).innerHTML);这个属性最初由微软引入并不属于 W3C DOM 规范但如今已被所有主流浏览器普遍支持成为事实标准。有趣的是本书下一章 chapter15.md 还会用innerHTML做“写”操作——比如用innerHTML li idcC/li向列表追加条目、或赋空字符串清空内容这正是读取与写入双向能力的体现。读取文本内容textContenttextContent属性返回 DOM 元素的全部文本内容且不包含任何 HTML 标记。与innerHTML相比它剥离了所有标签只留下纯文本// The textual content of the DOM element with ID content console.log(document.getElementById(content).textContent);两者用途泾渭分明需要以 HTML 字符串形式获得结构例如做序列化或诊断时用innerHTML只需要“看得见”的文字例如统计字数、拼接文案时用textContent。读取属性getAttribute()、hasAttribute() 与直接属性访问getAttribute()方法应用于某个 DOM 元素返回指定属性的值// Show href attribute of the first link console.log(document.querySelector(a).getAttribute(href));此外部分属性如id、href、value可以直接作为元素的属性property访问写法更简洁// Show ID attribute of the first list console.log(document.querySelector(ul).id); // Show href attribute of the first link console.log(document.querySelector(a).href);如果只想判断某个属性是否存在而不是读取其值可使用hasAttribute()方法它返回布尔值if (document.querySelector(a).hasAttribute(target)) { console.log(The first link has a target attribute.); } else { console.log(The first link does not have a target attribute.); // Will be shown }由于示例页面中的第一个链接没有target属性这段代码会输出 else 分支中的提示。读取类名classList 与 contains()一个 HTML 标签可以拥有多个类。classList属性返回该 DOM 元素的类列表这是一个类数组对象DOMTokenList既支持按索引访问也支持length长度属性// List of classes of the element identified by ancient const classes document.getElementById(ancient).classList; console.log(classes.length); // 1 (since the element only has one class) console.log(classes[0]); // wonders若要测试元素是否包含某个类可在类列表上调用contains()方法并传入待测试的类名if (document.getElementById(ancient).classList.contains(wonders)) { console.log(The element with ID ancient has the class wonders.); // Will be shown } else { console.log(The element with ID ancient does not have the class wonders.); }因为idancient的ul元素带有classwonders所以会输出前一个分支的结果。以上只是 DOM 遍历 API 的一部分。classList其实还提供add()、remove()、toggle()等修改方法Element接口上还有firstElementChild、lastElementChild、previousElementSibling等更丰富的导航属性读者可在后续章节或 MDN 的Element文档中继续深挖。本章要点速览与其逐节点遍历 DOM不如使用选择方法快速定位一个或多个元素。getElementsByTagName()、getElementsByClassName()分别按标签名、类名搜索两者都返回列表NodeList可用Array.from()转换为数组getElementById()按ID搜索返回单个元素。querySelectorAll()与querySelector()支持用CSS 选择器搜索前者返回全部匹配项后者只返回第一个匹配项。innerHTML返回元素的HTML 内容textContent返回不含任何 HTML 标记的文本内容。getAttribute()与hasAttribute()用于访问元素的属性classList属性及其contains()方法用于访问元素的类名。动手实践本章附有三组循序渐进的练习全部基于浏览器环境把示例 HTML 保存为本地网页打开浏览器控制台如 Chrome DevTools Console逐行运行验证即可。练习一统计元素数量以下 HTML 片段取自法国诗人 Paul Verlaine 的诗作Mon rêve familierh1Mon rêve familier/h1 pJe fais souvent ce rêve span classadjectiveétrange/span et span classadjectivepénétrant/span/p pDune spanfemme span classadjectiveinconnue/span/span, et que jaime, et qui maime/p pEt qui nest, chaque fois, ni tout à fait la même/p pNi tout à fait une autre, et maime et me comprend./p请补全countElements()函数——它接收一个 CSS 选择器作为参数返回对应元素的数量// TODO: write the countElements() function here console.log(countElements(p)); // Should show 4 console.log(countElements(.adjective)); // Should show 3 console.log(countElements(p .adjective)); // Should show 3 console.log(countElements(p .adjective)); // Should show 2参考解答一个可行实现是直接用querySelectorAll()配合length// Count elements matching a CSS selector const countElements (selector) document.querySelectorAll(selector).length;验证思路p匹配 4 个段落.adjective匹配 3 个强调词p .adjective是“段落后代中的强调词”同样是 3 个第三个段落里嵌套的inconnue也在段落之内而p .adjective要求强调词直接是段落的子元素嵌套在span中的inconnue不满足条件故结果为 2。练习二处理属性以下是几种乐器的描述列表h1Some musical instruments/h1 ul li idclarinet classwind woodwind The a hrefhttps://en.wikipedia.org/wiki/Clarinetclarinet/a /li li idsaxophone classwind woodwind The a hrefhttps://en.wikipedia.org/wiki/Saxophonesaxophone/a /li li idtrumpet classwind brass The a hrefhttps://en.wikipedia.org/wiki/Trumpettrumpet/a /li li idviolin classchordophone The a hrefhttps://en.wikipedia.org/wiki/Violinviolin/a /li /ul请编写一个包含linkInfo()函数的 JavaScript 程序要求显示页面上链接的总数。第一个与最后一个链接的href目标。该函数必须在页面没有任何链接时也能正常工作。然后在 HTML 列表末尾追加一件新乐器并检查程序的新结果li idharpsichord The a hrefhttps://en.wikipedia.org/wiki/Harpsichordharpsichord/a /li参考解答关键点在于先用querySelectorAll(a)拿到全部链接再借助数组索引访问首尾元素当length为 0 时跳过属性读取避免在空集合上取索引// Show information about the pages links const linkInfo () { const links Array.from(document.querySelectorAll(a)); console.log(The page contains ${links.length} links.); if (links.length 0) { console.log(First link: ${links[0].href}); console.log(Last link: ${links[links.length - 1].href}); } }; linkInfo();练习三处理类名继续改进上一个程序增加一个has()函数根据元素的 ID 判断它是否拥有某个类输出true、false如果找不到该元素则输出错误提示。// Show if an element has a class const has (id, someClass) { // TODO: write the function code }; has(saxophone, woodwind); // Should show true has(saxophone, brass); // Should show false has(trumpet, brass); // Should show true has(contrabass, chordophone); // Should show an error message提示用console.error()而非console.log()来在控制台显示错误信息。参考解答核心是先用getElementById()查找元素并处理null分支这正是本章强调的“找不到返回 null”的实战应用再用classList.contains()判断类名// Show if an element has a class const has (id, someClass) { const element document.getElementById(id); if (element null) { console.error(No element has the id ${id}.); return; } console.log(element.classList.contains(someClass)); };逐条核对预期saxophone的类为wind woodwind包含woodwindtrue而不包含brassfalsetrumpet的类为wind brass包含brasstrue而contrabass在页面中根本不存在getElementById()返回null于是走错误分支输出提示。在本地运行与验证想跟随本书边读边练有两种方式。其一是把文中示例保存为.html文件直接用浏览器打开并配合开发者工具控制台逐段运行 JavaScript这也是本书“零环境依赖”的推荐做法。其二是将整个仓库作为 MkDocs 站点在本地浏览按 README.md 的说明先安装 poetry然后在仓库根目录依次执行poetry shell poetry install mkdocs serve默认在http://localhost:8000提供书籍在线浏览第 14 章对应manuscript/chapter14.md源文件可随时对照正文、图片与练习进行学习。赞分享教程文档【免费下载链接】thejswayThe JavaScript Way book项目地址https://gitcode.com/gh_mirrors/th/thejsway点击查看免费下载相关推荐HTML DOM选择器与遍历如何高效获取元素和节点列表HTML DOM选择器与遍历如何高效获取元素和节点列表 掌握HTML DOM选择器和遍历技巧是前端开发的基础能力能让你快速定位页面元素并进行操作。在vani教程前端10个必读DA项目中语义分割领域自适应经典论文解读10个必读DA项目中语义分割领域自适应经典论文解读 欢迎来到领域自适应Domain Adaptation的世界 在这个快速发展的机器学习分支中语义Strophe.js核心功能解析BOSH与WebSocket双协议实现实时消息传输Strophe.js核心功能解析BOSH与WebSocket双协议实现实时消息传输 Strophe.js是一款强大的JavaScript库专为实时消息传输设即时通讯WebSocket通信上一篇全面解析R3nzSkin5个高效安全使用英雄联盟换肤工具的最佳实践下一篇网盘直链下载助手终极指南三步摆脱限速烦恼创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表