zoukankan      html  css  js  c++  java
  • 【JS】328- 8个你不知道的DOM功能

    最近一直在关注工具,从 React 和 npm-install-everything 中休息一下,看看一些原生的 DOMWeb 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 、mouseupmousedown )时,这些事件称为 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 特性列表,这些可能是我在过去几年中遇到的最有趣的特性之一,所以我希望其中至少有一个特性能在不久的将来在项目中使用。

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

    原文地址:

    https://blog.logrocket.com/8-dom-features-you-didnt-know-existed-ec2a0a28fd89/

    640?wx_fmt=png

    如果您觉得本文不错,

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


    原创系列推荐

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

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

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

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

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

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

    7. 59篇原创系列汇总

    640?wx_fmt=png

    640?wx_fmt=png

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

    个人博客:http://www.pingan8787.com 微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。 目前已连续推送文章 600+ 天,愿每个人的初心都能一直坚持下去!
  • 相关阅读:
    Mtk Ft6306 touch 驱动 .
    第一屏不显示懒加载的图片内容,这个方法可以搞定
    C#多线程中访问winform控件 (解决Winform 对象当前正在其他地方使用)
    变化的科技感十足的网站,推荐
    新年有感
    获取高精度时间注意事项 (QueryPerformanceCounter , QueryPerformanceFrequency)
    修改 TeamViewer ID 的方法
    VS2017离线安装包[百度云盘](收藏了)
    老子今天不加班,程序员也需要自由
    改变Eclipse 中代码字体大小
  • 原文地址:https://www.cnblogs.com/pingan8787/p/11838115.html
Copyright © 2011-2022 走看看