【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

你或许从未听说过的 15 个 HTML 元素方法

  • 2018-08-16
  • 本文字数:8340 字

    阅读完需:约 27 分钟

虽然现代化的 web 开发更多地依赖各种 MVC 框架,但开发者仍需要熟练掌握 HTML 与 DOM 方面的基础知识。不过,即使是有着多年经验的前端开发者,也会遇到一些不明所以的情况。本文首先将为初学者介绍 HTML 与 DOM 的基本常识,随后为大家介绍 15 个比较冷门的 HTML 元素的方法。

初学者指导

首先让我们来讨论一下 HTML 与 DOM 之间的区别。

显然,普通的 <table> 元素就是一段 HTML 代码,它可以应用在任何一个以 .html 为扩展名的文件中。元素自带一系列特性(attribute),以控制它的显示方式与行为。

这就是元素的全部内容,它与 JavaScript 没有任何关联。

而 DOM 的作用是将你的 JavaScript 代码与文档中的 HTML 元素关联在一起,让你能够以对象的方式与这些元素进行交互。

这就是所谓的文档对象模型。

在 HTML 中的每个元素都对应着一个 DOM ‘接口’,其中定义了若干属性(property,通常会映射至 HTML 元素上的特性)与方法。举例来说,一个 <table> 元素对应着一个 HTMLTableElement 接口。

你可以按以下方式获取某个元素的引用:

复制代码
const searchBox = document.getElementById('search-box');

现在,你就可以访问该元素上定义的所有属性与方法了。打个比方,你可以通过 searchBox.value 访问它的 value 属性,也可以调用 searchBox.focus() 方法让光标移至输入框上。

感谢你参加这个 58 秒的 DOM 入门培训课程,哈哈。

现在的问题在于,大多数元素都没有提供什么有趣的方法。因此,除非你特意到官方文档规范上去搜索那些可能永远都用不到的东西,否则很容易忽略掉那些零散的小技巧。

幸运的是,浏览规范与整理小技巧正是我用于避免陷入困境的两种最喜欢的方式。那么,让我们开始吧……

如果你也希望尝试一下这些技巧,又恰好有一些浏览器 DevTools 可以使用的话,可以在元素树型结构中先选中某个元素,然后在控制台中输入 $0,它会返回给你一个所选中元素的引用。如果你需要返回该元素的对象,请输入 dir($0)

在控制台中,你可以实现各种丰富的功能。

图片来自 Unsplash ,由 Holger Link 上传

#1 table 的方法

原始的 table 元素(时至今日仍然是网站布局方法里的第一名)本身自带许多精巧的方法,使用这些方法创建表格就像搭建宜家里的桌子一样简单。

以下是部分实用的方法。

复制代码
const tableEl = document.querySelector('table');
const headRow = tableEl.createHead().insertRow();
headerRow.insertCell().textContent = 'Make';
headerRow.insertCell().textContent = 'Model';
headerRow.insertCell().textContent = 'Color';
const newRow = tableEl.insertRow();
newRow.insertCell().textContent = 'Yes';
newRow.insertCell().textContent = 'No';
newRow.insertCell().textContent = 'Thank you';

整段代码里完全用不着使用 document.createElement() 方法。

如果你在一个 table 元素上直接调用 .insertRow() 方法,它甚至会自动为你插入一个 <tbody> 元素,是不是很棒?

#2 scrollIntoView()

你知道吗?当页面的 URL 中包含 #something 元素时,一旦页面加载,浏览器就会自动滚动至具有这个 ID 的元素之处。

这确实是一项很贴心的功能,但如果你在页面加载之后再渲染元素,这项功能就不起作用了。

不过,你也可以通过以下方式,手动地让这项功能重新生效:

复制代码
document.querySelector(document.location.hash).scrollIntoView();

#3 hidden

好吧,hidden 或许不是一个方法,但如果你提出抗议,那我也要争论一下:在 hidden 的背后很可能对应着一个 setter,这可是一个货真价实的方法,对不对?

不管怎样,你是否曾经为了隐藏某个元素而使用过 myElement.style.display = 'none' 这种方法呢?如果是的话,请别再这么做了!

