DOM模型

DOM模型

DOM:文档对象模型( Document Object Model ),它的作用是将网页转为一个 js 对象

节点 Node

DOM最小组成单位叫做节点

节点的类型有七种:

  • Document:整个文档节点(包含整个节点树)
  • DocumentType:文档声明类型 <!DOCTYPE html>
  • Element:元素节点,网页的各种HTML标签(<body>divimg等等)
  • Attribute:网页元素的属性(比如class="right"
  • Text:标签之间或标签包含的文本
  • Comment:注释
  • DocumentFragment:文档的片段
根节点

document 根节点,文档的第一层只有一个节点

节点的关系

除了根节点,其他节点都有三种层级关系。

  • 父节点关系
<!-- button的直接父节点是div -->
<div>
  <button>按钮</button>
</div>
  • 子节点关系
<!-- div的直接子节点是button -->
<div>
  <button>按钮</button>
</div>
  • 同级节点关系
<!-- button的同级节点是h2 -->
<div>
  <button>按钮</button>
  <h2>标题2</h2>
</div>
Node 接口的属性

所有 DOM 节点都继承了 Node 接口

  • Node.nodeType:

返回一个整数值,表示节点的类型,有以下类型:

  1. document:9 表示 文档
  2. element: 1 表示 元素
  3. attr: 2 表示 属性
  4. text: 3 表示 文本
  5. DocumentFragment: 11 表示 文档片段
  6. DocumentType: 10 表示 文档类型
  7. Comment: 8 表示 注释
<div id="box">你好</div>
<script>
  var box = document.getElementById('box');
  console.log( box.nodeType ); //1 元素
  console.log( box.childNodes[0].nodeType );//3 文本
</script>
  • Node.nodeName:
<div id="box">你好</div>
<script>
  var box = document.getElementById('box');
  console.log( box.nodeName ); //DIV 默认是大写
  console.log( box.childNodes[0].nodeName );//#text
</script>
  • Node.nodeValue

nodeValue属性返回一个字符串,表示当前节点本身的文本值

注意:该属性主要用于文本节点

var box = document.getElementById('box');
console.log( box.nodeValue );//null
console.log( box.childNodes[0].nodeValue );//您好
  • Node.textContent:

textContent属性返回当前节点和它的所有后代节点的文本内容。

自动忽略当前节点内部的HTML标签,提取文本内容,它和innerText功能一样

该属性可读可写

<div id="box">
  您好
  <p>
    张三
  </p>
</div>

<script>
  var box = document.getElementById('box');
  console.log( box.textContent );// 您好 张三
</script>
  • Node.baseURI

返回一个字符串,表示当前网页的绝对路径

会受<base href="#"> 基础地址影响,而location.href不会。

console.log( document.baseURI );
//file:///F:/studyspace/web1905/javascript/dom.html

console.log( window.location.href );
//file:///F:/studyspace/web1905/javascript/dom.html
  • Node.ownerDocument

返回当前节点所在的顶层文档对象,即document对象。

<div id="box">

</div>

<script>
  var box = document.getElementById('box');
  console.log( box.ownerDocument == document );//true
</script>
节点关系查找
父节点关系
  • Node.childNodes:

    父节点下所有的子节点,注意包含文本、注释、元素节点

  • Node.children:

    父节点下所有的子元素节点,只是元素节点

  <ul id="box">
  <li>一分</li>
  <li>二分</li>
  <li>三分</li>
  <li>四分</li>
  <li>五分</li>
</ul>

<script>
var box = document.getElementById('box');
var lis1 = box.childNodes;
var lis2 = box.children;

console.log( lis1, lis2);
</script>
子节点关系
  • parentNode

    当前节点的直接的父节点

  • parentElement

    当前节点的直接的父元素节点

<div>
  <span>
    <button id="btn">按钮</button>
  </span>
</div>

<script>
document.getElementById('btn').onclick = function(){
  var THIS = this;
  while( THIS.parentElement ){
    THIS = THIS.parentElement;
    if(THIS.nodeName == 'BODY'){
      THIS.style.backgroundColor='red';
    }
  }
}
</script>
同级节点关系
  • Node.nextSibling

    下一个节点,注意包含文本、注释、元素节点

  • Node.nextElementSibling:

    下一个元素节点,只是元素节点。

<button onclick="setBox(this)">按钮</button>
<div></div>

<script>
//单击按钮,给div设置宽200 高200 背景颜色红色
function setBox( btn ){
  btn.nextElementSibling.style.cssText = `width:200px;height:200px;background-color:red`;
}
</script>
  • Node.previousSibling

    上一个节点,注意包含文本、注释、元素节点

  • Node.previousElementSibling

    上一个元素节点,只是元素节点。

    综合的例子

  <ul>
  <li>一分</li>
  <li>二分</li>
  <li>三分</li>
  <li>四分</li>
  <li>五分</li>
</ul>

<script>
var lis = document.querySelectorAll('li');

lis.forEach( function( item ){

  item.onclick = function(){
    var THIS1 = this;
    var THIS2 = this;
    
    //查找当前元素往上的所有元素
    while( THIS1.previousElementSibling ){
      THIS1 = THIS1.previousElementSibling;
      THIS1.className = 'active' 
    }

    //查找当前元素往下的所有元素
    while( THIS2.nextElementSibling ){
      THIS2 = THIS2.nextElementSibling;
      THIS2.className = 'active' 
    }

  }

})
</script>

经典面试题:请用至少3种办法生成一个随机不重复的字符串

// 方法1
var id = new Date().getTime();
console.log( id );

// 方法2
var str = Math.random().toString(36).slice(2);
console.log(str);

// 方法3
var str = 'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ0123456789';
var arr = str.split('');
var newArr = arr.sort(function(){
  return .5 - Math.random();
}).slice(0,20);
console.log( newArr.join('') );

// 方法4
var str = 'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ0123456789';
var arr = str.split('');
var temp = '';
for(var i=0;i<arr.length;i++){
  var index = Math.floor(Math.random()*arr.length);
  temp += arr[index];
}
console.log( temp );
  • Node.isConnected

返回一个布尔值,表示当前节点是否在文档之中

<div id="box1"></div>

<script>
//文档本身就存在
var box1 = document.getElementById('box');
console.log( box1.isConnected );//true

//创建了元素,但是并没有插入到文档中
var box2 = document.createElement('div');
console.log( box2.isConnected );//false 
</script>
Node 接口的方法
  • document.createElement

在文档中创建一个元素

语法:

document.createElement('标签名');

示例

var div = document.createElement('div');
console.log( div );//<div></div>

综合示例

//1. 创建一个div元素
var div = document.createElement('div');

//2. 创建一个属性节点
var cls = document.createAttribute('class');

//3. 设置属性节点的值
cls.value = 'red';

//4. 把属性节点应用到目标元素上
div.setAttributeNode( cls );

//5. 创建注释
var zs = document.createComment('新的div');

//6. 将上面的注释添加到div的内部后面
div.appendChild( zs );

//7. 创建一个p标签
var p = document.createElement('p');

//8. 创建一个文本标签
var text = document.createTextNode('今天的天气有点阴沉!');

//9. 将文本节点追加到p标签内部的后面
p.appendChild( text );

//10. 将上面的p标签追加到div内部后面
div.appendChild( p );

//11. 输出新创建的节点
console.log( div );

使用JS标准API创建节点示例

<script>
var data = [
  {id:1,name:'首页',url:'#'},
  {id:2,name:'关于我们',url:'#', active: true},
  {id:3,name:'联系我们',url:'#'},
];

var div = document.createElement('div');
var divClass = document.createAttribute('class');
divClass.value = 'nav';

var divStyle = document.createAttribute('style');
divStyle.value = 'width:100px;';

div.setAttributeNode( divClass );

div.setAttributeNode( divStyle );

var ul = document.createElement('ul');

for(var i=0;i<data.length;i++){

  var li = document.createElement('li');
  var a = document.createElement('a');
  
  var aHref = document.createAttribute('href');
  aHref.value = data[i].url;
  a.setAttributeNode( aHref );

  if( data[i].active ){
    var aClass = document.createAttribute('class');
    aClass.value = 'active';
    a.setAttributeNode( aClass );
  }

  var text = document.createTextNode( data[i].name );

  a.appendChild( text );
  li.appendChild( a );
  ul.appendChild( li );
}

div.appendChild( ul );

document.getElementsByTagName('body')[0].appendChild( div );

</script>

示例

<button onclick="createBox()">创建盒子并附加样式</button>

<script>

function createBox(){
  
  var div = document.createElement('div');

  // var divClass = document.createAttribute('class');
  // divClass.value ='box';
  // div.setAttributeNode( divClass );

  //等同于上面的写法
  div.className = 'box';

  // var text = document.createTextNode('段落');
  // div.appendChild( text );

  //等同于上面的写法
  div.innerText = '段落';

  var style = document.createElement('style');
  style.innerHTML = `
  .box{
    width: 100px;
    height: 100px;
    background-color: red;
  }`;

  document.getElementsByTagName('head')[0].appendChild( style );

  document.getElementsByTagName('body')[0].appendChild( div );

}
</script>

页码示例

<div id="box1"></div>

<div id="box2"></div>

<script>

makePage( 'box1', 10, 1 );
makePage( 'box2', 5, 2 );

function makePage( id, totalPage, page=1 ){
  
  var target = document.getElementById( id );
  target.innerHTML = '';

  for(let p=1;p<=totalPage;p++){

    var btn = document.createElement('button');
    btn.innerText = p;
    if(p==page){
      btn.className = 'active';
    }

    //因为创建的是dom对象,该对象尚未插入到文档中,所以这里可以直接加上事件
    btn.onclick = function(){
      // console.log( p );
      makePage( id, totalPage, p );
    }

    target.appendChild( btn );

  }
}

</script>
  • Node.appendChild

往目标节点内部的后面插入新节点,返回被插入的新节点

var div = document.createElement('div');
div.innerText = '内容';
var text = document.createTextNode('段落');
div.appendChild( text );

console.log( div );// <div>内容段落</div>

穿梭框效果

 <style>
  ul{
    float: left;
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: auto;
    height: 200px;
    width: 160px;
    border: 1px solid #ccc;
    margin-right: 20px;
  }
  .btns{
    float: left;
    padding-top: 22px;
    width: 100px;
   
  }
  .btns button{
    margin-bottom: 20px;
  }
  ul li{
    line-height: 30px;
    font-size: 14px;
    padding: 0 10px;
    cursor: pointer;
  }
  ul li:nth-child(even){
    background-color: #eee;
  }
  ul li.active{
    background-color: rgb(2, 141, 255);
    color: white;
  }
  </style>
<h1>穿梭框效果</h1>

<ul id="left">
  <li>陈旻</li>
  <li>李杰</li>
  <li>曾崇博</li>
  <li>邓聪</li>
  <li>钟旺</li>
  <li>邓绍志</li>
  <li>刘江湖</li>
  <li>代晨</li>
</ul>

<div class="btns">
    <button onclick="addRightAll()"> 全部追加 </button>
    <button onclick="addRight()"> 向右添加 </button>
    <button onclick="addLeft()"> 向左添加 </button>
    <button onclick="addLeftAll()"> 全部移除 </button>
</div>

<ul id="right">

</ul>

<button onclick="getVal()">取值</button>

<script>
var left = document.getElementById('left');
var leftLis = left.children;

var right = document.getElementById('right');
var rightLis = right.children;

//添加单击选中事件
for(var i=0;i<leftLis.length;i++){
  leftLis[i].onclick = function(){
    this.classList.toggle('active');
  }
}

//向右追加全部
function addRightAll(){
  addItem( right,  leftLis, 'all' );
}

//向左移除全部
function addLeftAll(){
  addItem( left,  rightLis, 'all' );
}

//向右追加
function addRight(){
  addItem( right,  leftLis );
}

//向左追加
function addLeft(){
  addItem( left,  rightLis );
}

//追加li元素
function addItem( target,  lis, flag ){

  //倒着删除
  for( var i = lis.length-1; i >= 0 ; i-- ){
    if( lis[i].classList.contains('active') || flag == 'all' ){
      lis[i].classList.remove('active');
      target.appendChild( lis[i] );
    }
  }

}

//取值
function getVal(){
  var val = '';
  for( var i=0; i < rightLis.length; i++ ){
    val += rightLis[i].innerText+',';
  }
  val = val.slice(0, -1);
  alert( val );
}


</script>

代码片段

<div id="box">
</div>

<button onclick="add()">添加</button>

<script>
var box = document.getElementById('box');
function add(){

  var p = document.createElement('p');
  var span = document.createElement('span');
  var a = document.createElement('a');

  //创建一个代码片段节点,代码片段节点没有名称
  var fragment = document.createDocumentFragment();
  fragment.appendChild( p );
  fragment.appendChild( span );
  fragment.appendChild( a );

  box.appendChild( fragment );

}
</script>
  • Node.hasChildNodes

注意:节点包含7种类型

<div id="box">

</div>

<script>
var box = document.getElementById('box');
console.log( box.hasChildNodes() );//true 因为包含文本节点
</script>
  • Node.cloneNode

用于克隆一个节点。它接受一个布尔值作为参数,表示是否同时克隆子节点。它的返回值是一个克隆出来的新节点。

注意事项:

  • 克隆一个节点,会拷贝该节点的所有属性,但是会丧失事件方法
  • 该方法返回的节点不在文档之中,即没有任何父节点,必须使用诸如Node.appendChild这样的方法添加到文档之中。
  • 克隆一个节点之后,DOM 有可能出现两个有相同id属性
<span id="span">
  <b>文本</b>
</span>

<div id="div"></div>

<button onclick="copy()">复制文本</button>

<script>
function copy(){
  var span = document.getElementById('span');
  var div = document.getElementById('div');

  //复制节点,加true表示连同子节点一起复制
  var _span = span.cloneNode( true );

  div.appendChild( _span );

}

</script>
  • Node.insertBefore

用于将某个节点插入父节点内部的指定位置,给参考节点外部前面插入新节点。

语法:

父节点.insertBefore( 新节点, 参考节点);

示例

<button onclick="before( this )">按钮 </button>

<script>
function before( btn ){
  var parent = btn.parentNode;
  var p = document.createElement('p');
  p.innerText= '文本';
  parent.insertBefore( p, btn );
}
</script>
  • Node.removeChild

接受一个子节点作为参数,用于从当前节点移除该子节点。返回值是移除的子节点。

<ul id="nav">
  <li>首页 <button>删除</button></li>
  <li>关于我们 <button>删除</button></li>
  <li>联系我们 <button>删除</button></li>
</ul>

<script>
var nav = document.getElementById('nav');
var lis = nav.children;

for(var i=0;i<lis.length;i++){
  lis[i].lastElementChild.onclick = function(){
    if(confirm('您确定要删除此行吗?')){
      var li = this.parentNode;
      li.parentNode.removeChild( li );
    }
  }
}
</script>
  • Node.replaceChild()

用于将一个新的节点,替换当前节点的某一个子节点

<div>
  <button>修改</button>
</div>

<script>
var btn = document.getElementsByTagName('button')[0];
btn.onclick = function(){
  var newBtn = document.createElement('a');
  newBtn.innerText = '保存';
  newBtn.className = 'save';
  
  this.parentNode.replaceChild( newBtn, this);

  console.log( this );//button
}
  • Node.contains()

回一个布尔值,表示参数节点是否满足以下三个条件之一

<div id="box">
  <span id="span">
    <b id="b">文本</b>
  </span>
</div>

<h4 id="h4">标题4</h4>

<script>
var box = document.getElementById('box');
var span = document.getElementById('span');
var b = document.getElementById('b');
var h4 = document.getElementById('h4');

console.log( box.contains( box ) );// true 参数节点为当前节点
console.log( box.contains( span ) ); // true  参数节点为当前节点的子节点
console.log( box.contains( b ) ); //  true  参数节点为当前节点的后代节点
console.log( box.contains( h4 ) );// false 不符合以上3个条件
</script>
  • Node.isEqualNode(),Node.isSameNode()

isEqualNode方法返回一个布尔值,用于检查两个节点是否相等。所谓相等的节点,指的是两个节点的类型相同属性相同子节点相同。

<h1>标题1</h1>
<h1>标题1</h1>

<script>

var h1 = document.getElementsByTagName('h1')[0];
var h2 = document.getElementsByTagName('h1')[1];

console.log( h1.isEqualNode( h2 )  );//true
</script>

isSameNode方法返回一个布尔值,表示两个节点是否为同一个节点。

var p1 = document.createElement('p');
var p2 = document.createElement('p');

console.log( p1.isSameNode(p2) ) // false
console.log( p1.isSameNode(p1) ) // true
console.log( p1.isEqualNode(p2) ) // true
  • Node.normalize():

用于清理当前节点内部的所有文本节点,它会去除空的文本节点,并且将毗邻的文本节点合并成一个,也就是说不存在空的文本节点,以及毗邻的文本节点。

var div = document.createElement('div');
div.appendChild(document.createTextNode('部分1 '));
div.appendChild(document.createTextNode('部分2 '));

console.log( div );
div.normalize();
console.log( div );
  • Node.getRootNode()

返回当前节点所在文档的根节点。

<div id="nav">
  <ul>
    <li> <b id="b">首页</b></li>
    <li>关于</li>
    <li>练习</li>
  </ul>
</div>

<script>
var b = document.getElementById('b');
console.log( b.getRootNode() );//document
</script>
NodeList 接口

节点都是单个对象,有时需要一种数据结构,能够容纳多个节点。DOM 提供两种节点集合,用于容纳多个节点:NodeListHTMLCollection

NodeList内部有forEach方法,HTMLCollection没有此方法

NodeList是类数组,不能使用数组的方法。

通过以下方法可以得到NodeList实例。

  • Node.childNodes

  • document.querySelectorAll() 等节点搜索方法

  • forEach

forEach方法的第二个参数,用于绑定回调函数内部的this,该参数可省略。

<div id="nav">
  <ul>
    <li>首页</li>
    <li>关于</li>
    <li>练习</li>
  </ul>
</div>

<script>
var lis = document.querySelectorAll('li');
lis.forEach( function( item, ){
  console.log( item );
  console.log( this );// ['苹果','香蕉']
}, ['苹果','香蕉'] );

</script>
  • HTMLCollection 接口:

通过以下方法可以得到HTMLCollection实例。

  • document.links:得到文档中所有的超级链接
  • document.images:得到文档中所有的图像对象
  • document.forms:得到文档中所有的表单对象
  • document.scripts:得到文档中所有的script对象
  • document.styleSheets:得到文档中所有的style对象

获取所有超级链接集合

<a href="#">链接</a>
<p>
  <a href="#">链接</a>
</p>

<script>
var links = document.links;
console.log( links );
</script>

获取图像所有集合

<img src="images/a1.png">
<p>
  <img src="images/a1.png">
</p>

<script>
var images = document.images;
console.log( images );
</script>

图片预加载

<img src="images/2.png">
<p>
  <img src="images/a1.png">
</p>

<div>
    <img src="images/4.png">
</div>

<script>
//得到文档中图像集合
var images = document.images;

//循环每一张图像
for(let i=0; i<images.length; i++ ){

  //给每一张图像包装一个span标签
  var span = document.createElement('span');
  span.className = 'img';

  images[i].parentNode.insertBefore( span, images[i] );
  span.appendChild( images[i] );

  //如果图像加载完毕
  images[i].onload = function(){
    this.style.visibility = 'visible'; 
    var span = this.parentNode;
    span.parentNode.replaceChild(this, span);//替换
  }
  
} 

卸载外包裹

<div class="box">
  <span>
    <button id="btn">按钮</button>
  </span>
</div>

<script>
document.getElementById('btn').onclick = function(){
  var btn = this;
  var span = this.parentNode;
  span.parentNode.replaceChild( btn, span );
}
</script>

卸载内包裹

<button id="btn">按钮
  <i></i>
  <b>按钮</b>
</button>

<script>
document.getElementById('btn').onclick = function(){
  var b = this.lastElementChild;
  var bText = b.firstChild;
  b.parentNode.replaceChild( bText, b );
}
</script>

获取表单对象

<form name="form1" action="">
  <input type="text" name="username">
  <input type="text" name="password">
</form>

<form name="form2" action="">
  <input type="text" name="username">
  <input type="text" name="password">
</form>

<script>
var form1 = document.forms['form1'];
console.log( form1['username'], form1['password'] );

var form2 = document.forms['form2'];
console.log( form2['username'], form2['password'] );

</script>

批量验证表单示例

<form name="form1" action="http://www.baidu.com" method="post" autocomplete="off">
  用户:<input type="text" name="username" reg="^\w{3,10}$" required> <br>
  密码:<input type="text" name="password" reg="^\d{6,}$" required> <br>
  信息:<textarea name="msg" cols="30" rows="10" reg="" required></textarea> <br>
  <button type="button" onclick="submitForm()">提交</button>
</form>

<script>
function submitForm(){
  var form1 = document.forms['form1'];
  for( var i=0; i<form1.length; i++ ){
    if( form1[i].required ){

      //必填
      if( form1[i].value == '' ){
        alert('请输入!');
        form1[i].focus();
        return false;
      }

      //验证格式(正则)
      var str = form1[i].getAttribute('reg');
      var reg = new RegExp( str, 'gi');
      if( str && !reg.test( form1[i].value ) ){
        alert('格式不对!');
        form1[i].focus();
        return false;
      }

    }
  }

  //提交表达
  form1.submit();
  // console.log(form1);

}

</script>
  • ParentNode 接口

有那些节点拥有子节点?

  • 文档节点(document
  • 元素节点(element
  • 文档片段节点 (documentFragment

因此只有这三类节点会继承ParentNode

<script>
console.log( document.parentNode );//null
console.dir( document.body.parentNode );//html
console.dir( document.documentElement );//html
console.dir( document.documentElement.parentNode );//#document

console.log( document.body.parentNode == document.documentElement );//true
</script>
  • ParentNode.children

返回一个HTMLCollection实例,成员是当前节点的所有元素子节点。该属性只读。

  • ParentNode.firstElementChild

返回当前节点的第一个元素子节点。如果没有任何元素子节点,则返回null。

  • ParentNode.lastElementChild

返回当前节点的最后一个元素子节点,如果不存在任何元素子节点,则返回null。

  • ParentNode.childElementCount

返回一个整数,表示当前节点的所有元素子节点的数目。如果不包含任何元素子节点,则返回0

document.body.childElementCount // 13
  • ParentNode.append(),ParentNode.prepend()

append:在父节点内部的后面追加

prepend:在父节点内部的前面追加

<div id="box">

</div>

<script>
var box = document.getElementById('box');
var p = document.createElement('p');
var span = document.createElement('span');
box.append( p );//父节点方法
box.appendChild( span );//父节点追加子节点方法

</script>

prependappend区别

<div id="box">
  内容
</div>

<script>
var box = document.getElementById('box');
var p = document.createElement('p');
var span = document.createElement('span');
var a = document.createElement('a');
box.prepend( p );
box.append( span, a );

</script>
  • ChildNode.remove() 子节点方法

用于从父节点移除当前节点。

<div id="box"></div>

<script>
var box = document.getElementById('box');
box.remove();//删除
box.parentNode.removeChild( box );//删除
</script>

  • ChildNode.before(),ChildNode.after():
<button id="btn">按钮</button>

<script>
var btn = document.getElementById('btn');
var p = document.createElement('p');
btn.before( p );//目标节点外部的前面追加
p.append( btn );//目标节点内部的后面追加
</script>
<button id="btn">按钮</button>

<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
  var str = this.innerText;
  this.after( str );//外部的后面
}
</script>
  • ChildNode.replaceWith:

使用参数节点,替换当前节点。参数可以是元素节点,也可以是文本节点。

<button id="btn">按钮</button>

<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
  var div = document.createElement('div');
  var btn = this.cloneNode(true);
  div.append( btn );
  this.replaceWith( div );
}
</script>

Document 对象

Document 节点 属性
  • document.documentElement

返回当前文档的根节点(html),它通常是document节点的第二个子节,紧跟在document.doctype节点后面。

  • document.body,document.head

这两个属性是可写的,如果改写它们的值,相当于移除所有子节点

  • document.activeElement

返回获得当前焦点(focus)的 DOM 元素。通常,这个属性返回的是<input><textarea><select>等表单元素,如果当前没有焦点元素,返回<body>元素或null。

<div id="nav">
  <ul>
    <li tabindex="1" class="home">首页</li>
    <li tabindex="4" class="about">关于我们</li>
    <li tabindex="2" class="contact">联系我们</li>
    <li tabindex="3" class="product">产品中心</li>
  </ul>
</div>

<script>

setInterval(function(){
  console.log( document.activeElement );
},1000)

</script>
  • document.domain

属性返回当前文档的域名,不包含协议和接口

我们经常会用获取到当前程序的域名部分,拿域名作为前缀,避免和第三方应用命名冲突

var domain = document.domain; //seecen.com
localStorage.setItem(domain+'_mycart','购物车数据');//seecen.com_mycart
  • document.location

Location对象是浏览器提供的原生对象,提供 URL 相关的信息和操作方法。

// 标准的URL
var url = 'https://www.baidu.com:80/product/index.html';

//  https:// 协议部分
//  www 主机部分
//  baidu.com 域名部分
//  80 端口部分
//  /product/index.html  页面的路径和文件名

  • location.href: 返回完整的web地址,可读可写,写的就是网址转向
<button onclick="getUrl()">读取浏览器地址栏地址</button>
<button onclick="goUrl()">网易</button>
<script>
function getUrl(){
	console.log( location.href );//http://www.163.com
}
function goUrl(){
	location.href='http://www.163.com'
}
</script>
  1. location.hostname:返回 web 主机的域名
  2. location.pathname:返回当前页面的路径和文件名
  3. location.port: 返回 web 主机的端口 (80 或 443)
  4. location.protocol: 返回所使用的 web 协议(http: 或 https:)
  • document.lastModified:

返回一个字符串,表示当前文档最后修改的时间。不同浏览器的返回值,日期格式是不一样的

  • document.title

返回当前文档的标题。默认情况下,返回<title>节点的值

<button onclick="getTitle()">得到窗口标题</button>
<button onclick="setTitle()">设置窗口标题</button>
<script>
function getTitle(){
	alert(document.title);
}
function setTitle(){
	document.title = prompt('请输入窗口标题!');
}
</script>
  • document.referrer:

返回一个字符串,表示当前文档的访问者来自哪里

如果无法获取来源,或者用户直接键入网址而不是从其他网页点击进入,document.referrer返回一个空字符串。

  • document.hidden

返回一个布尔值,表示当前页面是否可见。如果窗口最小化、浏览器切换了 Tab,都会导致导致页面不可见,使得document.hidden返回true

setInterval(function(){
	console.log( document.hidden );
},1000);
  • document.readyState

document.readyState属性返回当前文档的状态,共有三种可能的值。

  • loading:加载 HTML 代码阶段
  • interactive: 加载外部资源阶段
  • complete: 加载完成
<img src="images/2.png" alt="">
<img src="images/4.png" alt="">
<img src="images/a1.png" alt="">

<script>
setInterval(function(){
	console.log( document.readyState );
},500);

</script>

js原生查找元素

  • document.getElementById: 通过id查找,返回单个dom对象
  <div id="box"></div>
  <script>
    document.getElementById('box').innerText = 'hello';
  </script>
  • document.getElementsByTagName: 通过标签名查找,返回HTMLCollection集合对象,是一个类数组,可以使用for循环。
  <h2>标题2</h2>
  <h2>标题2</h2>
  <h2>标题2</h2>

  <script>
  var h2 = document.getElementsByTagName('h2');
  console.log( h2 );// HTMLCollection(3) [h2, h2, h2]
  </script>

示例1

  <h2>标题2</h2>
  <h2>标题2</h2>
  <h2>标题2</h2>

  <script>
  var h2 = document.getElementsByTagName('h2');
  h2[0].style.color = 'red';
  h2[1].style.color = 'green';
  h2[2].style.color = 'blue';
  </script>

即便是只存在一个结果,也要使用中括号引用

  <h2>标题2</h2>
  <script>
  var h2 = document.getElementsByTagName('h2');
  h2[0].style.color = 'red';
  </script>
  • document.getElementsByClassName: 通过类名查找,返回HTMLCollection集合对象,是一个类数组,可以使用for循环,用法同上。
  <h2 class="bt2">标题2</h2>
  <h2 class="bt2">标题2</h2>
  <h2 class="bt2">标题2</h2>
  <script>
  var h2 = document.getElementsByClassName('bt2');
  h2[0].style.color = 'red';
  h2[1].style.color = 'green';
  h2[2].style.color = 'blue';
  </script>
  • document.getElementsByName: 通过属性名(name='box')查找,返回单个NodeList集合对象,是一个类数组,可以使用forEach循环,用法同上。
  <h2 name="bt2">标题2</h2>
  <h2 name="bt2">标题2</h2>
  <h2 name="bt2">标题2</h2>
  <script>
  var h2 = document.getElementsByName('bt2');
  console.log( h2 );
  h2[0].style.color = 'red';
  h2[1].style.color = 'green';
  h2[2].style.color = 'blue';
  </script>
  • document.links: 查找所有的链接
  • document.images: 查找所有的图像
  • document.forms: 查找所有的图像
  • document.scripts: 查找所有的图像
  • document.styleSheets: 查找所有的图像

采用 CSS 选择器作为参数的api接口

  • document.querySelector() 查找单个的dom对象,当有多个符合要求时,返回最近的dom对象
  <h2>标题2</h2>
  <h2>标题2</h2>
  <h2>标题2</h2>
  
  <script>
  var h2 = document.querySelector('h2');
  h2.style.color = 'red';
  </script>
  <h1 name="h2">标题1</h1>
  <h2 name="h2">标题2</h2>
  <h3 name="h2">标题3</h3>
  
  <script>
  var h2 = document.querySelector('h3[name="h2"]');
  h2.style.color = 'red';
  </script>
  <h1 name="gx-icon-del">标题1</h1>
  <h2 name="ok gx-icon-right">标题2</h2>
  <h3 name="no gx-icon-error">标题3</h3>
  
  <script>
  var a = document.querySelectorAll('[name ^="gx-icon-"]');
  console.log( a );

  var b = document.querySelectorAll('[name *="gx-icon-"]');
  console.log( b );

  var c = document.querySelectorAll('[name $="gx-icon-right"]');
  console.log( c );
  </script>
  • document.querySelectorAll() 查找多个的dom对象,返回NodeList对象,可以使用forEach
  <div class="nav">
    <ul>
      <li><a href="#">导航1</a></li>
      <li><a href="#">导航2</a></li>
      <li><a href="#">导航3</a></li>
      <li><a href="#">导航4</a></li>
    </ul>
  </div>
  
  <script>
  var lis1 = document.getElementsByClassName('nav')[0].getElementsByTagName('li'); // HTMLCollection(4) [li, li, li, li] 

  var lis2 = document.querySelectorAll('.nav li');
  console.log( lis1, lis2 ); // NodeList(4) [li, li, li, li]
  </script>
  • document.elementFromPoint() 和 document.elementsFromPoint()

document.elementFromPoint 方法返回位于页面指定位置最上层的元素节点。

document.elementsFromPoint() 返回一个数组,成员是位于指定坐标(相对于视口)的所有元素。

<style>
  div{
    position: fixed;
    width: 200px;
    height: 100px;
    
  }
  div.box1{
    background-color: red;
    z-index: 10;
  }
  div.box2{
    background-color: green;
    top: 60px;
    left: 100px;
  }
  </style>

<div class="box1">

</div>

<div class="box2">

  </div>
  
<script>
document.onclick = function( e){
  
  var elem = document.elementFromPoint( e.clientX, e.clientY );
  console.log( elem );
}

</script>
  • document.createEvent:

document.createEvent 方法生成一个事件对象(Event实例),该对象可以被element.dispatchEvent方法使用,触发指定事件。

var event = document.createEvent(type);

示例

<button onclick="triggle()">按钮</button>
  
<script>

//创建gongxian事件
var event = document.createEvent('Event');
event.initEvent('gongxian', true, true);

//侦听你创建的事件
document.addEventListener('gongxian', function (e) {
  console.log(e.type); 
}, false);

function triggle(){
  //触发gongxian 事件
  document.dispatchEvent(event);
}

</script>

js元素添加事件方法

  • 内联添加事件
<button onclick="add()">按钮</button>
  
<script>
function add(){
  //this 指向 window
  alert('hello');
}
</script>
  • DOM对象API添加事件
<button id="btn">按钮</button>
  
<script>
document.getElementById('btn').onclick = function() {
  //this 指向 button
  alert('hello')
}
</script>
  • 标准API添加事件
  1. addEventListener:添加事件

语法

dom对象.addEventListener( 事件名(不要on), 匿名函数, 事件类型 )
<button id="btn">按钮</button>
<script>
document.getElementById('btn').addEventListener('click',function(){
  console.log( this );//指向按钮
  alert('hello');
})
</script>
  1. removeEventListener:删除事件

非标准方法删除事件

<button id="btn" onclick="add()">添加事件</button>
<button onclick="del()">删除事件</button>
  
<script>
var add = function (){
  alert('添加了事件!');
}

function del(){
  document.getElementById('btn').onclick = null;//非标准方法删除事件
  alert('删除add事件!');
}
</script>

使用标准api删除事件

<button id="btn1">添加事件</button>
<button id="btn2">删除事件</button>
  
<script>
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');

function fn(){
  alert('添加了事件!');
}
btn1.addEventListener('click', fn )

btn2.onclick = function(){
  btn1.removeEventListener('click', fn ); //不能删除匿名事件处理器
  alert('事件删除成功!');
}
</script>

注意:不能删除匿名事件处理器

使用标准api触发事件

<button id="btn1">按钮1</button>

<script>
var btn1 = document.getElementById('btn1');

btn1.onclick = function(){
  console.log('被单击了!');
}

setInterval(function(){
  btn1.click();
},1000)

</script>
<style>
.myfile [type="file"]{
  display: none;
}
</style>

<div class="myfile">
  <input type="file">
  <button id="btn">图片上传</button>
</div>

<script>
document.getElementById('btn').onclick = function(){
  this.previousElementSibling.click();
}
</script>

Element 节点

  • draggable: 设置元素是否可拖拽
<button draggable="true">按钮</button>

注意:img元素默认是可拖拽的

你可以关闭这个行为

<img src="images/a1.png" draggable="false">
  • Element.tabIndex:返回一个整数,表示当前元素在 Tab 键遍历时的顺序
<ul>
  <li tabindex="3">首页</li>
  <li tabindex="1">关于</li>
  <li tabindex="2">联系</li>
</ul>

tabIndex属性值如果是负值-1,则 Tab 键不会遍历到该元素

  • Element.title

用来读写当前元素的 HTML 属性title,属性通常用来指定,鼠标悬浮时弹出的文字提示框。

<button title="按钮文字">标题</button>
  • Element.hidden

返回一个布尔值,表示当前元素的hidden属性,用来控制当前元素是否可见。该属性可读写。

<button id="btn">按钮1</button>
<button>按钮2</button>

<script>
document.getElementById('btn').hidden = true;
</script>
  • Element.contentEditable,Element.isContentEditable

HTML 元素可以设置contentEditable属性,使得元素的内容可以编辑。

<table>
  <tr>
    <th>学号</th>
    <th>姓名</th>
  </tr>
  <tr>
      <td contenteditable="true">1</td>
      <td contenteditable="true">张三</td>
    </tr>
  <tr>
      <td  contenteditable="true">2</td>
      <td  contenteditable="true">李四</td>
    </tr>
</table>

Element.isContentEditable 属性返回一个布尔值,同样表示是否设置了contenteditable 属性。

Element.attributes 返回一个类似数组的对象,成员是当前元素节点的所有属性节点

<button id="btn" title="文章" name="anniu" class="red">按钮</button>

<script>
document.getElementById('btn').onclick = function(){
  var obj = this.attributes;
  console.log( obj['title'].value );
}
</script>

  • Element.outerHTML 返回一个字符串,表示当前元素节点的所有 HTML 代码,包括该元素本身和所有子元素。

outerHTML属性是可读写的,对它进行赋值,等于替换掉当前元素

<button id="btn">按钮</button>
<script>
document.getElementById('btn').onclick = function(){
  var html = this.outerHTML;
  console.log( html ); //<button id="btn">按钮</button>
}
</script>
获取元素尺寸
  • window.innerWidth

获取窗口可视宽,该可视宽会包含滚动条的宽度( ~15px ),存在兼容性问题(IE9+)。

IE9以下如何获取可视宽?

document.documentElement.clientWidth; //不包含body的边距、滚动条。
  • window.innerHeight

获取窗口可视高,该可视宽会包含滚动条的宽度( ~15px ),存在兼容性问题(IE9+)。

IE9以下如何获取可视高?

document.documentElement.clientHeight; //不包含body的边距、滚动条。
<button onclick="getWidth()">窗口可视宽</button>
<button onclick="getHeight()">窗口可视高</button>

<script>
function getWidth(){
  console.log( window.innerWidth );
}
function getHeight(){
  console.log( window.innerHeight );
}
</script>
  • Element.clientWidth Element.clientHeight

获取元素的宽度,包含padding,但不包含border、margin、滚动条宽度。

<style>
#box{
  width: 100px;
  height: 100px;
  padding: 10px;
  border: 10px solid green;
  background-color: red;
  margin: 10px;
  overflow: auto;
}
</style>

<div id="box">
  <p>我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本我是文本</p>

</div>
<br>
<button onclick="getWidth()">获取客户端宽度</button>

<script>
function getWidth(){
  var box = document.getElementById('box');
  console.log( box.clientWidth );
}
</script>
  • Element.clientLeft,Element.clientTop
  1. Element.clientLeft:

元素节点左边框left border)的宽度,不包括左侧的paddingmargin

