Dom、事件

问答

一、dom对象的innerText和innerHTML有什么区别?

  • innerText
    innerText是一个可写属性,返回元素内包含的文本内容,在多层次的时候会按照元素由浅到深的顺序拼接其内容。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>innerText</title>
</head>
<body>
  <div>
    <p>
      123
      <span>456</span>
    </p>
  </div>
</body>
</html>

外层div的innerText返回内容是 "123456"


innerText
  • innerHTML
    innerHTML和innerText的作用类似,但是它不是返回元素的文本内容,而是返回元素的HTML结构。


    innerHTML

二、elem.children和elem.childNodes的区别?

  • elem.children
    elem.children是一个只读属性,对象类型为HTMLCollection
    ,返回一个包含当前元素的子元素的集合。非元素的部分,比如空格、换行、或者单纯的文字不返回(文本节点以外的其他HTML节点)。
  • elem.chilNodes
    elem.chilNodes是获取包括文本节点的所有子元素列表(NodeList)。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Element</title>
</head>
<body>
  <div>
    <p id="desp">
      <span>1</span>
    </p>
    <!-- <p class="desp">段落2<span>2</span></p>
    <p class="desp">段落3<span>3</span></p> -->
  </div>
  <script>
    var p = document.getElementById('desp');
    console.log(p);
    console.log(p.children);
    console.log(p.children[0]);
    console.log(p.childNodes);
    console.log(p.childNodes[0]);
  </script>
</body>
</html>
对比

一般来说,elem.children更稳妥一些。如上面结果所示,使用elem.chilNodes获取的第一个元素不是span,而是回车符(相当于文本字符)。

三、查询元素有几种常见的方法?

  • getElementById()
    返回匹配指定ID属性的元素节点,如果没有匹配的节点,则返回null。这是获取元素最快的方法。
var elem = document.getElementById('ct');
  • getElementsByClassName()
    返回一个类似数组的对象(HTMLCollection类型的对象),包括了所有class名字符合指定条件的元素(搜索范围包括本身),元素的变化实时反映在返回结果中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。
var elements = document.getElementsByClassName('desp');

getElementsByClassName方法的参数,可以是多个空格分隔的class名字,返回同时具有这些节点的元素。

var elements = document.getElementsByClassName('test desp');
  • getElementsByTagName()
    返回所有指定标签的元素(搜索范围包括本身),返回值是一个HTMLCollection对象,也就是说,搜索结果是一个动态集合,任何元素的变化都会实时反映在返回的集合中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。注意:此方法会将参数转换为小写后再进行搜索。
var elements = document.getElementsByTagName('p');
  • getElementsByName()
    返回具有name属性的HTML元素,比如form、img、frame、embed和object,返回NodeList格式的对象,也就是说不会实时的反应元素的变化。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
    <form name="myForm" action="/test/6.php" method="post">
        姓名:<input name="username" type="text" placeholder="用户名" value="hello" maxlength=10 />  <br/>
        密码:<input name="pwd" type="text" placeholder="密码" maxlength=10 disabled />  <br/>
        性别:<input type="radio" name="sex" value="male" /> 男
              <input type="radio" name="sex" value="female" /> 女 <br/>
        爱好:<input type="checkbox" name="bike" checked />自行车
              <input type="checkbox" name="car" checked />汽车
    </form>
  <script>
    var forms = document.getElementsByName("username");
    console.log(forms);
    console.log(forms[0].tagName);
  </script>
</body>
</html>
结果

注意:在IE浏览器使用这个方法,会将没有name属性、但有同名id属性的元素也返回,所以name和id属性最好设为不一样的值。

  • querySelector()
    返回匹配指定CSS选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有匹配的节点,则返回null。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div class="user-panel main">
    <input name="login"/>
</div>
<script>
    var el = document.querySelector("div.user-panel input[name=login]");
    console.log(el);
</script>
</body>
</html>
input标签被打印
  • querySelectorAll()
    返回匹配指定CSS选择器的所有节点,返回的是NodeList类型的对象。
var matches = document.querySelectorAll("div.note, div.alert"); // 返回class属性为note或者alert的div元素
  • elementFromPoint()
    返回位于页面指定位置的元素。如果该元素不可返回(比如文本框的滚动条),则返回它的父元素;如果坐标无意义,则返回null。
var ele = document.elementFromPoint(x, y); // x,y分别是相对于当前窗口左上角的横坐标和纵坐标,单位是CSS像素。

四、如何创建一个元素?如何给元素设置属性?

1、创建元素

  • createElement()
    createElement用来生成HTML元素节点,参数为元素的标签名,即元素的tagName属性。如果传入的为大写的标签名,则会被转换为小写。如果参数带有尖括号(即<和>)或者是null,会报错。
