内容简介:最近关注了太多的工具,现在最好从所有 React 和 npm-install-everything 的文章中休息一下,来看看一些纯粹的 DOM 和 Web API 功能,它们可以在不依赖任何第三方库的前提下在现代浏览器中运行。这篇文章将讲解八个鲜为人知的 DOM 功能,这些功能具有强大的浏览器支持。为了帮助你理解每个功能的工作原理,我将通过大量的测试代码为你自己提供演示,这些代码都放在了CodePen上。学习这些方法和属性没有陡峭的学习曲线,并且可以与项目中所使用的任何工具集在一起使用。
最近关注了太多的工具,现在最好从所有 React 和 npm-install-everything 的文章中休息一下,来看看一些纯粹的 DOM 和 Web API 功能,它们可以在不依赖任何第三方库的前提下在现代浏览器中运行。
这篇文章将讲解八个鲜为人知的 DOM 功能,这些功能具有强大的浏览器支持。为了帮助你理解每个功能的工作原理,我将通过大量的测试代码为你自己提供演示,这些代码都放在了CodePen上。
学习这些方法和属性没有陡峭的学习曲线,并且可以与项目中所使用的任何 工具 集在一起使用。
addEventListener() 的新参数 options
你肯定用 addEventListener()
处理过将事件附加到 Web 文档中的元素。通常 addEventListener()
调用看起来像这样:
element.addEventListener('click', doSomething, false); 复制代码
第一个参数是正在监听的事件。第二个参数是一个回调函数,它将在事件发生时执行。第三个参数是一个名为 useCapture
的布尔值,用于指示是否要使用事件冒泡或捕获。
这些大家都知道(特别是前两个)。但也许你不知道 addEventListener()
也接受一个替换最终布尔值的参数。这个新参数是一个 options
对象,如下所示:
element.addEventListener('click', doSomething, { capture: false, once: true, passive: false }); 复制代码
请注意,该语法允许定义三个不同的属性。以下是每个含义的快速概述:
- capture — 与之前提到的
useCapture
参数相同的布尔值 - once — 布尔值,如果设置为
true
,则表示该事件应仅在目标元素上运行一次,然后被删除 - passive — 一个最终的布尔值,如果设置为
true
,表示该函数永远不会调用preventDefault()
,即使它被包含在函数体中
其中最有趣的是 once
选项。这肯定会在很多情况下派上用场,并且无需用 removeEventListener()
或使用其他一些复杂的技术来强制单个事件触发器。如果你用过 jQuery,可能熟悉该库中的类似功能:.one() 方法。
你可以试着运行以下 CodePen 项目中关于 options
对象的一些代码:
.
CodePen演示: codepen.io/impressivew…
请注意,演示页面上的按钮只会附加一次文本。如果将 once
值改为 false
,则多次单击该按钮,每次单击按钮时都会附加文本。
浏览器对 options
对象的支持非常好:所有浏览器都支持它,除了 IE11 及更早版本,因此如果你不考虑微软 Edge 之前的浏览器,那么使用起来还是非常安全的。
scrollTo() 方法用于在窗口或元素中平滑滚动
平滑滚动总是经常被用到的。当点击本地页面链接并立即跳转到指定位置时(如果你眨眼,甚至可能会错过跳转过程),这会显得很突兀。平滑滚动改进了页面的用户体验。
虽然过去用 jQuery 插件就足以完成了,但现在用 window.scrollTo()
方法只需要一行 JavaScript。
scrollTo()
方法作用于 Window 对象,告诉浏览器滚动到页面上的指定位置。这是一个最简单语法的例子:
window.scrollTo(0, 1000); 复制代码
这将向右滚动窗口 0px
(表示x坐标或水平滚动)并向下滚动 1000px
(垂直滚动,这通常是你想要的)。但这样做的话滚动并不是一个平滑的动画效果,页面将会突然滚动。
有时确实是你想要的。但是为了能够平滑滚动,你必须加入鲜为人知的 ScrollToOptions
对象,如下所示:
window.scrollTo({ top: 0, left: 1000, behavior: 'smooth' }); 复制代码
这段代码与前面的例子相同,但在 options
对象中添加了 behavior
属性的 smooth
值。
请看下面这个 CodePen 演示,允许你自定义滚动量和行为:
See the Pen Using addEventListener() with an `options` Object as Third Parameter by Louis Lazaris (@impressivewebs) on CodePen.
CodePen演示: codepen.io/impressivew…
尝试在框中输入一个数字(最好是一个比较大的数字,比如4000)并更改 behavior
选择框以使用 smooth
或 auto
(这是 behavior
属性仅有的两个选项)。
关于此功能的一些说明:
-
对于
scrollTo()
的基本支持是全面的,但并非所有浏览器都支持options
对象 -
此方法在应用于元素时也可以使用
-
这些选项也同样适用于
scroll()
和scrollBy()
方法
setTimeout() 和带有可选参数的 setInterval()
在更多情况下,使用 window.setTimeout()
和 window.setInterval()
实现基于时序的动画的方案已经被性能更好的 window.requestAnimationFrame()
所取代。但是有些情况下使用 setTimeout()
或 setInterval()
是正确的选择,因此了解这些方法的一个鲜为人知的特性是很好的。
通常你总会看到这些方法被使用,语法如下:
let timer = window.setInterval(doSomething, 3000); function doSomething () { // Something happens here… } 复制代码
这里的 setInterval()
传递两个参数:回调函数和时间间隔。如果使用 setTimeout()
将只运行一次,而在当前这种情况下,它会无限期地运行,直到我在传入 timer 变量时调用 window.clearTimeout()
。
这很简单。但是如果我希望回调函数能够接受参数呢?可以这样做:
let timer = window.setInterval(doSomething, 3000, 10, 20); function doSomething (a, b) { // Something happens here… } 复制代码
注意我在 setInterval()
调用中添加了两个参数。然后我的 doSomething()
函数接受了这些参数,并可以根据需要操作它们。
这是一个 CodePen 演示,演示了如何使用 setTimeout()
:
.
CodePen: codepen.io/impressivew…
单击该按钮时,将会使用传入的两个值进行计算。可以通过修改代码中的数字更改值。
至于浏览器支持,似乎在兼容性上有些小问题,不过看上去现在几乎所有还在使用中的浏览器都支持可选参数功能,包括 IE10。
单选按钮和复选框的 defaultChecked 属性
你可能知道,对于单选按钮和复选框,可以直接通过 checked
属性去获取或设置它,如下所示(假设 radioButton
是对特定表单输入的引用):
console.log(radioButton.checked); // true radioButton.checked = false; console.log(radioButton.checked); // false 复制代码
但是还有一个名为 defaultChecked
的属性,它可以应用于单选按钮组或复选框组,用来找出组中哪一个最初被设置为了 checked
。
这是一些HTML示例:
<form id="form"> <input type="radio" value="one" name="setOne"> One <input type="radio" value="two" name="setOne" checked> Two<br /> <input type="radio" value="three" name="setOne"> Three </form> 复制代码
有了这个属性,即使在更改了被选中的单选按钮之后,也可以通过遍历找出最初哪一个是默认值,如下所示:
for (i of myForm.setOne) { if (i.defaultChecked === true) { console.log(‘i.value’); } } 复制代码
下面是CodePen演示,它将显示当前选中的单选按钮或默认选中的单选按钮,具体取决于你所使用的按钮:
See the Pen defaultChecked on Radio Buttons by Louis Lazaris (@impressivewebs) on CodePen.
CodePen: codepen.io/impressivew…
该示例中的 defaultChecked
选项将始终为 “Two” 单选按钮。如上所述,这也可以用于复选框组。你可以试着修改 HTML 中的默认选中选项,然后再次点击按钮看看效果。
下面是一个复选框组的演示:
See the Pen defaultChecked on Checkboxes by Louis Lazaris (@impressivewebs) on CodePen.
CodePen: codepen.io/impressivew…
在这种情况下,你会注意到默认情况下应该会检查两个复选框,因此当使用 defaultChecked
查询时,这两个复选框都会返回 true
。
使用 normalize() 和 wholeText 操作文本节点
HTML 文档中的文本节点可能会很复杂,尤其是当动态插入或创建节点时。例如假设有以下 HTML:
<p id="el">This is the initial text.</p> 复制代码
然后我可以在该段落元素中添加一个文本节点:
let el = document.getElementById('el'); el.appendChild(document.createTextNode(' Some more text.')); console.log(el.childNodes.length); // 2 复制代码
请注意,在附加的文本节点之后的注释中,我记录了段落内子节点的长度,并且它表示有两个节点。这些节点是一个文本字符串,但由于文本是动态附加的,因此它们应该被视为单独的节点。
在某些情况下,如果将文本视为单个文本节点会更有帮助,这使文本更容易操作。这就是 normalize()
和 wholeText()
的用武之地。
normalize()
方法可用于合并单独的文本节点:
el.normalize(); console.log(el.childNodes.length); // 1 复制代码
在元素上调用 normalize()
将会合并该元素内的任何相邻的文本节点。如果恰好在相邻的文本节点之间散布着一些 HTML,那么 HTML 将保持原样,而所有相邻的文本节点将被合并。
但是,如果由于某种原因我想使文本节点分开,但我仍然希望能够将文本作为一个单元抓取,那么 wholeText
就是有用的。因此我可以在相邻的文本节点上执行此操作,而不是调用 normalize()
。
console.log(el.childNodes[0].wholeText); // This is the initial text. Some more text. console.log(el.childNodes.length); // 2 复制代码
只要我没有调用 normalize()
,文本节点的长度将保持为 2
,我可以用 wholeText
记录整个文本。但需要注意以下几点:
- 我必须在其中一个文本节点上调用
wholeText
,而不是元素(因此代码中的el.childNodes [0]
、el.childNodes[1]
也可以正常工作) - 文本节点必须相邻,中间不能有其他 HTML 分隔它们
你可以看到这两个功能以及 splitText()
方法已经用在了这个 CodePen 演示中。打开 CodePen 控制台或浏览器的开发人员工具控制台可以查看生成的日志。
insertAdjacentElement() 和 insertAdjacentText()
很多人可能很熟悉 insertAdjacentHTML()
方法,它允许你轻松地将一串文本或 HTML 添加到页面中与其他元素相关的特定位置。
但也许你不知道的是,还有另外两个以类似方式工作的方法: insertAdjacentElement()
和 insertAdjacentText()
。
insertAdjacentHTML()
的一个缺点是插入的内容必须是字符串的形式。因此如果要包含 HTML,则必须将其声明为:
el.insertAdjacentHTML('beforebegin', '<p><b>Some example</b> text goes here.</p>'); 复制代码
但是 insertAdjacentElement()
的第二个参数可以是元素引用:
let el = document.getElementById('example'), addEl = document.getElementById('other'); el.insertAdjacentElement('beforebegin', addEl); 复制代码
这个方法的有趣之处在于,它不仅会将引用的元素添加到指定的位置,而且还会将元素从文档中的原始位置移除。这是一种在 DOM 中移动元素的简单方法。
这是使用 insertAdjacentElement()
的 CodePen 演示。点击按钮可以有效地“移动”目标元素:
CodePen: codepen.io/impressivew…
See the Pen Using insertAdjacentElement() to Change an Element's Location by Louis Lazaris (@impressivewebs) on CodePen.
insertAdjacentText()
方法的工作方式类似,但提供的文本字符串将仅作为文本插入,即使它包含HTML。请注意以下演示:
CodePen: codepen.io/impressivew…
See the Pen Using insertAdjacentText() with HTML Tags by Louis Lazaris (@impressivewebs) on CodePen.
你可以将自己的文本添加到输入字段,然后使用该按钮将其添加到文档中。注意:任何特殊字符(如HTML标记)都将会作为 HTML 实体插入,请区分此方法与 insertAdjacentHTML()
行为的区别。
所有三种方法( insertAdjacentHTML()
, insertAdjacentElement()
和 insertAdjacentText()
)的第一个参数所使用的值的规则是相同的:
beforebegin afterbegin beforeend afterend
event.detail 属性
如前所述,我们可以用熟悉的 addEventListener()
方法将事件附加到网页上的元素。例如:
btn.addEventListener('click', function () { // do something here... }, false); 复制代码
使用 addEventListener()
时,你可能想要阻止函数调用中的默认浏览器行为。例如,你可能希望拦截 <a>
元素的点击并使用 JavaScript 来处理,你会这样做:
btn.addEventListener('click', function (e) { // do something here... e.preventDefault(); }, false); 复制代码
这里使用了 preventDefault()
,这等价于老式的 return false
语句。这需要你将 event
对象传递给函数,因为在该对象上调用了 preventDefault()
方法。
但是你可以用 event
对象做更多事情。事实上当使用某些事件时(例如 click
, dbclick
, mouseup
, mousedown
),这些事件会暴露一些叫做UIEvent 接口的东西。正如 MDN 所指出的,该接口上的许多功能已被弃用或没有标准化。但最有趣并且最有用的是 detail
属性,它是官方规范的一部分。
以下是它在同一个事件监听器示例中的代码:
btn.addEventListener('click', function (e) { // do something here... console.log(e.detail); }, false); 复制代码
我已经设置了一个 CodePen 演示,演示了使用许多不同事件的结果:
CodePen: codepen.io/impressivew…
See the Pen Using the event.detail Property by Louis Lazaris (@impressivewebs) on CodePen.
演示中的每个按钮都将按照按钮文本描述的方式进行响应,并显示一条显示当前点击次数的消息。需要注意的是:
- WebKit 浏览器允许无限制的点击次数,除了
dblclick
,它总是两次点击。 Firefox 只允许最多三次点击,然后计数再次开始 - 我已经包通过包含
blur
和focus
来证明这些不符合条件并且总是返回0(即没有点击) - 在 IE11 等旧版浏览器中的行为严重不一致
请注意,在演示中包含了一个很好的用例——模仿三击事件:
btnT.addEventListener('click', function (e) { if (e.detail === 3) { trpl.value = 'Triple Click Successful!'; } }, false); 复制代码
如果所有浏览器都计算过三次点击次数,那么你还可以检测到更高的点击次数,但我认为在大多数情况下,三次点击事件就足够了。
scrollHeight 和 scrollWidth 属性
scrollHeight
和 scrollWidth
属性可能听起来很熟悉,因为你可能会将它们与其他与宽度和高度相关的 DOM 功能混淆。例如, offsetWidth
和 offsetHeight
属性将返回元素的高度和宽度,而不会考虑溢出。
请注意以下演示:
CodePen: codepen.io/impressivew…
See the Pen offsetHeight Doesn't Count Past CSS Overflow by Louis Lazaris (@impressivewebs) on CodePen.
演示中的列具有相同的内容。左边列的 overflow
被设置为 auto
,而右边列的 overflow
被设置为 hidden
。 offsetHeight
属性返回相同的值,因为它不考虑可滚动区域或隐藏区域,它只测量元素的实际高度,包括垂直填充和边框。
另一方面,命名恰当的 scrollHeight
属性将会计算元素的完整高度,包括可滚动(或隐藏)区域:
CodePen: codepen.io/impressivew…
See the Pen scrollHeight Measures an Element's Full Scrollable Area by Louis Lazaris (@impressivewebs) on CodePen.
上面的演示与前一个相同,只不过它用了 scrollHeight
来获取每列的高度。再次注意,两列的值相同。但这次它的值要打得多,因为溢出区域也算作高度的一部分。
上面的示例主要关注元素高度,这是最常见的用例,但你也可以用 offsetWidth
和 scrollWidth
,它们以相同的方式应用于水平滚动。
总结
这就是你不知道的 DOM 功能列表,这些可能是我在近几年遇到的一些最有趣的功能,所以我希望在不远的将来你能把它们用在自己的项目中。
如果你之前用过其中的某些功能,或是如果你能想到其中某个功能的有趣的用例,请在评论中告诉我。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 玩转TensorFlow?你需要知道这30功能
- PostgreSQL 的一些你可能不知道但应该尝试的功能
- 每个JavaScript开发人员都应该知道的新ES2018功能
- R语言有多强大?十个你不知道的功能
- 8 个你不知道的 DOM 功能[每日前端夜话0x79]
- WWDC19 - Xcode 11 新功能,以及你不一定知道的其他特性
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。