首页 技术 正文
技术 2022年11月19日
0 收藏 381 点赞 2,967 浏览 10549 个字

最近一直在关注工具,从 React 和 npm-install-everything 中休息一下,看看一些原生的 DOM 和 Web API 的功能,他们可以在没有任何依赖库的浏览器中直接运行。

这篇文章将介绍八个鲜为人知的 DOM 功能,浏览器已经支持了这些功能。为了帮助解释每个功能的工作原理,我将为您用代码来演示这些功能。

这些方法没有陡峭的学习曲线,并且可以为你的项目所用。

你肯定习惯于使用 addEventListener() 将事件添加到Web中的元素,一般情况下, addEventListener() 调用起来是这样的:

element.addEventListener('click',doSomething,false);

第一个元素是我们要监听的事件,第二个元素是事件触发时的回调函数,第三个参数是一个布尔值用来标识事件在捕获还是冒泡阶段触发。

很多时候我们都知道前两个参数,但是也许你不知道 addEventListener() 也接受传其他参数来代替布尔值。这个新的参数是一个可选的对象,就像这样:

element.addEventListener('click', doSomething, {
capture: false,
once: true,
passive: false
});

语法允许定义三个不同的属性。以下是每个属性的简介:

  • capture — 布尔值,和上文提到的作用一样

  • once — 布尔值,如果设置为 true 事件只会执行一次,然后就会被移除掉

  • passive — 最后一个布尔值,如果设置为 true, 将永远不会调用 preventDefault() ,即使在函数体中。

这里面最有意思的是 once 选项。在很多情况下我们都需要这个功能,并且不会使用 removeEventListener() 或使用其他的复杂技术来强制只能点击一次。如果你使用过 jQuery,那你就知道 .one() 的功能。

你能在 CodePen 里来验证它:

let btn = document.querySelector('button'),
op = document.querySelector('.output');btn.addEventListener('click', function () {
op.innerHTML += 'Button was clicked';
}, {
capture: false,
once: true,
passive: false
});

请注意,上面页面上的按钮只会添加一次文本。如果将 once 值改为 false ,则可以点击多次,每次点击都可以添加一行文本。

浏览器中对 options 对象支持的非常好:除了IE11及更早的版本外,所有浏览器都支持它,因此如果你不担心微软浏览器,那就可以使用它。

scrollTo() 用于窗口或元素是否平滑滚动


平滑滚动是必要的。当前页面链接跳转到制定位置时(如果你不注意,就一闪而过),看起来就很卡。平滑滚动是不仅看起来不错,而且还能改进页面用户体验。

虽然过去使用 jQuery 插件已经做到了,但现在只需要使用一行 JavaScript 也能达到类似的效果, 那就是 window.scrollTo()。

该方法应用于 Window 对象,告知浏览器滚动到页面上的制定位置。例如,这里有个简单示例: scrollTo()。

window.scrollTo(0, 1000);

这将滚动到横坐标 0px 和纵坐标 1000px 的页面位置。但这种情况下,滚动并不是平滑的,页面会突然滚动,就是用哈希到本地链接一样。

也许这就是你想要的,为了获得平滑滚动,你必须加入 ScrollToOptions 对象,就像这样:

window.scrollTo({
top: 0,
left: 1000,
behavior: 'smooth'
})

这个代码和前面的示例等效,但是是在对象内添加了 behavior值为 smooth 的 options。

let btn = document.querySelector('button'),
btn2 = document.querySelectorAll('button')[1],
input = document.querySelector('input'),
select = document.querySelector('select');btn.addEventListener('click', function () {
window.scrollTo({
left: 0,
top: input.value,
behavior: select.value
});
}, false);btn2.addEventListener('click', function () {
window.scrollTo({
left: 0,
top: 0,
behavior: select.value
});
}, false);

试试在输入框输入一个数字(最好是一个大数),并且更改 options 选项框里的值 smooth 或 auto (这也是 behaviro 属性的唯一两个选项)。

关于这个功能的一些说明:

  • 浏览器基本上都支持 scrollTo() ,但部分浏览器依然不支持 options 对象

  • 即使不作用于 window ,也可以使用该方法

  • 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() 来说,这个只会运行一次,而在这种情况下,他将无限期运行,直到我在传入计时器的时候调用 window.clearTimeout()。