如果没有设置左边框,或者是行内元素(display: inline),该属性返回0

注意:该属性总是返回整数值,如果是小数,会四舍五入

  1. Element.clientTop

Element.clientTop 属性等于网页元素顶部边框的宽度(单位像素),其他特点都与clientTop相同。

  • Element.scrollHeight,Element.scrollWidth
  1. Element.scrollWidth

返回一个整数值(小数会四舍五入),表示当前元素的总宽度,包括溢出容器、当前不可见的部分,它包括padding,但是不包括bordermargin、垂直滚动条的高度。

  1. Element.scrollHeight

scrollWidth要求差不多。

  • Element.scrollLeft,Element.scrollTop

表示当前元素的水平滚动条向右侧滚动的像素数量,Element.scrollTop属性表示当前元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。

如果要查看整张网页的水平的和垂直的滚动距离,要从

document.documentElement

这两个属性都可读写,设置该属性的值,会导致浏览器将当前元素自动滚动到相应的位置。

  • Element.offsetParent

Element.offsetParent属性返回最靠近当前元素的、并且 CSSposition属性不等于static的上层元素。

  • Element.offsetHeight,Element.offsetWidth

Element.offsetHeight属性返回一个整数,表示元素的 CSS 垂直高度(单位像素),包括元素本身的高度paddingborder,以及水平滚动条的高度(如果存在滚动条)。