只需调用 myElement.hidden = true ,即可实现元素隐藏的功能。

#4 toggle()

嗯,toggle 也不算是元素的方法,它实际上是元素属性上的一个方法。严格来说,这是一种为元素添加或删除某个 class 的方法,具体做法是 myElement.classList.toggle('some-class')

如果你曾经通过 if 条件语句为元素添加 class,那就应该赶紧改用这种做法。

正确的方式是为 toggle 方法传入第二个参数,如果该参数返回 true ,则指定的 class 就会添加至元素上。

复制代码
el.classList.toggle('some-orange-class', theme === 'orange');

我知道你在想些什么:这种写法违背了 'toggle' 这个词的本义(开关),那些从 IE 时代过来的开发者们都这么想,他们断言应当彻底摒弃使用第二个参数的做法。

所以,我收回我的话。不必坚持这种写法了,各位请随意!

#5 querySelector()

好吧,你当然知道这个方法,但据我推测,应该只有 17% 的开发者才知道,该方法可以使用在任意元素上。

打个比方,myElement.querySelector('.my-class') 的作用是返回在 myElement 的子代中包含 my-class 这个 class 的所有元素。

#6 closest

该方法可在任意元素上使用,它能够向上查找元素的树型结构,可以理解为 与 querySelector() 相反的方法。因此,我可以通过以下方法获取当前内容的对应标头:

复制代码
myElement.closest('article').querySelector('h1');

这段方法首先向上找到最近的 <article> 元素,然后再向下找到最近的 <h1> 元素。

#7 getBoundingClientRect()

在对 DOM 元素调用该方法时,将返回一个包含其空间结构详细信息的简单对象。

复制代码
{
x: 604.875,
y: 1312,
width: 701.625,
height: 31,
top: 1312,
right: 1306.5,
bottom: 1343,
left: 604.875
}

不过,在调用该方法时需要注意两点:

  • 调用该方法会导致元素的重绘,根据设备与页面复杂程度的不同,重绘的时间可能会占用几毫秒。因此,如果你需要重复地调用该方法,例如在使用动画的场景下,需要特别注意这一点。
  • 并非所有的浏览器都会返回这些值,他们有这个责任么?

#8 matches()

假设我需要检查某个元素是否包括一个特定的 class。

这是最复杂的方式:

复制代码
if (myElement.className.indexOf('some-class') > -1) {
// do something
}

比上面的好一点,但和本文没什么关系:

复制代码
if (myElement.className.includes('some-class')) {
// do something
}

最佳方式:

复制代码
if (myElement.matches('.some-class')) {
// do something
}

#9 insertAdjacentElement()

我今天才刚学到这一条!它的作用类似于 appendChild() ,但能够更好地控制插入子元素的具体位置。

parentEl.insertAdjacentElement('beforeend', newEl)parentEl.appendChild(newEl) 的作用是一样的,但除此之外,你还可以指定 beforebeginafterbeginafterend 这几个参数值,元素将按这些值的名称所示插入相应的位置。

多么强大的控制能力!

多棒的点子。

#10 contains()

你有没有遇到过这样的情形,需要知道某个元素是否被包含在另一个元素中?至少我本人经常会遇到这样的问题。

打个比方,假设我在处理一个鼠标点击事件时,需要知道它是发生在一个模态窗口中还是发生在外面(这样我才能够关闭这个窗口),我大概会这么做:

复制代码
const handleClick = e => {
if (!modalEl.contains(e.target)) modalEl.hidden = true;
};

代码中的 modalEl 是模态窗口的引用,而 e.target 则代表各种发生点击事件的元素。

有趣的是,每当遇到这种情形,在我第一遍写代码的时候,100% 的概率会将其中的判断逻辑写反。

哪怕是我提高了警惕,并在保存代码之前尝试将逻辑颠倒过来写,仍然还是写错。

#11 getAttribute()

这毫无疑问是所有元素方法中最没用的一个,但有一个场景除外。

你是否记得,我在本文的开头部分曾提到,对象的属性 property 通常也会映射到它的特性 attribute 中(我在上文中特别用粗体强调了这一点,注意不是斜体)?