很容易吧,但是如果我希望回调函数接受参数呢?好吧,对计时器方法添加新的内容试一下:

let timer = window.setInterval(doSomething, 3000, 10, 20);
function doSomething (a, b) {
// Something happens here…
}

注意,我在 setInterval() 中添加了两个参数。然后我在 doSomething() 中接受这些参数,并根据需要对其操作。

下面演示如何使用 setTimeout() :

let btn = document.querySelector('button'),
op = document.querySelector('output'),
a = 5,
b = 7;btn.addEventListener('click', () => {
op.innerHTML = 'Calculating...';
setTimeout(doSomething, 2000, a, b);
});function doSomething (a, b) {
op.innerHTML = a + b;
}

单击按钮时,将使用两个传入值进行运算。然后数字展示在页面上。

至于浏览器支持情况似乎不太一样,但几乎所有正在使用的浏览器都支持可选参数功能,包括 IE10。

单选按钮和复选框的默认选中属性

就像你所直到的,对于单选框和复选框,如果你想获取或者设置 checked 属性,你可以使用 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’);
}
}

下面是代码演示:

let myForm = document.getElementById('form'),
btn = document.querySelector('button'),
btn2 = document.querySelectorAll('button')[1],
op = document.querySelector('output'),
i;btn.addEventListener('click', function () {
for (i of myForm.setOne) {
if (i.checked === true) {
op.innerHTML = `Current selected option is: ${i.value}`;
}
}
}, false);btn2.addEventListener('click', function () {
for (i of myForm.setOne) {
if (i.defaultChecked === true) {
op.innerHTML = `The default selected option is: ${i.value}`;
}
}
}, false);

defaultChecked 总是返回 “Two” 的选项。如前所述,也可以通过复选框组来完成,尝试更改HTML中的默认选中选项,然后重试按钮。

这里是另外一个使用复选框按钮的例子:

let myForm = document.getElementById('form'),
btn = document.querySelector('button'),
btn2 = document.querySelectorAll('button')[1],
op = document.querySelector('output'),
op2 = document.querySelectorAll('output')[1],
i;btn.addEventListener('click', function () {
op.innerHTML = 'Current selected option(s): ';
for (i of myForm.setOne) {
if (i.checked === true) {
op.innerHTML += `${i.value} `;
}
}
}, false);btn2.addEventListener('click', function () {
op2.innerHTML = 'Default selected option(s): ';
for (i of myForm.setOne) {
if (i.defaultChecked === true) {
op2.innerHTML += `${i.value} `;
}
}
}, false);

在这个例子中,你看到了两个默认的选中复选框的按钮,当使用 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 控制台或者浏览器的控制台查看生成的日志。

let b = document.body;// length of child nodes is "1"
console.log(b.firstElementChild.childNodes.length);// I split the child text nodes at character 15
b.firstElementChild.firstChild.splitText(15);// Now the length is "2"
console.log(b.firstElementChild.childNodes.length);// Read the text as a single text node using "wholeText"
console.log(b.firstElementChild.childNodes[0].wholeText);// It's still 2 nodes
console.log(b.firstElementChild.childNodes.length);// Then I can normalize as needed
b.firstElementChild.normalize();// Back to "1" text node
console.log(b.firstElementChild.childNodes.length);


insertAdjacentElement() and insertAdjacentText()


许多人可能会熟悉 insertAdjacentHTML() 方法,该方法允许您轻松地将文本或HTML字符串添加到页面中与其他元素相关的特定位置。

但您可能不知道规范还包含两个在类似的环境中工作的相关方法

那就是: insertAdjacentElement() and 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() 的代码演示。点击按钮可有效“移动”目标元素:

let p1 = document.getElementById('p1'),
btn = document.querySelector('button');btn.addEventListener('click', function () {
p1.insertAdjacentElement('beforebegin', p2);
this.disabled = true;
}, false);

insertAdjacentText() 方法的工作原理类似,但所提供的文本字符串将以文本的形式插入,即使它包含HTML。请注意以下演示:

let p1 = document.getElementById('p1'),
btn = document.querySelector('button');btn.addEventListener('click', function () {
p1.insertAdjacentText('beforeend', document.getElementById('textIns').value);
}, false);