<style>
.box{
  position: absolute;
  width: 200px;
  background-color: red;
  visibility: hidden;
}
</style>
<div id="box" class="box">
  文本文本文本文本
</div>

<button id="btns">按钮</button>

<script>
document.getElementById('btns').onclick = function(){
  console.log( document.getElementById('box').offsetWidth );
}
</script>
  • Element.className,Element.classList

兼容性IE10+

Element.className 返回一个字符串,多个类用空格风格,该属性可读可写

<div id="box" class="red green blue"></div>

<script>
var str = document.getElementById('box').className;
console.log( str );//red green blue 
</script>

Element.classList 返回一个类数组对象,当前元素节点的每个class就是这个对象的一个成员。

<div id="box" class="red green blue"></div>

<script>
var obj = document.getElementById('box').classList;
console.log( obj );//类数组对象
</script>
  1. Element.classList.add:追加类
  2. Element.classList.remove:移除类
  3. Element.classList.toggle:切换类(没有此类就加上,有此类就移除)
  4. Element.classList.contains:检测是否包含某类,返回布尔值
<div id="box" class="red green blue"></div>

<script>
var obj = document.getElementById('box').classList;
obj.add('yellow'); //追加类
obj.remove('red'); //移除类
obj.toggle('red'); //切换类
console.log( obj.contains('green') );//true 检测是否包含某类
console.log( obj[2], obj.item(2) );// 读取指定索引值的类名
console.log( obj.toString() );// 文本化类名 green blue yellow red
</script>
  • Element.dataset 网页元素可以自定义data-属性,用来添加数据。

