导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

什么是文档碎片?

var oFragmeng = document.createDocumentFragment();
for(var i=0;i<10000;i++)
{

    var op = document.createElement("span");

    var oText = document.createTextNode(i);

    op.appendChild(oText);

    //先附加在文档碎片中

    oFragmeng.appendChild(op);

}
//最后一次性添加到document中
document.body.appendChild(oFragmeng);

⭐ JS 中元素视图的各个尺寸?

来源:https://zh.javascript.info/size-and-scroll

属性 说明
offsetLeft 获取当前元素到定位父节点的left方向的距离
offsetTop 获取当前元素到定位父节点的top方向的距离
offsetWidth 获取当前元素 width + 左右padding + 左右border-width
offsetHeight 获取当前元素 height + 上下padding + 上下border-width
clientWidth 获取当前元素 width + 左右padding
clientHeight 获取当前元素 height + 上下padding
scrollWidth 当前元素内容真实的宽度,内容不超出盒子宽度时为盒子的clientWidth
scrollHeight 当前元素内容真实的高度,内容不超出盒子高度时为盒子的clientHeight

https://codepen.io/JingW/pen/gOQRZaw

Window 视图的各个尺寸?

属性 说明
innerWidth innerWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏)
innerHeight innerWidth 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏)

Document 文档视图的各个尺寸?

属性 说明
document.documentElement.clientWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
document.documentElement.clientHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
document.documentElement.offsetHeight 获取整个文档的高度(包含body的margin)
document.body.offsetHeight 获取整个文档的高度(不包含body的margin)
document.documentElement.scrollTop 返回文档的滚动top方向的距离(当窗口发生滚动时值改变)
document.documentElement.scrollLeft 返回文档的滚动left方向的距离(当窗口发生滚动时值改变)

⭐ offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别

⭐ attribute 和 property 的区别

实际编程中,基本上的 DOM 操作都是使用 property 的点操作符。

只有两种情况不得不使用 attribute:

  1. 自定义HTML Attribute,因为它不能同步到 DOM property 上
  2. 访问内置的 HTML 标签的 Attribute ,这些 attribute 不能从 property 上同步过来,比如 input 标签的 value 值(可以用来检验 input 值是否变化)

原生 JS 添加 class 类

⭐ 判断元素是否出现在屏幕中

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    body {
      position: relative;
    }
    .box {
      width: 100px;
      height: 100px;
      background-color: pink;
    }
    p {
      width: 200px;
    }
  </style>