var newDiv = document.createElement('div');
  • createTextNode()
    用来生成文本节点,参数为文本节点的内容。
var newDiv = document.createElement('div');
var newContent = document.createTextNode('我是div');
  • createDocumentFragment()
    用于生成一个DocumentFragment对象。DocumentFragment可以提供一个缓冲的机制,将DOM节点先放到内存中,当节点都构造完成后,再将DocumentFragment对象添加到页面中,这时所有的节点都会一次渲染出来,这样就能减少浏览器很多的负担,明显的提高页面渲染速度。
var fragment = document.createDocumentFragment();

2、给元素设置属性
setAttribute()可以用来给元素设置属性。

  <div id='ct'>Hello</div>
  <script>
    var el = document.getElementById('ct');
    el.setAttribute('myAttribute', 'newVal');
  </script>

五、元素的添加、删除?

1、元素的添加

  • appendChild()
    用于向节点添加最后一个子节点。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <ul class="ct">
      <li class="item"><span class="s">1</span>1</li>
      <li class="item"><span class="s">4</span>4</li>
      <li class="item"><span class="s">3</span>3</li>
      <li class="item"><span class="s">2</span>2</li>
    </ul>
</body>
<script>
    var items = document.querySelectorAll('.item');
    var itemsArr = [];
    for(var i=0;i<items.length;i++)
    {
      itemsArr.push(items[i]);
    }
    itemsArr.sort(function(a, b){
      return parseInt(a.children[0].innerText) - parseInt(b.children[0].innerText);
    })
    for(var i=0;i<itemsArr.length;i++)
    {
      document.querySelector('.ct').appendChild(itemsArr[i]);
    }
</script>
</html>
  • insertBefore()
    在某个元素之前插入元素。
<div id="ct">
    <p>1</p>
    <p>2</p>
</div>
<script>
    var span = document.createElement('span');
    var el = document.getElementById('ct');
    el.insertBefore(span, el.firstChild); // 在<p>1</p>前插入
</script>

2、元素的删除
removeChild()

六、DOM0 事件和DOM2级在事件监听使用方式上有什么区别?

  • DOM0
    DOM0级事件处理程序是将一个函数赋值给一个事件处理程序属性,而通过将事件处理程序设置为null删除绑定在元素上的事件处理程序。无法给一个事件添加多个事件处理程序,后面的程序会覆盖前面的程序。
<input id='btn' type='button' value='click me...' />

<script type="text/javascript">
  var btnClick = document.getElementById('btn');
  // 添加事件处理程序
  btnClick.onclick = function () {
    alert (this.id);
  };
  // 删除事件处理程序
  btnClick.onclick = null;
</script>
  • DOM2
    DOM2级事件定义了两个方法用于添加和删除事件处理程序的操作:addEventListenerremoveEventListener。所有DOM节点都包含这两个方法,它们接受三个参数:事件类型、事件处理方法、布尔参数(true,表示在捕获阶段调用事件处理程序;false:表示在事件冒泡阶段处理)。
<input id='btn' typ='button' value='click me...' />
 <script type="text/javascript">
    var btnClick = document.querySelector('#btn');
    btnClick.addEventListener('click', function(){
      alert(this.id);
    }, false);
  // 可以为click事件添加多个处理程序
  btnClick.addEventListener('click', function(){
    alert('Hello');
}, false);
</script>

通过addEventListener添加的事件处理程序只能通过removeListener移除,移除时参数与添加的时候相同,这就意味着刚才我们添加的匿名函数无法移除。因为匿名函数虽然方法体一样,但是句柄却不相同。所以可以如下实现:

<input id="btn" type="button" value="Click Here" />
<script type="text/javascript">
    var btnClick = document.getElementById('btn');
    var handler=function() {
        alert(this.id);
    }
    btnClick.addEventListener('click', handler, false);
    btnClick.removeEventListener('click', handler, false);
</script>

七、attachEvent与addEventListener的区别?

IE不支持addEventListener和removeListener,而是实现了两个类似的方法:attachEvent和detachEvent。
attachEvent与addEventListener的区别:

  • 参数个数不同
    addEventListener有三个参数,attachEvent只有两个。attachEvent添加事件处理程序只能发生在冒泡阶段,addEventListener第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理。
  • 第一个参数意义不同
    addEventListener第一个参数是事件类型(click),而attachEvent第一个参数是事件处理函数名称(onclick)。
  • 事件处理程序的作用域不相同
    addEventListener作用域是元素本身,this指的是触发的元素。而attachEvent事件处理程序会在全局变量内运行,事件处理程序会在全局变量内运行。
  • 为一个事件添加多个事件处理程序时,执行顺序不同
    addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律。