但在某一个场景中,这种假设并不成立,这就是某个元素的 href 特性,例如 <a href="/animals/cat">Cat</a>

调用 el.href 不会返回 /animals/cat,这可能与你的猜测不符。原因在于 <a> 元素实现了 HTMLHyperlinkElementUtils 接口,该接口提供了一系列辅助属性,例如 prototolhash 等等,以展现与链接的目标相关的值。

href 就是其中一个实用的属性,它将返回完整的 URL,并去掉无用的空格,而不是返回在特性中所指定的相对 URL。

这样一来,如果你需要获取 href 特性中的字符串字面值,就只能使用 el.getAttribute('href') 方法了。

#12 dialog 元素的三大法宝

<dialog> 是一个相对较新的元素,它带来了两个还算能用的方法,和一个非常棒的方法。其中show()close() 方法的功能与你所想象的一样,我感觉还算可以。

showModal() 方法能够将 <dialog> 元素显示在页面的顶层,居中对齐,这正是所期望的模态窗口行为。你无需指定 z-index,或者手动添加一个灰色的背景,也不需要监听 esc 按键以关闭此窗口。浏览器能够理解模态窗口的工作方式,并自动完成你所期望的行为。

这真是太棒了。

#13 forEach()

某些情况下,当你获取到一个元素列表的引用时,可以通过 forEach() 方法进行迭代式调用。

for() 进行循环已经是 2014 年代的老古董了。

假设你需要记录页面中所有链接的 URL,可以输入以下代码,只要你不介意看到报错。

复制代码
document.getElementsByTagName('a').forEach(el ==> {
console.log(el.href);
});

也可以这么做:

复制代码
document.querySelectorAll('a').forEach(el ==> {
console.log(el.href);
});

问题出在 getElementsByTagName 与其他类似的 get... 方法返回的是一个 HTMLCollection 接口,而 querySelectorAll返回的是一个 NodeList 接口。

NodeList 接口为我们提供了 forEach() 方法(此外还包括 keys()values(),和 entries() 等方法 )。

理想的情况下,最好是每个方法都只返回简单的数组,而不是返回一些类似数组的对象。不过别担心,ECMA 大神为我们提供了 Array.from() 方法,它能够把所有这些类数组对象转化为一个真正的数组。

所以,这样的代码就能够正常工作:

复制代码
Array.from(document.getElementsByTagName('a')).forEach(el ==> {
console.log(el.href);
});

奖励关卡:创建了一个数组之后,你就能够对其使用 map()filter()reduce() 以及其他各种数组方法了。打个比方,先不管目的是什么,总之你可以按以下方式返回所有外部链接的数组:

复制代码
Array.from(document.querySelectorAll('a'))
.map(el => el.origin)
.filter(origin => origin !== document.origin)
.filter(Boolean);

我最喜欢的一个方法是 .filter(Boolean),它肯定会给将来的我在调试问题时带来无穷的烦恼,哈哈。

#14 表单

或许你已经知道,<form> 有一个 submit() 方法。但或许你不知道表单还有一个 reset() 方法,而且当你需要对表单元素进行验证时,还可以调用 reportValidity() 方法。

此外,你也可以通过对表单的 elements 属性加上元素的 name 特性 的方式调用它的属性。打个比方,myFormEl.elements.email 将返回属于某个 <form> 中的 <input name="email" /> 元素(‘属于’,并不代表它一定是一个‘子元素’)。

好吧,其实刚才我是骗你的。elements 并不会返回一个元素列表,而是返回一个控件列表(显然它不是一个数组,因为没必要这么做)。

举例来说:假设你有三个单选按钮,每个都有相同的名称 animal,那么 formEl.elements.animal 将返回一个单选按钮集的引用(一个控件,三个元素)。

formEl.elements.animal.value 将返回所选中的单选按钮的值。

这种语法看起来非常古怪,让我们来分解一下看看:formEl 是一个元素,elements 则对应 HTMLFormControlsCollection 接口,这并非一个真正的数组,其中的每一项内容也未必代表一个 HTML 元素。animal 是多个单选按钮的集合,只是因为他们具有相同的 name 特性才聚集在一起( RadioNodeList 接口就是为此而生的),而 value 则返回该集合中所选中的那个单选按钮的 value 特性。