您可以将自己的文本添加到输入框中,然后使用按钮将其添加到文档中。请注意,任何特殊字符(如HTML标记)都将作为HTML实体插入,与 insertadjacenthl() 相比,该方法的行为有所不同。

这三个方法第一个参数都是一样的,取值为:

  • beforebegin: 插入到调用方法的元素之前

  • afterbegin: 插入元素中,在其第一个子元素之前

  • beforeend: 插入元素内部,在元素的最后一个子元素之后

  • afterend: 插入元素之后

事件详细信息

如前所述,事件使用熟悉的 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 等价的。要求将事件传递到函数中,因为调用了 preventDefault() 方法。

但是你可以用那个 event 对象做更多的事情。事实上,当使用某些事件(例如 click、 dbclick 、mouseup、mousedown )时,这些事件称为 uievent 接口的内容。正如MDN指出的那样,这个接口上的许多特性被弃用或不标准化。但最有趣和最有用的是 detail 属性,它是官方规范的一部分。

以下是同一个事件监听的示例:

btn.addEventListener('click', function (e) {
// do something here...
console.log(e.detail);
}, false);

我设置了一些代码演示,它返回不同事件的结果:

let btns = document.querySelector('.btns').querySelectorAll('button'),
btnT = document.querySelector('.trpl');for(i of btns) {
(function(index) {
index.addEventListener(index.innerHTML, function(e) {
document.getElementById(index.innerHTML).value = e.detail + ' event(s) occured.';
});
})(i);
}btnT.addEventListener('click', function (e) {
if (e.detail === 3) {
trpl.value = 'Triple Click Successful!';
}
}, false);

演示中的每个按钮都将以按钮文本描述的方式响应,并将显示一条显示当前单击计数的消息。需要注意的一些事项:

  • WebKit 浏览器允许无限制的点击次数,dbclick 除外,dbclick 总是两个。火狐只允许点击三次,然后计数再次开始。

  • 我将 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 属性将返回元素的高度或宽度,而不考虑溢出。

这里有个例子:

let op = document.querySelector('output');op.innerHTML = `Left column offsetHeight value:
${document.querySelector('.col1').offsetHeight}px&lt;br&gt;
Right column offsetHeight value:
${document.querySelector('.col1').offsetHeight}px
`;

演示中的列具有相同的内容。左侧列的 overflow 设置为 auto,而右侧列的 overflow 设置为 hidden。 offsetheight 属性为每个属性返回相同的值,因为它不考虑滚动或隐藏区域;它只测量元素的实际高度,包括任何垂直填充和边框。

另一方面,适当命名的 ScrollHeight 属性将计算元素的完整高度,包括可滚动(或隐藏)区域:

let op = document.querySelector('output');op.innerHTML = `Left column scrollHeight value: 
${document.querySelector('.col1').scrollHeight}px&lt;br&gt;
Right column scrollHeight value:
${document.querySelector('.col1').scrollHeight}px
`;

上面的演示与前面的演示相同,只是它使用了 ScrollHeights 来获取每列的高度。请再次注意,两列的值相同。但这一次它是一个更高的数字,因为溢出面积也被算作高度的一部分。

上面的例子集中在元素高度上,这是最常见的用例,但是您也可以使用 offsetwidth 和 scrollwidth,这将以与水平滚动相同的方式应用。

结论

这就是 DOM 特性列表,这些可能是我在过去几年中遇到的最有趣的特性之一,所以我希望其中至少有一个特性能在不久的将来在项目中使用。

如果您以前使用过其中一个,或者您能想到其中任何一个有趣的用例,请在评论中告诉我。

原文地址:

8 DOM features you didn’t know existed

如果您觉得本文不错,

请点击文章底部广告,支持一下我啦!

原创系列推荐

1. JavaScript 重温系列(22篇全)

2. ECMAScript 重温系列(10篇全)

3. JavaScript设计模式 重温系列(9篇全)

4. 正则 / 框架 / 算法等 重温系列(16篇全)

5. Webpack4 入门手册(共 18 章)(上)

6. Webpack4 入门手册(共 18 章)(下)

7. 59篇原创系列汇总

点这,与大家一起分享本文吧~

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,083
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,558
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,407
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,180
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,817
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,900