返回一个DOMStringMap对象,对象可以使用中括号或者点的形式调用,该对象可读可写

<div id="box" data-price="100" data-num="46"></div>

<script>
var box = document.getElementById('box');
box.dataset.name = '手机';
console.log( box.dataset.name, box.dataset.price, box.dataset.num );
//手机 100 46
</script>
  • Element.innerHTML:

返回一个字符串,等同于该元素包含的所有 HTML 代码。

  • Element.outerHTML

返回一个字符串,表示当前元素节点的所有 HTML 代码,包括该元素本身所有子元素

<div id="box">
  <span>文本</span>
</div>

<script>
var box = document.getElementById('box');
box.innerHTML;// <span>文本</span>
box.outerHTML;// <div id="box"><span>文本</span></div>
</script>
  • Element.getAttribute()

接受一个字符串作为参数,返回同名属性的值。如果没有该属性,则返回null

  • Element.setAttribute()

用于为当前节点设置属性。如果属性已经存在,将更新属性值,否则将添加该属性。该方法没有返回值。

<div id="box" price="2000"></div>

<script>
var box = document.getElementById('box');
box.setAttribute('price', 100);
</script>
  • Element.hasAttribute():

返回一个布尔值,表示当前元素节点是否有指定的属性。

<div id="box" price="2000"></div>