非常直观,嗯……

#15 select()

我或许应该重新组织一下本文,让最后一条内容不会显得过于无足轻重。不管怎样,.select() 方法会将你指定的元素中的所有内容全选。

真方便。

感谢你耐心阅读本文,希望本文能为你带来一些新知识,给你的工作带来实际的用途。

请始终记住在使用这些技巧前先查阅一下浏览器的支持情况,万一遇到什么令你上火的情况,别揪自己的眉毛出气。

查看英文原文 https://hackernoon.com/15-html-element-methods-youve-potentially-never-heard-of-fc6863e41b2a

感谢覃云对本文的审校。

2018-08-16 18:152008
用户头像

发布了 428 篇内容, 共 172.0 次阅读, 收获喜欢 38 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

GraphX 在图数据库 Nebula Graph 的图计算实践

NebulaGraph

图数据库 图数据库实战

疫情又反扑,除了不乱跑,我们还能干点啥?

数据君

面试杀手锏!2021最新Android常用开源库总结,Android校招面试指南

欢喜学安卓

android 程序员 面试 移动开发

面试看这个就够了!6年菜鸟开发面试字节跳动安卓研发岗,学习路线+知识点梳理

欢喜学安卓

android 程序员 面试 移动开发

让机器人响应更快!阿里云 ARMS 助力深绘智能系统响应时长缩短50%

阿里巴巴中间件

k8s-client-go源码剖析(三)

远鹏

Kubernetes Kubernetes源码 Go 语言

字节面试太刁钻了:不加机器,怎么提升系统并发100倍

Java架构师迁哥

2020-21《全球质量报告》解读

BY林子

质量保障 质量赋能 敏捷测试

如何避免让微服务测试成为研发团队最大的瓶颈?

阿里巴巴中间件

MySQL之父,MySQL官方,三大顶会齐赞,凭什么?

数据君

2020已过,2021来临,iOS 开发市场如何?一切都是未知!【未来可期】

ios 程序员

单例模式原来是这么简单?!

后台技术汇

28天写作 2月春节不断更

软件架构模式之事件驱动架构

架构精进之路

软件架构 七日更 28天写作 2月春节不断更

List去除重复数据的五种方式

xcbeyond

Java ArrayList 28天写作

云话题 | 第3期 你女朋友在买买买时,程序员小哥在干嘛?

阿里云Edge Plus

CDN 直播 直播带货

疫情成本遭不住?一招降本85%,架构特性全部公开!

数据君

领域的边界,一个小讨论

李小腾

领域驱动设计 DDD

Linux-Lab 入门:体验

贾献华

Docker Linux 嵌入式 内核 Lab

这只猫在云端定居了?边缘计算在天猫精灵云应用上的落地实践

阿里云Edge Plus

CDN IoT 边缘计算 云桌面

最基础的3道java面试题,你真的答得上来吗

田维常

面试

一款基于 WEB 的通用数据管控工具 - CloudQuery

棱镜射线

开发工具 运维工程师 dba 数据库管理工具

点赞系统软件开发

luluhulian

滴滴 Flink-1.10 升级之路

Apache Flink

flink

【内含福利】流行在CDN圈内的黑话有哪些?

阿里云Edge Plus

CDN

勿让 Docker Volume 引发 Terminating Pod

黄久远

Docker 云计算 Kubernetes 容器 云原生

第三周

ALone

Elasticsearch 从 0 到千万级数据查询实践

📿

Java spring elasticsearch Spring Cloud spring data

LeetCode题解:69. x 的平方根,二分查找,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

CodeDay#5 全程回顾——一场关于动态化开发实践的技术探讨

蚂蚁集团移动开发平台 mPaaS

mPaaS Codeday 技术沙龙

new的过程是怎样的?看完这一篇就懂了

codevald

Java JVM原理 面向对象编程 类对象

DIY一款能随周围环境变化的智能灯泡,求婚必备!

IoT云工坊

人工智能 物联网 人脸识别 sdk IoT App

你或许从未听说过的15个HTML元素方法_语言 & 开发_David Gilbertson_InfoQ精选文章