疯狂的技术宅 前端先锋 javascript
每日前端夜话0x79
每日前端夜话,陪你聊前端。
天天晚上18:00准时推送。
正文共:4740 字
预计阅读时间: 16 分钟
翻译:疯狂的技术宅
来源:logrocket前端
最近关注了太多的工具,如今最好从全部 React 和 npm-install-everything 的文章中休息一下,来看看一些纯粹的 DOM 和 Web API 功能,它们能够在不依赖任何第三方库的前提下在现代浏览器中运行。java
这篇文章将讲解八个不为人知的 DOM 功能,这些功能具备强大的浏览器支持。为了帮助你理解每一个功能的工做原理,我将经过大量的测试代码为你本身提供演示,这些代码都放在了CodePen上。web
因为微信公众号不能引用并显示CodePen上的效果,请你们点击文末的查看原文或者复制连接并粘贴到浏览器【http://blog.yidengxuetang.com/post/201905/30/】,到个人博客上查看效果。另外查看原文以前顺便点一下“在看” ^_^npm
学习这些方法和属性没有陡峭的学习曲线,而且能够与项目中所使用的任何工具集在一块儿使用。浏览器
你确定用 addEventListener() 处理过将事件附加到 Web 文档中的元素。一般 addEventListener() 调用看起来像这样:安全
1element.addEventListener('click', doSomething, false);
第一个参数是正在监听的事件。第二个参数是一个回调函数,它将在事件发生时执行。第三个参数是一个名为 useCapture 的布尔值,用于指示是否要使用事件冒泡或捕获【https://www.sitepoint.com/event-bubbling-javascript/】。微信
这些你们都知道(特别是前两个)。但也许你不知道 addEventListener() 也接受一个替换最终布尔值的参数。这个新参数是一个 options 对象,以下所示:app
1element.addEventListener('click', doSomething, { 2 capture: false, 3 once: true, 4 passive: false 5});
请注意,该语法容许定义三个不一样的属性。如下是每一个含义的快速概述:dom
你能够试着运行如下 CodePen 项目中关于 options 对象的一些代码:
CodePen演示:https://codepen.io/impressivewebs/pen/GeJZYz/
请注意,演示页面上的按钮只会附加一次文本。若是将 once 值改成 false,则屡次单击该按钮,每次单击按钮时都会附加文本。
浏览器对 options 对象的支持很是好:全部浏览器都支持它,除了 IE11 及更早版本【https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Browser_compatibility】,所以若是你不考虑微软 Edge 以前的浏览器,那么使用起来仍是很是安全的。
平滑滚动老是常常被用到的。当点击本地页面连接并当即跳转到指定位置时(若是你眨眼,甚至可能会错过跳转过程),这会显得很突兀。平滑滚动改进了页面的用户体验。
虽然过去用 jQuery 插件就足以完成了,但如今用 window.scrollTo() 方法只须要一行 JavaScript。
scrollTo() 方法做用于 Window 对象,告诉浏览器滚动到页面上的指定位置。这是一个最简单语法的例子:
1window.scrollTo(0, 1000);
这将向右滚动窗口 0px (表示x坐标或水平滚动)并向下滚动 1000px (垂直滚动,这一般是你想要的)。但这样作的话滚动并非一个平滑的动画效果,页面将会忽然滚动。
有时确实是你想要的。可是为了可以平滑滚动,你必须加入不为人知的 ScrollToOptions 对象,以下所示:
1window.scrollTo({ 2 top: 0, 3 left: 1000, 4 behavior: 'smooth' 5});
这段代码与前面的例子相同,但在 options 对象中添加了 behavior 属性的smooth值。
请看下面这个 CodePen 演示,容许你自定义滚动量和行为:
CodePen演示:https://codepen.io/impressivewebs/pen/pGYXgj
尝试在框中输入一个数字(最好是一个比较大的数字,好比4000)并更改 behavior 选择框以使用 smooth 或 auto(这是 behavior 属性仅有的两个选项)。
关于此功能的一些说明:
对于 scrollTo() 的基本支持是全面的,但并不是全部浏览器【https://caniuse.com/#feat=element-scroll-methods】都支持 options 对象
此方法在应用于元素时也可使用
在更多状况下,使用 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:https://codepen.io/impressivewebs/pen/PgoNEj
单击该按钮时,将会使用传入的两个值进行计算。能够经过修改代码中的数字更改值。
至于浏览器支持,彷佛在兼容性上有些小问题,不过看上去如今几乎全部还在使用中的浏览器都支持可选参数功能,包括 IE10。
你可能知道,对于单选按钮和复选框,能够直接经过 checked 属性去获取或设置它,以下所示(假设 radioButton 是对特定表单输入的引用):
1console.log(radioButton.checked); // true 2radioButton.checked = false; 3console.log(radioButton.checked); // false
可是还有一个名为 defaultChecked 的属性,它能够应用于单选按钮组或复选框组,用来找出组中哪个最初被设置为了 checked。
这是一些HTML示例:
1<form id="form"> 2 <input type="radio" value="one" name="setOne"> One 3 <input type="radio" value="two" name="setOne" checked> Two<br /> 4 <input type="radio" value="three" name="setOne"> Three 5</form>
有了这个属性,即便在更改了被选中的单选按钮以后,也能够经过遍历找出最初哪个是默认值,以下所示:
1for (i of myForm.setOne) { 2 if (i.defaultChecked === true) { 3 console.log(‘i.value’); 4 } 5}
下面是CodePen演示,它将显示当前选中的单选按钮或默认选中的单选按钮,具体取决于你所使用的按钮:
CodePen:https://codepen.io/impressivewebs/pen/qwWoOr
该示例中的 defaultChecked 选项将始终为 “Two” 单选按钮。如上所述,这也能够用于复选框组。你能够试着修改 HTML 中的默认选中选项,而后再次点击按钮看看效果。
下面是一个复选框组的演示:
CodePen:https://codepen.io/impressivewebs/pen/wZMJYQ
在这种状况下,你会注意到默认状况下应该会检查两个复选框,所以当使用 defaultChecked 查询时,这两个复选框都会返回 true。
HTML 文档中的文本节点可能会很复杂,尤为是当动态插入或建立节点时。例如假设有如下 HTML:
1<p id="el">This is the initial text.</p> 2
而后我能够在该段落元素中添加一个文本节点:
1let el = document.getElementById('el'); 2el.appendChild(document.createTextNode(' Some more text.')); 3console.log(el.childNodes.length); // 2
请注意,在附加的文本节点以后的注释中,我记录了段落内子节点的长度,而且它表示有两个节点。这些节点是一个文本字符串,但因为文本是动态附加的,所以它们应该被视为单独的节点。
在某些状况下,若是将文本视为单个文本节点会更有帮助,这使文本更容易操做。这就是 normalize()和wholeText()的用武之地。
normalize() 方法可用于合并单独的文本节点:
1el.normalize(); 2console.log(el.childNodes.length); // 1
在元素上调用 normalize() 将会合并该元素内的任何相邻的文本节点。若是刚好在相邻的文本节点之间散布着一些 HTML,那么 HTML 将保持原样,而全部相邻的文本节点将被合并。
可是,若是因为某种缘由我想使文本节点分开,但我仍然但愿可以将文本做为一个单元抓取,那么 wholeText 就是有用的。所以我能够在相邻的文本节点上执行此操做,而不是调用 normalize()。
1console.log(el.childNodes[0].wholeText); 2// This is the initial text. Some more text. 3console.log(el.childNodes.length); // 2
只要我没有调用 normalize(),文本节点的长度将保持为 2,我能够用 wholeText 记录整个文本。但须要注意如下几点:
不少人可能很熟悉 insertAdjacentHTML() 方法,它容许你轻松地将一串文本或 HTML 添加到页面中与其余元素相关的特定位置。
但也许你不知道的是,还有另外两个以相似方式工做的方法:insertAdjacentElement() 和 insertAdjacentText()。
insertAdjacentHTML() 的一个缺点是插入的内容必须是字符串的形式。所以若是要包含 HTML,则必须将其声明为:
1el.insertAdjacentHTML('beforebegin', '<p><b>Some example</b> text goes here.</p>');
可是 insertAdjacentElement() 的第二个参数能够是元素引用:
1let el = document.getElementById('example'), 2addEl = document.getElementById('other'); 3el.insertAdjacentElement('beforebegin', addEl);
这个方法的有趣之处在于,它不只会将引用的元素添加到指定的位置,并且还会将元素从文档中的原始位置移除。这是一种在 DOM 中移动元素的简单方法。
这是使用 insertAdjacentElement()的 CodePen 演示。点击按钮能够有效地“移动”目标元素:
CodePen:https://codepen.io/impressivewebs/pen/MRjOpj
insertAdjacentText()方法的工做方式相似,但提供的文本字符串将仅做为文本插入,即便它包含HTML。请注意如下演示:
CodePen:https://codepen.io/impressivewebs/pen/MRymba
你能够将本身的文本添加到输入字段,而后使用该按钮将其添加到文档中。注意:任何特殊字符(如HTML标记)都将会做为 HTML 实体插入,请区分此方法与 insertAdjacentHTML() 行为的区别。
全部三种方法(insertAdjacentHTML(),insertAdjacentElement()和insertAdjacentText() )的第一个参数所使用的值的规则是相同的:
如前所述,咱们能够用熟悉的 addEventListener()方法将事件附加到网页上的元素。例如:
1btn.addEventListener('click', function () { 2 // do something here... 3}, false);
使用addEventListener()时,你可能想要阻止函数调用中的默认浏览器行为。例如,你可能但愿拦截 <a> 元素的点击并使用 JavaScript 来处理,你会这样作:
1btn.addEventListener('click', function (e) { 2 // do something here... 3 e.preventDefault(); 4}, false);
这里使用了 preventDefault(),这等价于老式的 return false 语句。这须要你将 event 对象传递给函数,由于在该对象上调用了 preventDefault()方法。
可是你能够用 event 对象作更多事情。事实上当使用某些事件时(例如click,dbclick,mouseup,mousedown),这些事件会暴露一些叫作 UIEvent 接口的东西。正如 MDN 所指出的,该接口上的许多功能已被弃用或没有标准化。但最有趣而且最有用的是 detail 属性,它是官方规范的一部分。
如下是它在同一个事件监听器示例中的代码:
1btn.addEventListener('click', function (e) { 2 // do something here... 3 console.log(e.detail); 4}, false);
我已经设置了一个 CodePen 演示,演示了使用许多不一样事件的结果:
CodePen:https://codepen.io/impressivewebs/pen/QoZoQe
演示中的每一个按钮都将按照按钮文本描述的方式进行响应,并显示一条显示当前点击次数的消息。须要注意的是:
1btnT.addEventListener('click', function (e) { 2 if (e.detail === 3) { 3 trpl.value = 'Triple Click Successful!'; 4 } 5}, false);
若是全部浏览器都计算过三次点击次数,那么你还能够检测到更高的点击次数,但我认为在大多数状况下,三次点击事件就足够了。
scrollHeight 和 scrollWidth 属性可能听起来很熟悉,由于你可能会将它们与其余与宽度和高度相关的 DOM 功能混淆。例如,offsetWidth 和 offsetHeight 属性将返回元素的高度和宽度,而不会考虑溢出。
请注意如下演示:
CodePen:https://codepen.io/impressivewebs/pen/WWxEpX
演示中的列具备相同的内容。左边列的 overflow 被设置为 auto,而右边列的 overflow 被设置为 hidden。 offsetHeight 属性返回相同的值,由于它不考虑可滚动区域或隐藏区域,它只测量元素的实际高度,包括垂直填充和边框。
另外一方面,命名恰当的 scrollHeight 属性将会计算元素的完整高度,包括可滚动(或隐藏)区域:
CodePen:https://codepen.io/impressivewebs/pen/EJyvoB
上面的演示与前一个相同,只不过它用了 scrollHeight 来获取每列的高度。再次注意,两列的值相同。但此次它的值要打得多,由于溢出区域也算做高度的一部分。
上面的示例主要关注元素高度,这是最多见的用例,但你也能够用 offsetWidth 和 scrollWidth,它们以相同的方式应用于水平滚动。
这就是你不知道的 DOM 功能列表,这些多是我在近几年遇到的一些最有趣的功能,因此我但愿在不远的未来你能把它们用在本身的项目中。
若是你以前用过其中的某些功能,或是若是你能想到其中某个功能的有趣的用例,请在评论中告诉我。
原文:https://blog.logrocket.com/8-dom-features-you-didnt-know-existed-ec2a0a28fd89