DOM (Document Object Model)

DOM是一套编程接口,让js能操作html和xml。

1. DOM选择器

1.1 document.getElementById()

  • 其中元素id在ie8以下的浏览器不区分大小写
  • 该方法定义在 Document.prototype上,即Element节点上不能使用

1.2 getElementsByTagName()

  • 该方法定义在 Document.prototype 和 Element.prototype上, 最常用的一个方法
<div>
  <span>sun</span>
</div>
<span></span>

<script>
  var div = document.getElementsByTagName('div')[0];
  var span = div.getElementsByTagName('span')[0];
</script>
getElementsByTagName()

1.3 getElementsByName()

  • 其中只有部分标签的name可生效,例如 表单,表单元素, img, iframe...
  • 方法定义在 HTMLDocument.prototype上

1.4 getElementsByClassName()

  • 类名,其中ie8和ie8以下的ie版本中没有
  • 该方法定义在 Document.prototype 和 Element.prototype上

1.5 querySelector()querySelectorAll()

  • css选择器,在ie7和ie7以下的版本中没有
  • querySelector 选出来的是一个, querySelectorAll 选出来是一组。
  • 这俩方法选出来的不是实时的。
  • 这俩方法定义在 Document.prototype 和 Element.prototype上
<div>
  <span>
    <strong class="demo"><strong>
  </span>
</div>

<script>
  var strong = document.querySelector('div > span strong.demo')
</script>