<script>
var box = document.getElementById('box');
console.log( box.hasAttribute('price') );//true
</script>
  • Element.hasAttribute():
<div></div>

<script>
var box = document.getElementsByTagName('div')[0];
console.log( box.hasAttributes() );//false
</script>
  • Element.removeAttribute()

移除属性

<input id="username" type="text" disabled>

<button id="btn">开启</button>

<script>
document.getElementById('btn').onclick = function(){
  document.getElementById('username').setAttribute('disabled','');
  document.getElementById('username').disabled = false;
  document.getElementById('username').removeAttribute('disabled');
}
</script>
  • Element.matches()

返回一个布尔值,表示当前元素是否匹配给定的 CSS 选择器。

  <div id="box" class="red" name="box">
    <ul>
      <li class="red">首页</li>
    </ul>
  </div>

  <script>
  var box = document.querySelector('#box'); 
  console.log( box.matches('#box') ); //true
  console.log( box.matches('#box.red') ); //true
  console.log( box.matches('div') ); //true
  console.log( box.matches('[name="box"]') ); //true
  console.log( box.matches('#box .red') ); //false
  </script>

利用offsetParent向上累积求总的偏移值

  <div style="position: fixed;left:300px;">
  <div style="position: absolute;left:300px;">
    <div style="position: absolute;left:100px;">
        <div id="two" class="two"></div>
    </div>
  </div>
  </div>
  <script>

  var two = document.getElementById('two');
  
  var left = two.offsetLeft;
  while( two.offsetParent ){
    two = two.offsetParent; 
    left += two.offsetLeft;
  }

  console.log( left );
  
  </script>
  • Element.getBoundingClientRect()

    返回一个对象,提供当前元素节点的大小、位置等信息,基本上就是 CSS 盒状模型的所有信息。

  <div id="one" class="one">
      <div id="two" class="two"></div>
  </div>
  <script>
  var two = document.getElementById('two');
  console.log( two.getBoundingClientRect() )
  </script>