八、解释IE事件冒泡和DOM2事件传播机制?

  • IE事件冒泡
    事件由最具体的元素接收,然后逐级向上传播到较为不具体的元素。
  • DOM2事件传播机制
    DOM2事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的是事件捕获阶段,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段。

九、如何阻止事件冒泡? 如何阻止默认事件?

  • 阻止事件冒泡
    当bubbles为true时,可以通过stopPropagation()方法阻止事件冒泡。
  • 阻止默认事件
    当cancelable为true时,可以通过preventDefault()方法阻止默认事件。
<div id="ct">
  <button id="btn">点我</button>
  <a id='link' target="_blank" href='www.baidu.com'>百度</a>
</div>
<script type="text/javascript">
  var wrap = document.querySelector('#ct');
  var btn = document.querySelector('#btn');
  var link = document.querySelector('#link');
  wrap.addEventListener('click', function(e){
    console.log(this.id);
  }, false);
  btn.addEventListener('click', function(e){
    console.log(this.id);
    e.stopPropagation();
  }, false);
  link.addEventListener('click', function(e){
    console.log(this.id);
    e.preventDefault();
  }, false);
</script>

代码

一、有如下代码,要求当点击每一个元素li时控制台展示该元素的文本内容。不考虑兼容

<ul class="ct">
    <li>苹果</li>
    <li>橘子</li>
    <li>香蕉</li>
</ul>
<script>
//todo ...
</script>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>one</title>
</head>
<body>
  <ul class="ct">
    <li>苹果</li>
    <li>橘子</li>
    <li>香蕉</li>
</ul>
<script>
  var ct = document.getElementsByClassName('ct')[0];
  ct.addEventListener('click', function(e){
    console.log(e.target.innerText);
  }, false);
</script>
</body>
</html>

二、补全代码,要求:

  • 当点击按钮开头添加时在<li>苹果</li>元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在<li>香蕉</li>后添加用户输入的非空字符串.
  • 当点击每一个元素li时控制台展示该元素的文本内容。
<ul class="ct">
    <li>苹果</li>
    <li>橘子</li>
    <li>香蕉</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
//todo ...
</script>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>second</title>
</head>
<body>
  <ul class="ct">
    <li>苹果</li>
    <li>橘子</li>
    <li>香蕉</li>
  </ul>
  <input class="ipt-add-content" placeholder="添加内容"/>
  <button id="btn-add-start">开头添加</button>
  <button id="btn-add-end">结尾添加</button>
  <script>
    // 获取input的输入值
    var value;
    var input = document.getElementsByClassName('ipt-add-content')[0];
    input.addEventListener('change', function(e){
      value = e.target.value;
    }, false);
    document.body.addEventListener('click', function(e){
      // 增加元素
      var ct = document.getElementsByClassName('ct')[0];
      var li = document.createElement('li');
      var content = document.createTextNode(value);
      li.appendChild(content);
      if(e.target.id == 'btn-add-start')
      {
        var addStart = document.getElementById('btn-add-start');
        var eleStart =  ct.children[0];
        if(!value)
        {
          alert('输入内容不能为空');
          return;
        }
        ct.insertBefore(li, eleStart);
      }
      if(e.target.id == 'btn-add-end')
      {
        if(!value)
        {
          alert('输入内容不能为空');
          return;
        }
        ct.appendChild(li);
      }
      console.log(e);
      // 点击li打印文本内容
      if(e.target.tagName.toLowerCase() == 'li')
      {
        console.log(e.target.innerText);
      }
    }, false);
  </script>
</body>
</html>

预览

三、补全代码,要求:当鼠标放置在li元素上,会在img-preview里展示当前li元素的data-img对应的图片。

<ul class="ct">
    <li data-img="1.png">鼠标放置查看图片1</li>
    <li data-img="2.png">鼠标放置查看图片2</li>
    <li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
//todo ...
</script>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>third</title>
</head>
<body>
  <ul class="ct">
    <li data-img="http://ww3.sinaimg.cn/bmiddle/68bf4cd7ly1fb9899g6bij226k3vj7wp.jpg">鼠标放置查看图片1</li>
    <li data-img="http://ww2.sinaimg.cn/bmiddle/68bf4cd7ly1fb98bn69t6j21111trqva.jpg">鼠标放置查看图片2</li>
    <li data-img="http://ww3.sinaimg.cn/bmiddle/68bf4cd7ly1fb98bzvmzbj21ww2pfe82.jpg">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
  var ct = document.querySelector('.ct');
  console.log(ct);
  var preview = document.querySelector('.img-preview');
  ct.addEventListener('mouseover', function(e){
    var url = e.target.getAttribute('data-img');
    preview.innerHTML = `<img src= "${url}" />`;
  }, false);
</script>
</body>
</html>

预览