</head>
<body>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Rem corporis nostrum saepe. Odit nulla debitis vitae fugiat maiores voluptatem quibusdam quod fugit labore, sequi repellendus ullam facilis dolores quam blanditiis aperiam ab modi quia cumque! Sit sequi cum dolore et, doloremque labore mollitia illum laborum sint ab. Deleniti soluta voluptatem dolorum officiis cumque nostrum aut nobis debitis magni adipisci, consectetur, ea modi ullam recusandae quia facilis officia consequatur temporibus necessitatibus eos mollitia commodi tempore consequuntur illum! Asperiores, repellat libero consequuntur cupiditate laudantium rerum porro deleniti facilis omnis? Repellat tenetur, beatae facere nostrum consequatur dicta sequi, et placeat qui maiores vel impedit iusto expedita, est eligendi dolor at delectus commodi perspiciatis! Odio dolore unde odit libero, illo hic deleniti numquam facilis nobis nam quo velit fugiat sunt doloribus suscipit inventore? Ducimus recusandae minima nostrum obcaecati vitae aliquid tenetur beatae dolores aliquam inventore aperiam tempora, quae et aut voluptas! Eveniet porro maiores corporis dignissimos minima reiciendis facere eius vel at vitae fugiat eaque est ipsam exercitationem consequatur, explicabo hic earum impedit, numquam aliquid voluptas laborum. Non tempore, corrupti totam animi ab iste reiciendis rem ad nihil commodi omnis sed tenetur sapiente, consequatur quo reprehenderit doloremque! Voluptas autem explicabo dolor laboriosam ipsa. Error esse atque neque cum, nulla rem expedita quis? Placeat perspiciatis, beatae amet ipsam fuga sint consectetur itaque facilis quas explicabo accusantium impedit expedita esse nisi vero. Velit alias ratione ex ad accusamus tempora iste repellendus molestiae nihil neque? Ad excepturi deleniti maxime similique commodi, pariatur sequi dolore reiciendis laboriosam consectetur ea aut facilis neque at quod mollitia maiores unde quas ullam reprehenderit quam laudantium, nam architecto magnam. Unde architecto iste expedita recusandae porro reprehenderit inventore? Odio inventore numquam quo qui natus repellat mollitia quam dolor dolorum dicta maiores deleniti quia error itaque autem, voluptatibus iste optio adipisci quidem tempora id asperiores? Aperiam libero illum harum sunt dolor minima, dolorem sint quo veritatis omnis at ad inventore exercitationem. Iusto, voluptatem ipsam praesentium atque aspernatur, placeat nostrum accusamus commodi deleniti quam et. Iure pariatur officia a voluptatem eos, ipsam cupiditate voluptatum asperiores aut et commodi velit odio ullam harum dolores fuga, nobis saepe odit soluta nam molestiae. Cupiditate eius voluptates veritatis voluptatum aliquam voluptas itaque pariatur. Voluptas ipsam corrupti dolores fuga sint vero veniam facere, eius fugiat delectus beatae iusto iure autem laboriosam accusantium! Ratione molestiae voluptas explicabo facilis repellendus quasi iure exercitationem repellat culpa unde placeat maiores dolorum modi rerum consequatur, sequi illo cumque cum cupiditate nostrum magnam esse dolores! Quaerat sed aut mollitia nemo necessitatibus praesentium nisi sapiente, quia enim, officia dolore! Consequuntur est officiis, ullam impedit totam tenetur corrupti assumenda itaque temporibus quis deleniti esse. Dolorem maxime omnis quos alias itaque repellendus dolorum recusandae dolor, voluptatum quis facere quaerat tempore quisquam ullam autem, aperiam repellat? Quasi vitae amet praesentium. Ullam nobis laborum recusandae placeat laudantium. Eos optio dolore sequi ipsum autem dolor tempore, delectus tenetur temporibus animi fugit dolorum omnis voluptas dolorem porro doloribus nulla! Expedita vitae, veritatis officia dolores ullam laboriosam, fugiat accusamus reprehenderit voluptates, quibusdam corrupti voluptatem.</p>
  <div class="box"></div>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Rem corporis nostrum saepe. Odit nulla debitis vitae fugiat maiores voluptatem quibusdam quod fugit labore, sequi repellendus ullam facilis dolores quam blanditiis aperiam ab modi quia cumque! Sit sequi cum dolore et, doloremque labore mollitia illum laborum sint ab. Deleniti soluta voluptatem dolorum officiis cumque nostrum aut nobis debitis magni adipisci, consectetur, ea modi ullam recusandae quia facilis officia consequatur temporibus necessitatibus eos mollitia commodi tempore consequuntur illum! Asperiores, repellat libero consequuntur cupiditate laudantium rerum porro deleniti facilis omnis? Repellat tenetur, beatae facere nostrum consequatur dicta sequi, et placeat qui maiores vel impedit iusto expedita, est eligendi dolor at delectus commodi perspiciatis! Odio dolore unde odit libero, illo hic deleniti numquam facilis nobis nam quo velit fugiat sunt doloribus suscipit inventore? Ducimus recusandae minima nostrum obcaecati vitae aliquid tenetur beatae dolores aliquam inventore aperiam tempora, quae et aut voluptas! Eveniet porro maiores corporis dignissimos minima reiciendis facere eius vel at vitae fugiat eaque est ipsam exercitationem consequatur, explicabo hic earum impedit, numquam aliquid voluptas laborum. Non tempore, corrupti totam animi ab iste reiciendis rem ad nihil commodi omnis sed tenetur sapiente, consequatur quo reprehenderit doloremque! Voluptas autem explicabo dolor laboriosam ipsa. Error esse atque neque cum, nulla rem expedita quis? Placeat perspiciatis, beatae amet ipsam fuga sint consectetur itaque facilis quas explicabo accusantium impedit expedita esse nisi vero. Velit alias ratione ex ad accusamus tempora iste repellendus molestiae nihil neque? Ad excepturi deleniti maxime similique commodi, pariatur sequi dolore reiciendis laboriosam consectetur ea aut facilis neque at quod mollitia maiores unde quas ullam reprehenderit quam laudantium, nam architecto magnam. Unde architecto iste expedita recusandae porro reprehenderit inventore? Odio inventore numquam quo qui natus repellat mollitia quam dolor dolorum dicta maiores deleniti quia error itaque autem, voluptatibus iste optio adipisci quidem tempora id asperiores? Aperiam libero illum harum sunt dolor minima, dolorem sint quo veritatis omnis at ad inventore exercitationem. Iusto, voluptatem ipsam praesentium atque aspernatur, placeat nostrum accusamus commodi deleniti quam et. Iure pariatur officia a voluptatem eos, ipsam cupiditate voluptatum asperiores aut et commodi velit odio ullam harum dolores fuga, nobis saepe odit soluta nam molestiae. Cupiditate eius voluptates veritatis voluptatum aliquam voluptas itaque pariatur. Voluptas ipsam corrupti dolores fuga sint vero veniam facere, eius fugiat delectus beatae iusto iure autem laboriosam accusantium! Ratione molestiae voluptas explicabo facilis repellendus quasi iure exercitationem repellat culpa unde placeat maiores dolorum modi rerum consequatur, sequi illo cumque cum cupiditate nostrum magnam esse dolores! Quaerat sed aut mollitia nemo necessitatibus praesentium nisi sapiente, quia enim, officia dolore! Consequuntur est officiis, ullam impedit totam tenetur corrupti assumenda itaque temporibus quis deleniti esse. Dolorem maxime omnis quos alias itaque repellendus dolorum recusandae dolor, voluptatum quis facere quaerat tempore quisquam ullam autem, aperiam repellat? Quasi vitae amet praesentium. Ullam nobis laborum recusandae placeat laudantium. Eos optio dolore sequi ipsum autem dolor tempore, delectus tenetur temporibus animi fugit dolorum omnis voluptas dolorem porro doloribus nulla! Expedita vitae, veritatis officia dolores ullam laboriosam, fugiat accusamus reprehenderit voluptates, quibusdam corrupti voluptatem.</p>

  <script>
    const box = document.getElementsByClassName('box')[0];
    function getViewportSize() {
      if (window.innerWidth) {
        return {
          width: window.innerWidth,
          height: window.innerHeight
        }
      } else {
        if (document.compatMode === 'BackCompat') {
          return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
          }
        } else {
          return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
          }
        }
      }
    }
    function getScrollOffset() {
      if (window.pageXOffset) {
        return {
          left: window.pageXOffset,
          top: window.pageYOffset
        }
      } else {
        return {
          left: document.body.scrollLeft + document.documentElement.scrollLeft,
          top: document.body.scrollTop + document.documentElement.scrollTop
        }
      }
    }
    function show(ele) {
      // 元素距离body距离 < 滚动条距离顶部距离 + 浏览器高度 && 元素距离body距离 + 自身高度 > 滚动条距离顶部距离
      return ele.offsetTop < getScrollOffset().top + getViewportSize().height && ele.offsetTop + parseInt(ele.getBoundingClientRect().height) >= getScrollOffset().top
    }
    document.onscroll = function() {
      console.log(show(box) ? '出现' : '消失');
    }
  </script>