返回的rect对象,具有以下属性(全部为只读)。

  1. x: x坐标
  2. y: y坐标
  3. height: 高度
  4. width: 宽度
  5. left: 距左值
  6. right: 距右值
  7. top: 距顶值
  8. bottom: 距下值
  • Element.getClientRects():

    返回一个类似数组的对象,里面是当前元素在页面上形成的所有矩形
    每个矩形都有bottom、height、left、right、top和width六个属性,表示它们相对于视口的四个坐标,以及本身的高度和宽度。

事件模型

事件各个组成部分之间的一种通信方式,DOM 支持大量的事件

EventTarget 接口

该接口主要提供三个实例方法。

  • addEventListener: 绑定事件的监听函数,IE9+
  • removeEventListener: 移除事件的监听函数,不能移除匿名函数
  • dispatchEvent:触发事件
EventTarget.addEventListener()

语法

EventTarget.addEventListener( '不加on的事件名', 事件处理器, 事件类型(默认冒泡) )

什么是冒泡事件?

冒泡事件是指从目标对象一直到根节点的事件触发过程。

  <div id="box">
    <ul id="ul">
      <li id="li">首页  <button id="btn">删除</button></li>
    </ul>

  </div>

  <script>
  var box = document.getElementById('box');
  var ul = document.getElementById('ul');
  var li = document.getElementById('li');
  var btn = document.getElementById('btn');

  box.addEventListener('click',function(){
    console.log('btn被单击了!','-from div');
  })

  ul.addEventListener('click',function(){
    console.log('btn被单击了!','-from ul');
  })

  li.addEventListener('click',function(){
    console.log('btn被单击了!','-from li');
  })

  btn.addEventListener('click',function(){
    console.log('btn被单击了!','-from button');
  })

  </script>