四、实现如下图Tab切换的功能。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>fourth</title>
  <style>
    html, body, ul, li{
      margin: 0;
      padding: 0;
    }
    li{
      list-style: none;
    }
    a{
      text-decoration: none;
      color: black;
    }
    .ct{
      height: 210px;
      width: 600px;
      border: 2px solid #ccc;
      font-weight: 600;
    }
    .nav > li{
      float: left;
      width: 200px;
      line-height: 30px;
      border-bottom: 2px solid #ccc;
      text-align: center;
    }
    .nav>li:hover{
      background: #ededed;
    }
  </style>
</head>
<body>
  <div class='ct'>
    <ul class='nav'>
      <li><a href='#'>tab1</a></li>
      <li><a href="#">tab2</a></li>
      <li><a href="#">tab3</a></li>
    </ul>
    <div class='content'>内容1</div>
  </div>
  <script>
    var tab = document.querySelector('.ct');
    var contentTag = document.querySelector('.content');
    tab.addEventListener('click', function(e){
      var value = e.target.innerText;
      switch(value)
      {
        case 'tab1':
          contentTag.innerText = '内容1';
          break;
        case 'tab2':
          contentTag.innerText = '内容2';
          break;
        case 'tab3':
          contentTag.innerText = '内容3';
          break;
      }
    }, false);
  </script>
</body>
</html>

预览

五、实现下图的模态框功能。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>fifth</title>
  <style>
    *{
      margin: 0px;
      padding: 0px;
    }
    a{
      text-decoration: none;
      color: black;
    }
    hr{
      border-color: #fff;
    }
    .clearFix:after{
      content: '';
      display: block;
      clear: both;
    }
    .cover{
      background: black;
      position: fixed;
      top: 0;
      left: 0;
      opacity: 0.3;
      width: 100vw;
        height: 100vh;
      display: none;
    }
    .modal{
      position: absolute;
      top: 50%;
      left: 50%;
      width: 400px;
      transform: translate(-50%, -50%);  //绝对定位+transform, 只需设置宽度,高度自适应
      z-index: 1;
      border-radius: 4px;
      font-size: 18px;
      padding: 0 3px;
      background: #fff;
      display: none;
    }
    .header{
      height: 40px;
      line-height: 40px;
    }
    .header>h3{
      float: left;
    }
    .close{
      float: right;
    }
    .content{
      margin: 10px 0px;
      line-height: 36px;
    }
    .footer{
      float: right;
      height: 40px;
      line-height: 40px;
    }
    .footer>a{

    }
  </style>
</head>
<body>
  <button class='showModal'>点我1</button>
  <div class='cover'></div>
  <div class='modal'>
    <div class='header clearFix'>
      <h3>我是标题1</h3>
      <a class='close' href='#'>×</a>
    </div>
    <hr>
    <div class='content'>
      <p>我是内容1</p>
      <p>我是内容1</p>
    </div>
    <hr>
    <div class='footer clearFix'>
      <a class='cancel' href='#'>取消</a>
      <a class='confirm' href='#'>确定</a>
    </div>
  </div>

  <script>
    var btn = document.querySelector('.showModal'),
        modal = document.querySelector('.modal'),
        cover = document.querySelector('.cover'),
        close = document.querySelector('.close'),
        cancel = document.querySelector('.cancel');
    function showModal() {
      modal.style.display = 'block';
      cover.style.display = 'block';
    }
    function cancelModal() {
      modal.style.display = 'none';
      cover.style.display = 'none';
    }
    btn.addEventListener('click', function(e){
      showModal();
    }, false);
    cover.addEventListener('click', function(e){
      cancelModal();
    }, false);
    close.addEventListener('click', function(e){
      cancelModal();
    }, false);
    cancel.addEventListener('click', function(e){
      cancelModal();
    }, false);
  </script>
</body>
</html>

预览

由于预览好像有问题就放在js bin上面了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 1.dom对象的innerText和innerHTML有什么区别? innerText是一个可写属性,返回元素内包...
    GarenWang阅读 451评论 0 0
  • 1.dom对象的innerText和innerHTML有什么区别? innerText是一个可写属性。将写入的内容...
    candy252324阅读 527评论 0 0
  • DOM0 事件和DOM2级在事件监听使用方式上有什么区别? DOM 0 级事件是基于元素内联属性或DOM元素命名的...
    邢烽朔阅读 332评论 0 0
  • 2017.10.31。无为。焦点解决分享第87天.。人这一辈子,活得不容易,要想与众不同,就要含辛茹苦,就要忍辱负...
    无为wyw阅读 117评论 1 2
  • 车窗外两边的树飞快往后去了,天阴沉沉的,微微有点晕车的我听着音乐瞌睡死了,前途未卜独思量。旁边的大爷时而打盹,时而...
    a1f3fb911c82阅读 272评论 0 0