</body>
</html>

⭐ 编写一个可拖拽的 div

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>编写一个可拖拽 div</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      .box {
        position: absolute;
        left: 0;
        top: 0;
        background-color: orange;
        width: 100px;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="box"></div>
    <script>
      function getScrollOffset() {
        if (window.pageXOffset) {
          return {
            left: window.pageXOffset,
            top: window.pageYOffset
          }
        } else {
          return {
            left: document.body.scrollLeft + document.documentElement.scrollLeft,
            top: document.body.scrollTop + document.documentElement.scrollTop
          }
        }
      }

      function pagePos(e) {
        var sLeft = getScrollOffset().left,
            sTop = getScrollOffset().top,
            cLeft = document.documentElement.clientLeft || 0,
            cTop = document.documentElement.clientTop || 0;

        return {
          X: e.clientX + sLeft - cLeft,
          Y: e.clientY + sTop - cTop
        } // 也可以直接 X: e.clientX/Y: e.clientY
      }

      function getStyles(elem, prop) {
        if (window.getComputedStyle) {
          if (prop) {
            return window.getComputedStyle(elem, null)[prop];
          } else {
            return window.getComputedStyle(elem, null);
          }
        } else {
          if (prop) {
            return window.currentStyle(elem, null)[prop];
          } else {
            return window.currentStyle(elem, null);
          }
        }
      }

      var box = document.getElementsByClassName("box")[0];

      box.onmousedown = function(e) {
        var e = e || window.event;
        // 鼠标离文档左侧距离 - box离文档左侧距离 = 鼠标距box左边缘距离
        var x = pagePos(e).X - parseInt(getStyles(box, 'left')),
            y = pagePos(e).Y - parseInt(getStyles(box, 'top'));

        document.onmousemove = function(e) {
          var e = e || window.event;
          // 每次再把x,y这段距离减去
          box.style.left = pagePos(e).X - x + 'px';
          box.style.top = pagePos(e).Y - y + 'px';
        }

        document.onmouseup = function(e) {
          this.onmousemove = null;
          this.onmouseup = null;
        }
      }
    </script>
  </body>
</html>

原型上编程,判断父元素有没有子元素节点

HTMLElement.prototype.hasChildren = function() {
  var children = this.childNodes;
  for (var i = 0; i < children.length; i++) {
    const child = children[i];
    if (child.nodeType === 1) {
      return true;
    } else {
      continue;
    }
  }
  return false;
}

⭐️ 寻找兄弟元素节点,参数为正找之后的第 n 个,参数为负,找之前的第 n 个,参数为0,找到自己

HTMLElement.prototype.findSibling = function(num) {
  var parentEle = this.parentNode,
      childrenEle = parentEle.childNodes,
      targetNode,
      tempNode;

  if (typeof num === 'undefined' || typeof num !== 'number' || num === 0) {
    return this;
  } else if (num > 0) { // 大于0
    tempNode = this;
    while (num > 0) {
      targetNode = tempNode.nextSibling;
      tempNode = targetNode;
      num--;
    }
  } else { // 小于0
    tempNode = this;
    while (num < 0) {
      targetNode = tempNode.previousSibling;
      tempNode = targetNode;
      num++;
    }
  }

  return targetNode;
}

遍历一个父级元素下面所有的子元素节点

HTMLElement.prototype.getAllElementChildren = function() {
  var ownChildNodes = this.childNodes,
      elementChildren = [];

  for (var i = 0; i < ownChildNodes.length; i++) {
    var nodeItem = ownChildNodes[i];

    if (nodeItem.nodeType === 1) {
      var subElementChildren = nodeItem.getAllElementChildren();
      if (subElementChildren.length > 0) {
        elementChildren.push(nodeItem, ...subElementChildren);
      } else {
        elementChildren.push(nodeItem);
      }
    }
  }

  return elementChildren;
}

⭐ 封装 insertAfter 方法

HTMLElement.prototype.insertAfter = function(target, afterNode) {
  var nextElem = afterNode.nextElementSibling;
  if (nextElem) {
    this.insertBefore(target, nextElem);
  } else {
    this.appendChild(target);
  }
}

⭐️ 子元素逆序排序

HTMLElement.prototype.reverseElement = function() {
  var childElem = this.children,
      childrenLen = childElem.length,
      fragment = document.createDocumentFragment();

  for (var i = childrenLen - 1; i >= 0; i--) {
    fragment.appendChild(childElem[i]);
  }

  this.appendChild(fragment);
}

⭐ mouseover 和 mouseenter 的区别

参考:JavaScript中的mouseover与mouseenter,mouseout和mouseleave的区别

input 搜索如何处理中文输入

其实看过 elementui 框架源码的童鞋都应该知道,elementui 是通过 compositionstart & compositionend 做的中文输入处理:

<input
	ref="input"
	@compositionstart="handleComposition"
	@compositionupdate="handleComposition"
	@compositionend="handleComposition">

这3个方法是原生的方法,这里简单介绍下,官方定义如下 compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)

简单来说就是切换中文输入法时在打拼音时 (此时 input 内还没有填入真正的内容) ,会首先触发 compositionstart,然后每打一个拼音字母,触发 compositionupdate,最后将输入好的中文填入 input 中时触发 compositionend。触发 compositionstart 时,文本框会填入 “虚拟文本”(待确认文本),同时触发 input 事件;在触发 compositionend 时,就是填入实际内容后(已确认文本),所以这里如果不想触发 input 事件的话就得设置一个 bool 变量来控制。

Untitled

根据上图可以看到

输入到input框触发 input 事件

失去焦点后内容有改变触发 change 事件

识别到你开始使用中文输入法触发 compositionstart 事件未输入结束但还在输入中触发 compositionupdate 事件

输入完成(也就是我们回车或者选择了对应的文字插入到输入框的时刻)触发 compositionend 事件。

那么问题来了 使用这几个事件能做什么?

因为 input 组件常常跟 form 表单一起出现,需要做表单验证

Untitled

为了解决中文输入法输入内容时还没将中文插入到输入框就验证的问题

我们希望中文输入完成以后才验证

题目来源:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/129