什么是捕获事件?

从根节点到一直到目标节点的事件触发过程。

 <div id="box">
    <ul id="ul">
      <li id="li">首页  <button id="btn">删除</button></li>
    </ul>

  </div>

  <script>
  var box = document.getElementById('box');
  var ul = document.getElementById('ul');
  var li = document.getElementById('li');
  var btn = document.getElementById('btn');

  box.addEventListener('click',function(){
    console.log('btn被单击了!','-from div');
  },true)

  ul.addEventListener('click',function(){
    console.log('btn被单击了!','-from ul');
  },true)

  li.addEventListener('click',function(){
    console.log('btn被单击了!','-from li');
  },true)

  btn.addEventListener('click',function(){
    console.log('btn被单击了!','-from button');
  },true)


  
  </script>

如何阻止事件冒泡?

btn.addEventListener('click',function( event ){
  event.stopPropagation();//阻止事件冒泡
  // event.stopImmediatePropagation(); //除了可以阻止事件冒泡之外,还可以把这个元素绑定的同类型事件也阻止
  console.log('btn被单击了!','-from button');
})
<div>
  <p>段落</p>
</div>

<script>
var p = document.querySelector('p');
p.addEventListener('click', function (event) {
  // event.stopPropagation(); //会执行下面的click事件
  event.stopImmediatePropagation(); //不会执行下面的click事件
  console.log(1);
});