2. 遍历节点树

  • parentNode 父节点(最顶端的parentNode为 #document)
<div>
  <strong></strong>
  <span></span>
  <em></em>
</div>

<script>
  var strong = document.getElementsByTagName('strong')[0];
</script>
parentNode
  • childNodes 选出子节点们
<div>
  <strong>
    <span></span>
  </strong>
  <span></span>
  <em></em>
</div>

<script>
  var div= document.getElementsByTagName('div')[0];
</script>
childNodes

需要注意的是,这个东西选出来的子节点们,是会把所有类型的子节点都选出来。什么 文本节点,注释节点,元素节点... ...(节点的类型在后文会有写)

  • firstChild 第一个子节点
  • lastChild 最后一个子节点, 即能选择元素中的最后一个节点。
  • nextSibling & previousSibling 后/ 前一个兄弟节点
<div>
  <strong>
    <span></span>
  </strong>
  <span></span>
  <em></em>
</div>
<script>
  var strong = document.getElementsByTagName('strong')[0];
</script>

nextSibling
可以看到 strong的下一个兄弟节点是文本节点,再下一个兄弟节点是 span ... ...


3. 基于元素节点树的遍历

下面这些方法遍历时,是基于真正的元素节点;即文本节点,注释节点等等都不会识别了。
注意: 下面的 ie不兼容 指的是 ie9 和 ie9 以下的。

  • parentElement 返回当前元素的 父元素的节点(ie不兼容)
<div>
  sun
  <!-- 嘤嘤嘤 -->
  <strong></strong>
  <span></span>
</div>
<script>
  var strong = document.getElementsByTagName('strong')[0];
</script>

需要明白的是,document自成一个节点,不是元素节点。也就是 parentElement 和 上面那个parentNode出来结果不一样的地方。

parentElement

  • children 只返回当前元素的元素子节点们
<div>
  <!-- 嘤嘤嘤 -->
  <strong></strong>
  <span></span>
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>
children
  • node.childElementCount === node.children.length 当前元素节点的子元素节点个数 (ie不兼容)
  • firstElementChild & lastElementChild 返回的是第一个/ 最后一个元素子节点 (ie不兼容)
<div>
  <strong></strong>
  <span></span>
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>
firstElementChild/ lastElementChild
  • nextElementSibling / previousElementSibling 返回后一个/ 前一个兄弟元素节点

3.1 节点的四个属性

  • nodeName
    元素的标签名,返回一个字符串;只读。
<div>
   sun
  <!--嘤嘤嘤-->
  <strong></strong>
  <span></span>
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>
nodeName
  • nodeValue
    只有 Text (文本)节点 和 Comment (注释)节点有这个属性;可读写;

  • nodeType (重点)
    该节点的类型;只读。
    获取节点类型

    nodeType

  • attributes
    元素的Element 节点的属性集合

3.2 节点的类型

  • 1 --- 元素节点
  • 2 --- 属性节点
  • 3 --- 文本节点
  • 8 --- 注释节点
  • 9 --- 文档节点 (document)

3.4 节点的一个方法Node.hasChildNodes()
返回值: true / false

<div>
  <strong></strong>
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>

hasChildNodes()

注意: 是找有没有节点,不是有没有元素节点,所以下列两种情况皆返回 true

<!--这坨div中含有注释节点-->
<div>
  <!--嘤嘤嘤-->
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>
<!--这坨div中含有文本节点-->
<div>
</div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>

下面这种情况返回 false:

<div></div>
<script>
  var div= document.getElementsByTagName('div')[0];
</script>

4. DOM结构树 (表示一种继承关系)

DOM结构树
  • 继承关系:
    document ----> HTMLDocument.prototype ----> Document.prototype
    继承关系

即: HTMLDocument.prototype = { __proto__: Document.prototype}

  • HTMLDocument.prototype 定义了一些常用的属性, body, head 分别指代 HTML 文档中的 <body><head>标签; 用法: document.bodydocument.head
  • Document.prototype 上定义了 documentElement 属性,指代文档的根元素,在HTML文档中,他总是指代 <html> 元素;用法:document.documentElement

5. DOM 基本操作

5.1 增

  • document.createElement();
    创建元素节点: document.createElement('div');
  • document.createTextNode();
    创建文本节点: document.createTextNode('啦啦啦,德玛西亚');
  • document.createComment();
    创建注释节点: document.createComment('这是注释嗷');
  • document.createDocumentFragment();
    创建文档碎片节点

5.2 插

  • PARENTNODE.appendChild();
    任何一个元素节点都有这个方法。
<body>
    <script>
        var div = document.createElement('div');
        document.body.appendChild(div);
    </script>
</body>
appendChild()

如果把页面中已经存在的一个部分,appendChild去另一个部分,做的是 剪切 操作。

<body>
    <div></div>
    <span></span>

    <script>
        var div = document.getElementsByTagName('div')[0];
        var span = document.getElementsByTagName('span')[0];
        div.appendChild(span);
    </script>
</body>
效果
  • ParentNode.insertBefore(a, b);
    必须父级去调用,然后往父级里面放东西。(把 a 放到 b 前面)
<body>
    <div>
        <span></span>
    </div>
   
    <script>
        var div = document.getElementsByTagName('div')[0];
        var span = document.getElementsByTagName('span')[0];
        var strong = document.createElement('strong');
        div.insertBefore(strong, span);
    </script>
</body>
效果

5.3 删

  • parent.removeChild();
    父节点删除子节点, 该方法返回被删除的子节点
<body>
    <div>
        <span></span>
        <i></i>
        <strong></strong>
    </div>
   
    <script>
        var div = document.getElementsByTagName('div')[0];
        var i = document.getElementsByTagName('i')[0];
        div.removeChild(i);
    </script>
</body>
效果
  • child.remove();
    自己销毁自己,返回 undefined
<body>
    <div>
        <span></span>
        <i></i>
        <strong></strong>
    </div>
   
    <script>
        var div = document.getElementsByTagName('div')[0];
        var span = document.getElementsByTagName('span')[0];
        span.remove();
    </script>
</body>
效果

5.4 替换

  • parent.replaceChild(new, origin);
    拿新的元素(new)去替换旧的元素(origin)
<body>
    <div>
        <span></span>
        <i></i>
        <strong></strong>
    </div>
   
    <script>
        var div = document.getElementsByTagName('div')[0];
        var span = document.getElementsByTagName('span')[0];
        var p = document.createElement('p'); 
    </script>
</body>
Example

5.4 Element 节点的一些属性

  • innerHTML
    改变一个元素里面的html内容
<body>
    <div>
        <span>sun</span>
        <p>sweet</p>
    </div>
   
    <script>
        var div = document.getElementsByTagName('div')[0];
    </script>
</body>
Example
  • innerText
    取一个元素中的文本内容。


    Example

5.5 Element 节点的一些方法

  • ele.setAttribute();
<body>
    <div></div>
    <script>
        var div = document.getElementsByTagName('div')[0];
        div.setAttribute('class', 'test');
    </script>
</body>
效果
  • ele.getAttribute();


    效果

6. date对象

日期对象 Date()。打印当前是何年何月何日何时,几分几秒。

var date = new Date();
Result
  1. getDate()
    这个方法会返回今天是这个月中的第几天 (今天是5月1)


    getDate()
  2. getDay()
    这个方法会返回今天是一周中的第几天(0~6)

    注意: 周天是第一天
    getDay()
  3. getMonth()
    这个方法会返回当前是几月(0 ~11)

    注意: 从0开始计算,1月为0
    getMonth()
  4. getFullYear()

    这个方法会返回当前是几几年
    getFullYear()
  5. getHours()/ getMinutes()/ getSeconds()
    返回Date对象的小时/分钟/秒数

    注意:这个返回的是创建时候那个时刻的时分秒 (我电脑的时间是 14:01)
    result
  6. getTime() 重点嗷~~~

  • 这个方法返回1970年1月1日至今的毫秒数;
  • 这个方法可以求时间戳
    下面这段代码可以求证1000000次循环用了多少时间。结果显示为 4毫秒。
<script>
  var firstTime = new Date().getTime();
  for(var i=0; i<1000000; i++) {}  
  var lastTime = new Date().getTime();
  console.log(lastTime - firstTime);
</script>
getTime()
  1. setDate()

    这个方法可以设置Date对象中 月的某一天(1~31)
    setDate()
  2. toString()
    把 Date对象转换为字符串


    toString()

7. js定时器

注意:都是全局对象 window 上的方法,内部函数 this 指向 window。

  1. setInterval()
  • 每隔1000毫秒就执行一次函数
  • 它会返回一个数字作为它的唯一表示 (表示这是第几个定时器)
var timer = setInterval(function() {
  console.log('sun');
}, 1000) ;
  1. setTimeout()
  • 推时作用, 推迟多少时间之后才执行某个操作, 并且只执行一次。
var timer = setTimeout(function () {
  console.log('sun');
}, 1000);
  1. clearInterval()
    清除定时器
var i = 0;
var timer = setInterval(function() {
  console.log(i ++);
  if (i > 10) {
    clearInterval(timer);
  }
}, 10) ;
  1. clearTimeout()
var timer = setTimeout(function() {
  console.log('a');
}, 1000);
clearTimeout(timer);

8. 用dom获取界面尺寸

1. 查看滚动条的滚动距离
语法: window.pageXOffset/ pageYOffset (IE及IE8以下不兼容)
语法: document.body/documentElement.scrollLeft/ scrollTop(IE8及IE8以下用这个方法去求滚动条的滚动距离)
注意: IE8和IE8以下以下的浏览器, document.body.scrollLeft/Topdocument.documentElement.scrollLeft/Top这两个由于兼容性问题,只有一个会生效。所以说以后用的话直接把两个加一加。

document.body.scrollLeft + document.documentElement.scrollLeft
result

封装一个方法,使滚动条的滚动距离能兼容所有浏览器

function getScrollOffset() {
  if(window.pageXOffset) {
    return {
      x: window.pageXOffset,
      y: window.pageYOffset
    }
  } else {
      return {
        x: document.body.scrollLeft + document.documentElement.scrollLeft,
        y: document.body.scrollTop + document.documentElement.scrollTop
      }
    }
}
效果

2. 查看可视区窗口的尺寸
可视区窗口其实就是 html 文档的部分。
语法:window.innerWidth/innerHeight (IE8及IE8以下不兼容)
语法:document.documentElement.clientWidth/clientHeight (标准模式下,任意浏览器都兼容; IE8及IE8以下是可以兼容的)
语法: document.body.clientWidth/clientHeight (怪异/ 混杂模式模式下; IE8及IE8以下是可以兼容的)

科普:混杂模式启用方法
<!DOCTYPE html> 这句话删了就启用了混杂模式了。写了这句话就是标准模式。
封装一个方法,获取可视区窗口的尺寸,兼容所有浏览器

function getViewportOffset() {
  if(window.innerWidth) {
    return {
      w: window.innerWidth,
      h: window.innerHeight
    }
  }  else {
      if (document.compatMode === "BackCompat") {
        return {
          w: document.body.clientWidth,
          h: document.body.clientHeight
        }
      } else {
        return {
          w: document.documentElement.clientWidth,
          h: document.documentElement.clientHeight
        }
      }
   }
}

3. 查看元素的几何尺寸
该方法兼容性很好。 任何一个dom元素都有这个方法。
语法: domEle.getBoundingClientRect()
该方法返回一个对象。需要注意的是,这个返回的结果并不是实时的。(讲道理,这个方法没什么用,稍微看一看。)

<body>
    <div style="width: 50px; height: 50px; background-color: pink; 
    position: absolute; left: 100px; top: 100px;"></div>
    <script>
        var div = document.getElementsByTagName('div')[0];
    </script>
</body>
效果

4. 查看元素尺寸
语法: dom.offsetWidth, dom.offsetHeight

查看元素尺寸

5. 查看元素的位置
语法:dom.offsetLeftdom.offsetTop
注意:这个方法会忽略元素自身是否是定位元素,求得值是距离它有定位的父级的坐标。如果对于无定位父级的元素,则返回的值是相对文档的坐标。
语法:dom.offsetParent
该方法能求出相对于最近的有定位的父级,如果没有,就返回body

6. 让滚动条滚动
window上有三个方法:

  • scroll() / scrollTo() 这俩方法没区别,喜欢用哪个就用哪个吧。滚动到指定的点。
    里面可以填俩参数,第一个参数是让x轴滚动的距离,第二个参数是让y轴滚动的距离
<div style="width: 5000px; height: 5000px; 
border: 1px solid black"></div>
效果
  • scroll By()
    累加滚动距离,用法和上面类似,只不过这个可以累加。

9. 脚本化 CSS

  1. 读写元素css属性
  • dom.style.prop
    这个可以读写 行间样式
    注意:
  • 在js访问css属性时,不能访问有-的属性,例如 background-color。所以但凡碰到这样的,改成小驼峰式就可以访问了。即 backgroundColor
  • 碰到关键字的时候,例如 float,写成 cssFloat
  • 写入的值必须是字符串格式
<body>
  <div style="width: 50px; height: 50px; background-color:pink;"></div>
  <script>
    var div = document.getElementsByTagName('div')[0];
    div.style.backgroundColor = 'red';
    div.style.width = '200px';
  </script>
</body>
效果
  1. 查询计算样式
    获取的是当前元素所展示出的一切css的显示值
  • window.getComputedStyle()
  • 第一个参数填你要获取的是哪个元素,第二个参数一般情况下填null,这个参数可以获取伪元素的样式表
    例子
  • 这个方法只读,不能改。
  • 该方法返回的值都是绝对值,没有相对单位
  • IE8及IE8以下不兼容

所以IE8和IE8以下的浏览器,查询样式使用的方法如下:

  • window.currentStyle['prop']
  • 计算样式只读
  • IE独有属性

封装兼容性方法获取css style

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

10. 事件

1. 绑定事件的几种方法

  • ele.onxxx = function (event) {}
    兼容性很好,但是一个元素的同一个事件上只能绑定一个处理程序。基本等同于写在html行间上。
    程序this指向dom元素本身。
<div></div>
... ...
var div = document.getElementsByTagName('div')[0];
div.onclick = function() {
  this.style.backgroundColor = 'green';
}
  • obj.addEventListener(type, fn, false);
    IE9以下不兼容,可以为一个事件绑定多个处理程序。
    程序this指向dom元素本身。
div.addEventListener('click', function() {
  
} , false);

  • obj.attachEvent('on' + type, fn)
    IE独有,一个事件同样可以绑定多个处理程序。
    程序this指向window。
    如果想让this指向div,方式如下:
div.attachEvent('onclick', function() {
  handle.call(div);
})
function handle() {
  this.xxx = xxxxxxxxx;
}

封装兼容性方法 addEvent(elem, type, handle)

function addEvent(elem, type, handle) {
  if (elem.addEventListener) {
    elem.addEventListener(type, handle, false);
  } else if(elem.attachEvent) {
    elem.attachEvent('on' + type, function () {
      handle.call(elem);
    })
  } else {
    elem['on' + type] = handle;
  }
}

2. 解除事件处理程序
注意:如果绑定的是匿名函数,则无法解除。

  • ele.onclick = false/''/null;
var div = document.getElementsByTagName('div')[0];
// 只执行一次事件
div.onclick = function() {
  console.log('a');
  this.onclick = null;
}
  • ele.removeEventListener(type, fn, false);
var div = document.getElementsByTagName('div')[0];
function test() {
  console.log('sun');
}
div.addEventListener('click', test, false);
div.removeEventListener('click', test, false);
  • ele.detachEvent('on' + type, fn)

11. 事件处理模型

一个对象的一个事件类型只能遵循一种模型。
如果一个对象的一个事件类型上绑定了两个函数,两个函数分别遵循捕获和冒泡,那么执行顺序为 先捕获后冒泡

1. 事件冒泡
  • 结构上嵌套关系(就是父子关系)的元素,会存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素。(自底向上)
  • 特殊事件没有冒泡功能: focus, blur, change, submit, reset, select
<style>
  .wrapper{
    width: 300px;
    height: 300px;
    background-color: red;
  }
  .content {
    width: 200px;
    height: 200px;
    background-color: green;
  }
  .box {
    width: 100px;
    height: 100px;
    background-color: yellow;
  }
</style>
... ...
<body>
    <div class="wrapper">
        <div class="content">
            <div class="box"></div>
        </div>
    </div>
    
    <script>
        var wrapper = document.getElementsByClassName('wrapper')[0];
        var content = document.getElementsByClassName('content')[0];
        var box = document.getElementsByClassName('box')[0];

        wrapper.addEventListener('click', function() {
            console.log('wrapper');
        }, false);
        content.addEventListener('click', function() {
            console.log('content');
        }, false);
        box.addEventListener('click', function() {
            console.log('box');
        }, false);
    </script>
</body>
事件冒泡
2. 事件捕获
  • 与冒泡顺序相反,结构上嵌套关系的元素,会存在事件捕获的功能,即同一事件,自父元素捕获至子元素。(自顶向下)
  • 注意:IE没有捕获事件
<style>
  .wrapper{
    width: 300px;
    height: 300px;
    background-color: red;
  }
  .content {
    width: 200px;
    height: 200px;
    background-color: green;
  }
  .box {
    width: 100px;
    height: 100px;
    background-color: yellow;
  }
</style>
... ...
<body>
    <div class="wrapper">
        <div class="content">
            <div class="box"></div>
        </div>
    </div>
    
    <script>
        var wrapper = document.getElementsByClassName('wrapper')[0];
        var content = document.getElementsByClassName('content')[0];
        var box = document.getElementsByClassName('box')[0];

        wrapper.addEventListener('click', function() {
            console.log('wrapper');
        }, true);
        content.addEventListener('click', function() {
            console.log('content');
        }, true);
        box.addEventListener('click', function() {
            console.log('box');
        }, true);
    </script>
</body>
事件捕获
3. 阻止事件冒泡
  • event.stopPropagation(), 该方法不支持IE9以下版本。
<style>
  .wrapper {
    width: 300px;
    height: 300px;
    background-color: red;
  }
</style>
... ...
<body>
    <div class="wrapper"></div>
    <script>
        var div = document.getElementsByTagName('div')[0];
        document.onclick = function() {
            console.log('点我干啥');
        }
        div.onclick = function(e) {
            e.stopPropagation();
            this.style.background = "orange";
        }
    </script>
</body>
  • event.cancelBubble = true, 该方法兼容IE。
<body>
    <div class="wrapper"></div>
    <script>
        var div = document.getElementsByTagName('div')[0];
        document.onclick = function() {
            console.log('点我干啥');
        }
        div.onclick = function(e) {
            e.cancelBubble = true;
            this.style.background = "orange";
        }
    </script>
</body>
  • 封装取消冒泡函数
function stopBubble(event) {
  if (event.stopPropagation) {
    event.stopPropagation();
  } else {
    event.cancelBubble = true;
  }
}
4. 阻止默认事件

默认事件 —— 表单提交, a标签跳转, 右键菜单等。
科普科普,右键出菜单事件 document.oncontextmenu = function() {}

  • return false;,以对象属性的方式注册的事件才生效
document.oncontextmenu = function() {
  console.log('a');
  return false;
}
  • event.preventDefault();,该方法IE9以下不支持
document.oncontextmenu = function(e) {
  console.log('a');
  e.preventDefault();
}
  • event.returnValue = false;,该方法兼容IE
document.oncontextmenu = function(e) {
  console.log('a');
  e.returnValue = false;
}
  • 封装阻止默认事件函数
// 使用
document.oncontextmenu = function(e) {
  console.log('sun');
  cancelHandler(e);
};
// 封装的函数
function cancelHandler(e) {
  if (e.preventDefault) {
    e.preventDefault();
  } else {
    e.returnValue = false;
  }
}
5. 事件对象
  • event || window.event 兼容IE的写法
<script>
  var div = document.getElementsByTagName('div')[0];
  div.onclick = function(e) {
    var event = e || window.event;
    console.log(event);
  }
</script>
  • 事件源对象:
    • event.target 火狐只有这个
    • event.srcElement IE只有这个
    • chrome 这俩都有
    • 封装一个兼容函数,获取事件源对象
    <body>
        <div class="wrapper">
            <div class="box"></div>
        </div>
        <script>
            var wrapper = document.getElementsByClassName('wrapper')[0];
            var box = document.getElementsByClassName('box')[0];
            wrapper.onclick = function(e) {
                var event = e || window.event;
                var target = event.target || event.srcElement;
                console.log(target);
            }
        </script>
    </body>
    
6. 事件委托
  • 利用事件冒泡和事件源对象进行处理
  • 性能好,不需要循环所有的元素一个个去绑定事件
  • 灵活,当有新的子元素时,不需要重新绑定事件
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
    </ul>
    
    <script>
        var ul = document.getElementsByTagName('ul')[0];
        ul.onclick = function(e) {
            var event = e || window.event;
            var target = event.target || event.srcElement;
            console.log(target.innerText);
        }
    </script>
</body>

12. 事件分类

1. 鼠标事件
  • click, mousedown, mousemove, mouseup, contextmenu, mouseover, mouseout, mouseenter, mouseleave

  • 用 button 来区分鼠标的按键, 0/1/2

document.onmousedown = function(e) {
  console.log(e);
  if (e.button == 2) {
    console.log('right');
  } else if (e.button == 0) {
    console.log('left');
  }
}
左键点击,button为0

右键点击,button为2
  • click 事件只能监听左键,只能通过 mousedownmouseup 来判断鼠标键。 右键无法触发click事件。

  • 解决 mousedownclick 的冲突
    用时间差来进行判断。

var firstTime = 0;
var lastTime = 0;
var key = false;

document.onmousedown = function() {
  firstTime = new Date().getTime();
}
document.onmouseup = function() {
  lastTime = new Date().getTime();
  if (lastTime - firstTime < 300) {
    key = true;
  }
}
document.onclick = function() {
  if (key) {
    console.log('click');
    key = false;
  } 
}
2. 键盘事件
  • keydown, keyup, keypress
    触发顺序:keydown > keypress > keyup

  • keydown 和 keypress 的区别
    keydown 可以响应任意键盘按键, keypress 只响应字符类键盘按键。
    keypress 返回 ASCII 码,可以转换成相应字符。

<script>
  document.onkeypress = function (e) {
    console.log(String.fromCharCode(e.charCode));
  }
</script>
3. 移动端事件
  • touchstart
  • touchmove
  • touchend
4. 事件分类
  • 文本类事件
    input, change, focus, blur
<input type="text">
... ...
// 但凡文本有变化,就会触发input事件
var input = document.getElementsByTagName('input')[0];
input.oninput = function (e) {
  console.log(this.value);
}

// 聚焦,改变内容,失去焦点,触发change事件
input.onchange= function (e) {
  console.log(this.value);
}
  • 窗体操作类 (window上的事件)
    scroll 当滚动条一滚动,这个事件就会被触发;
    load 这个方法是最慢的,这个页面所有要加载的要初始化的东西全部完成后,这个方法才会触发。
window.onscroll = function () {
  console.log(window.pageXOffset + ' ' + window.pageYOffset);
}
window.onload = function () {
  // 没事情别用这个瓜皮方法
} 

小知识:
浏览器有个时间线:
(html和css是并行解析的)
html在解析的时候会形成一个 domTree;所有的dom解析完毕,不是下载完。
css在解析的时候会形成一个 cssTree;
这俩会形成一个 renderTree;


练习
  1. 遍历元素节点树 (在原型链上编程)
  2. 封装函数,返回元素e的第n层祖先元素节点
function retParent(elem, n) {
 while(elem && n) {
    elem = elem.parentElement;
    n--;
  }
  return elem;
}
  1. 封装函数,返回元素e的第n个兄弟元素节点,n为正,返回后面的兄弟元素节点,n为负,返回前面的,n为0,返回自己。
  • 不考虑兼容性
function retSibling(e, n) {
  while(e && n) {
    if(n > 0) {
      e = e.nextElementSibling;
      n--;
    } else {
      e = e.previousElementSibling;
      n++;
    }
    return e;
  }
}
  • 考虑兼容性
function retSibling(e, n) {
  while(e && n) {
    if(n > 0) {
      if(e.nextElementSibling) {
        e = e.nextElementSibling;
      } else {
        for(e=e.nextSibling; e && e.nodeType  != 1; e = e.nextSibling);
      }
      n--;
    } else {
      if(e.previousElementSibling) {
        e = e.previousElementSibling;
      } else {
        for(e = e.previousSibling; e && e.nodeType != 1; e = e.previousSibling);
      }
      n++;
    }
    return e;
  }
}
  1. 编辑函数,封装myChildren功能,解决以前部分浏览器的兼容性问题。(找该元素的子元素节点)
Element.prototype.myChildren = function() {
  var child = this.childNodes;
  var len = child.length;
  var arr = [];
  for(var i=0; i<len; i++) {
    if(child[i].nodeType ==1) {
      arr.push(child[i]);
    }
  }
  return arr;
}
  1. 自己封装hasChildren()方法,不可用children属性。
Element.prototype.myChildren = function() {
  var child = this.childNodes;
  var len = child.length;
  for(var i=0; i<len; i++) {
    if(child[i].nodeType ==1) {
      return true;
    }
  }
  return false;
}
  1. 请编写一段 JavaScript脚本生成下面这段DOM结构。要求,使用标准的DOM方法或属性。
    <div class="example">
    <p class="content"></p>
    </div>
<body>
    <script>
        var div = document.createElement('div');
        var p = document.createElement('p');
        div.setAttribute('class', 'example');
        p.setAttribute('class', 'content');
        p.innerHTML = '这里是仙女萝';
        div.appendChild(p);
        document.body.appendChild(div);
    </script>
</body>
效果
  1. 封装函数 insertAfter();功能类似 insertBefore();
<body>
    <div>
        <i></i>
        <b></b>
        <span></span>
    </div>

    <script>
        Element.prototype.insertAfter = function(targetNode, afterNode) {
            var beforeNode = afterNode.nextElementSibling;
            if(beforeNode == null) {
                this.appendChild(targetNode);
            } else {
                this.insertBefore(targetNode, beforeNode);
            }            
        }
        var div = document.getElementsByTagName('div')[0];
        var i = document.getElementsByTagName('i')[0];
        var b = document.getElementsByTagName('b')[0];
        var span = document.getElementsByTagName('span')[0];
        var p = document.createElement('p');
    </script>
</body>
效果
  1. 将目标节点内部的节点顺序逆序
    example: <div><a></a><em></em></div>
    <div><em></em><a></a></div>
<body>
    <div>
        <i></i>
        <b></b>
        <span></span>
    </div>

    <script>
        var div = document.getElementsByTagName('div')[0];
        Element.prototype.reverseChild = function() {
            var arr = this.children;
            for(let i = arr.length-1; i > 0; i --) {
                // console.log(arr[i-1]);
                this.appendChild(arr[i-1]);
            }
        }
    </script>
</body>
效果
  1. 计时器,到三分钟停止
<body>
    minutes: <input type="text" value="0">
    seconds: <input type="text" value="0">

    <script>
        var minutesNode = document.getElementsByTagName('input')[0];
        var secondsNode = document.getElementsByTagName('input')[1];
        var minutes = 0, 
            seconds = 0;
        var timer = setInterval(function() {
            seconds ++;
            if(seconds === 60) {
                seconds = 0;
                minutes ++;
            }
            secondsNode.value = seconds;
            minutesNode.value = minutes;
            if(minutes == 3) {
                clearInterval(timer);
            }
        }, 1000);
    </script>
<body>

10 . 让小方块移动

<body>
    <div style="width: 100px; height: 100px; background-color:pink;
    position: absolute; left: 0; top: 0;"></div>
    <script>
        var div = document.getElementsByTagName('div')[0];
        
        function getStyle(elem, prop) {
            if(window.getComputedStyle) {
                return window.getComputedStyle(elem, null) [prop];
            } else {
                return elem.currentStyle[prop];
            }
        }

        var timer = setInterval(function() {
            div.style.left = parseInt(getStyle(div, 'left')) + 10 + 'px';
            if(parseInt(div.style.left) > 500) {
                clearInterval(timer);
            }
        }, 100)
    </script>
</body>
  1. 使用原生js,addEventListener,给每个li元素绑定一个click事件,输出他们的顺序。
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>
<script>
  var liCol = document.getElementsByTagName('li');
  var len = liCol.length;
  for(var i=0; i<len; i++) {
    (function(i) {
      liCol[i].addEventListener('click', function() {
        console.log(i);
      }, false)
    }(i))
  }
</script>
  1. 取消a标签默认事件
var a = document.getElementsByTagName('a')[0];
a.onclick = function() {
  return false;
}
<a href="javascript:void(0)">demo</a>
  1. 小方块拖拽
<body>
    <div style="width: 100px; height: 100px; background-color: orange; 
    position:absolute; left: 0; top: 0;"></div>
    
    <script>
        var div = document.getElementsByTagName('div')[0];
        var disX,
            disY;

        div.onmousedown = function(e) {
            disX = e.pageX - parseInt(div.style.left);
            disY = e.pageY - parseInt(div.style.top);
            document.onmousemove = function (e) {
                var event = e || window.event;
                console.log(e.pageX + " " + e.pageY);
                div.style.left = event.pageX - disX + 'px';
                div.style.top = event.pageY -disY + 'px';
            }   
            document.onmouseup = function() {
                document.onmousemove = null;
            }
        }
    </script>
</body>
<script>
  // 阻止默认事件
  function cancelHandler(e) {
    if (e.preventDefault) {
      e.preventDefault();
    } else {
      e.returnValue = false;
    }
  }

  // 阻止冒泡
  function stopBubble(event) {
    if (event.stopPropagation) {
      event.stopPropagation();
    } else {
      event.cancelBubble = true;
    }
  }

  // 绑定事件
  function addEvent(elem, type, handle) {
    if (elem.addEventListener) {
      elem.addEventListener(type, handle, false);
    } else if(elem.attachEvent) {
      elem.attachEvent('on' + type, function () {
        handle.call(elem);
      })
    } else {
      elem['on' + type] = handle;
    }
  }

  // 鼠标移动时
 function mouseMove(e) {
    var event = e || window.event;
    elem.style.left = event.clientX - disX + 'px';
    elem.style.top = event.clientY - disY + 'px';
  }
  
  // 鼠标松开时
  function mouseUp(e) {
    var event = e || window.event;
    removeEvent(document, 'mousemove', mouseMove);
    removeEvent(document, 'mouseup', mouseUp);
  }

  // 鼠标拖拽
  function drag(elem) {
    var disX,
        disY;
    addEvent(elem, 'mousedown', function(e) {
        var event = e || window.event;
        disX = event.clientX - parseInt(getStyle(elem, 'left'));
        disY = event.clientY - parseInt(getStyle(elem, 'top'));
        addEvent(document, 'mousemove', mouseMove);
        addEvent(document, 'mouseup', mouseUp);
        stopBubble(event);
        cancelHandler(event);
    });
  } 
</script>
  1. 输入框功能完善
 <input typt="text" value="请输入用户名" 
    style="color: #999"
    onfocus="if(this.value == '请输入用户名'){this.value=''; this.style.color='#424242'}"
    onblur="if(this.value == ''){this.value='请输入用户名'; this.style.color='#999'}">
  1. 二阶菜单栏
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 参考书:《JavaScript高级程序设计》 知识点前提:什么是节点 Node类型 DOM1级定义了一个Node接...
    DHFE阅读 404评论 0 0
  •   DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API(应用程序编程接口)。   DOM 描绘...
    霜天晓阅读 3,619评论 0 7
  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,477评论 1 11
  •   DOM 1 级主要定义的是 HTML 和 XML 文档的底层结构。   DOM2 和 DOM3 级则在这个结构...
    霜天晓阅读 1,428评论 1 3
  • DOM DOM把一份文档表示为一棵树(这是所说的“树”是数学意义上的概念),这是我们理解和运用这一模型的关键。更具...
    我是猪队友Y阅读 181评论 0 0