p.addEventListener('click', function(event) {
  // 会触发
  console.log(2);
});

</script>

如何阻止默认动作?

默认动作有那些?

  1. 右击
  2. 提交表单
  3. 超级链接
  4. 拖拽
btn.addEventListener('click',function( event ){
  event.preventDefault();//阻止默认动作
  console.log('btn被单击了!','-from button');
})

什么是事件代理(委托)?

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理。

事件代理可以提高执行效率,属于性能优化的一种手段

<button id="addbtn">添加</button>
<script>
//事件代理
document.getElementById('ul').onclick = function(e){
  var target = e.target;
  var tag = target.nodeName.toLowerCase();
  if(tag == 'button'){
    target.parentNode.remove();
  }
}
//添加
document.getElementById('addbtn').onclick = function(){
  var title = prompt('请输入名称!');
  var temp = `<li>${title}<button>删除</button></li>`;
  document.querySelector('ul').innerHTML += temp
}
</script>

如何制作一次性事件?

<button id="paybtn">立即支付</button>
<script>
function fn(){
  alert('支付成功!');
  //删除自己添加的事件
  this.removeEventListener('click', fn );
}
document.getElementById('paybtn').addEventListener('click', fn );
</script>

利用addEventListener 第三个参数也可以做单次事件功能

第三个参数:

  1. capture:true 捕获 false 冒泡
  2. once:true 单次 false 多次
  3. passive:true 不允许阻止默认动作 false 允许
<button id="paybtn">立即支付</button>
<script>
document.getElementById('paybtn').addEventListener('click', function(){
  alert('支付成功!');
},{
  capture: true,
  once: true,
  passive: true
});
</script>
  • EventTarget.dispatchEvent()
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>

<script>
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');

//1.创建自定义事件
var event = new Event('gongxian');

//2.监听自定义事件
btn1.addEventListener('gongxian',function(){
  console.log('开饭了!');
})

btn2.onclick = function(){
  //3.触发自定义事件
  btn1.dispatchEvent( event );
}
</script>
  • Event.currentTarget,Event.target

Event.currentTarget 属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点

Event.target属性返回原始触发事件的那个节点,即事件最初发生的节点。

Event.currentTarget属性的值是不一样的,前者总是不变的, 后者则是指向监听函数所在的那个节点对象。

<div id="box" style="padding:20px;">
  <p>段落 <button>按钮</button></p>
</div>

<script>
var box = document.querySelector('#box');
box.onclick = function( e ){
  console.log( '当前目标对象', e.currentTarget );
  console.log( '目标对象', e.target );
}
</script>
  • Event.type

Event.type属性返回一个字符串,表示事件类型。

<script>
var box = document.querySelector('#box');
box.onclick = function( e ){
  console.log( '事件类型', e.type );//click
}
</script>
  • Event.timeStamp

Event.timeStamp属性返回一个毫秒时间戳,表示事件发生的时间。它是相对于网页加载成功开始计算的。

实践应用:控制事件触发频率,提高性能

<script>
var box = document.querySelector('#box');
box.onclick = function( e ){
  console.log( '事件时间戳', e.timeStamp );
}
</script>
  • e.clientX,e.screenX
<script>
document.onmousemove = function(e){
  console.log( 'client:', e.clientX );//相对浏览器水平平移
  console.log( 'screen:', e.screenX );//相对设备屏幕水平偏移
}
</script>
  • Event.isTrusted

返回一个布尔值,表示该事件是否由真实的用户行为产生。比如,用户点击链接会产生一个click事件,该事件是用户产生的;Event构造函数生成的事件,则是脚本产生的。

  • Event.detail

该属性返回一个数值,表示事件的某种信息,具体含义与事件类型相关。

Event.detail是鼠标按下的次数:

  1. 1表示单击
  2. 2表示双击
  3. 3表示三击
Event 对象的实例方法
  • Event.preventDefault() 取消浏览器对当前事件的默认行为,比如点击链接后。
<div style="height: 5000px;"></div>
<script>
//按下空格页面会往下走动,以下代码阻止这个行为
document.onkeydown = function(e){
  e.preventDefault();
}
</script>
  • Event.stopPropagation() 阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数
  • stopImmediatePropagation 阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。也就是说,该方法阻止事件的传播,比Event.stopPropagation()更彻底。
  • CustomEvent 接口

用于生成自定义的事件实例。那些浏览器预定义的事件,虽然可以手动生成,但是往往不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,就可以使用 CustomEvent 接口生成的自定义事件对象

<button id="btn">按钮</button>
<script>
//1. 创建自定义事件
var ev = new CustomEvent('gongxian', {
  detail: {
    name: '张三',
    age: 30,
    sex: '男'
  }
})

//2. 监听自定义事件
document.addEventListener('gongxian',function(e){
  console.log(e.detail);
})

document.getElementById('btn').onclick = function(){
  //3. 触发自定义事件
  document.dispatchEvent( ev );
}
</script>
常用系统事件
  • click:单击
  • dblclick:双击事件
  • contextmenu:右击事件
  • change:改变事件
  • input: 输入事件
  • paste:粘贴事件
  • selectstart: 开始选择时触发
  • select: 选择文本时触发,仅限表单控件(单行文本和多行文本框)
  • copy: 拷贝后触发
  • mousewheel:滚动滚动时触发
  • scroll: 滚动条滚动时触发
  • mouseenter:鼠标进入触发
  • mouseleave:鼠标离开触发
  • mouseover: 鼠标划过触发
  • mouseout: 鼠标划出触发
  • mousedown: 鼠标按下
  • mousemove: 鼠标移动
  • mouseup: 鼠标松开

mousedown、mousemove、mouseup、click的顺序是?

  <div id="box">
    <p>段落</p>
    <button>按钮</button>
  </div>

  <script>
  document.getElementById('box').onmouseenter = function(e){
    console.log(e.target);
  }
  
  document.getElementById('box').onmouseover = function(e){
    console.log(e.target);
  }
  </script>
<input type="text" id="prcie">
<script>
//输入的时候替换为空 \D 表示非数字
document.getElementById('prcie').oninput = function(){
  this.value = this.value.replace(/\D/g,'');
}
//粘贴的时候替换为空
document.getElementById('prcie').onpaste = function(){
  this.value = this.value.replace(/\D/g,'');
}
</script>
  • oncopy:拷贝事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值