DOM 对象 => 宿主对象
DOM 是操作 HTML 和 XML的
JavaScript中的三种对象
- 
本地对象
Native ObjectObject Function Array Number Boolean Error EvalError SyntaxError RangeError ReferenceError TypeError URIError Date RegExp - 
内置对象
Built-in ObjectGlobal Math ECMA => isNaN parseInt Number decodeURI encodeURI Infinity NaN undefinedglobal在JavaScript中是不存在的,全局下的这一些方法都属于global - 
宿主对象
Host Object浏览器对象 window(BOM) 和 Document(DOM) -> DOM 是被BOM包含的 现在是被拆开的,为什么是拆开的呢 是因为 DOM 是有 W3C 规范的 - 
模型
 
Document
- document.getElementByid 在
Ie8以下是不区分大小写的,在ie8以下是可以根据标签的name获取到这个元素的 - document.getElementsByTagName 根据标签名获取一组元素 返回的是类数组
 - document.getElementsByClassName 根据className 获取一组元素 返回的是类数组
- byClassName兼容到IE8
 
 - document.getElementsByName 根据标签的Name获取一组元素 返回的是类数组 原则上是必须得有name数组的标签但是根据浏览器的不同 只要你写name就可以用到 非常不常用
 - document.querySelector 根据css获取元素 获取到当前DOM的第一个
 - document.querySelectorAll  根据css获取元素 获取一组元素
- querySelector,.querySelectorAll 这两个兼容到 IE7 企业一般不让用
 - 存在性能问题
 - 致命的弱点获取的DOM不实时更新
- 就比如我们 
remove删除了这个DOM元素 这个元素还会在这个伪数组中保存 
 - 就比如我们 
 
 
节点树
遍历节点树 元素节点树

- parentNodes 获取父级节点 => 最顶级是document
 - childNodes 获取子级节点
- 元素节点 = 1
 - 属性节点 = 2
 - 文本节点 test = 3
 - 注释节点 comment = 8
 - document = 9
 - documentFragment = 11
 
 - lastChild firstChild
 - nextSibling previousSibling
 
遍历元素节点树
- parentElement => 最顶级是Html   
IE9及一下不支持 - children 
IE7及一下不支持 - childElementCount = children.length 
IE9及一下不支持 - firstElementChild lastElemntChild 
IE9及一下不支持 - nextElementSibling previousElementChild 
IE9及一下不支持 
为什么parentNodes的顶级是document而parentElement是html?
获取元素兼容性解决方案
/**
 * @description:  获取所有子元素
 * @param {*} node
 * @return {*}
 */
function getChildElementNodes(node) {
    var len = node.childNodes.length,
        childNodes = node.childNodes,
        nodeArr = [],
        elem;
    for (var i = 0; i < len; i++) {
        elem = childNodes[i]
        if (elem.nodeType === 1) {
            nodeArr.push(elem)
            // nodeArr[nodeArr['length']] = elem
            // nodeArr['length']++
        }
    }
    return nodeArr;
}
/**
 * @description: 获取第一个元素节点
 * @param {*} node
 * @return {*}
 */
function getFirstELementChildNode(node) {
    var elem = node.firstChild
    while (elem && elem.nodeType !== 1) {
        elem = elem.nextSibling
    }
    return elem
}
/**
 * @description: 获取最后一个元素节点
 * @param {*} node
 * @return {*}
 */
function getLastELementChildNode(node) {
    var elem = node.lastChild
    while (elem && elem.nodeType !== 1) {
        elem = elem.previousSibling
    }
    return elem;
}
/**
 * @description:  获取下一个兄弟元素
 * @param {*} node
 * @return {*}
 */
function getNextSiblingElementNode(node) {
    var elem = node.nextSibling
    while (elem && elem.nodeType !== 1) {
        elem = elem.nextSibling
    }
    return elem
}
/**
 * @description: 获取上一个兄弟元素
 * @param {*} node
 * @return {*}
 */
function getPreviousSiblingElementNode(node) {
    var elem = node.previousSibling
    while (elem && elem.nodeType !== 1) {
        elem = elem.previousSibling
    }
    return elem;
}
节点的属性方法
元素节点   = 1 
属性节点   = 2
文本节点  test  = 3
注释节点  comment  = 8
document = 9
documentFragment = 11
// ------------------------
getAttributeNode() 获取属性节点 
attributes 获取属性集合 => 类数组
- nodeName  元素节点的nodeName 
大写只读 - nodeValue   节点的值 
可读可写- 元素节点没用
nodeValue属性 - 属性 注释 文本可用
 
 - 元素节点没用
 - value 获取属性节点的值
 - nodeType 获取节点类型 
只读 - hasChildNodes 该元素的是否有子节点
 
DOM结构树

DOM操作深入
- getElementById()
- 只有在Document.prototype 上有getElementById()
 
 - getElementsByName()
- 只有在Document.prototype 上有getElementsByName()
 
 - getElementsByTagName() | getElementByClassName() | querySelector | querySelectorAll
- Document.prototype 和 Element.prototype 都有 getElementsByTagName() | getElementByClassName() | querySelector | querySelectorAll
 
 - document.body
- 获取的时body元素
 - 在HTMLdocument上
 
 - document.head
- 获取的时head元素
 - 在HTMLdocument上
 
 - document.title
- 获取的是title里面的文本,不是title元素
 - 在HTMLdocument上
 
 - document.documentElement
- 获取html元素
 - 在Doducment上
 
 
// 示例
// 1. 当我们想选择某个ID下的某些标签可以利用DOM原型这个关系进行选择
document.getElementById('box').getElementsByTagName('div') // 由于Element.prototype上也有getElementsByTagName所以可以进行选择
小案例
/**
 * @description: 获取任意子元素
 * @param {Number}  子元素索引 不传返回全部
 * @return {*} 任意子元素
 */
HTMLElement.prototype.getChild = function () {
  // var nodes = [],
  var nodes = {
      splice: Array.prototype.splice,
      push: Array.prototype.push,
      length: 0
    },
    arg1 = arguments[0],
    len = this.childNodes.length,
    child = this.childNodes
  for (var i = 0; i < len; i++) {
    if (child[i].nodeType === 1) {
      nodes[nodes.length] = child[i]
      nodes.length++
    }
  }
  return arg1 ? nodes[arg1] || nodes : nodes
}
/**
 * @description: 获取N层父节点
 * @param {Number} 获取的第N层不传查上一层,大于顶级节点的索引返回最后一层
 * @return {*} N层的父元素
 */
HTMLElement.prototype.getParent = function () {
  var parentNode = this,
    oldParentNode,
    arg1 = arguments[0] || 1
  while (arg1 && parentNode) {
    oldParentNode = parentNode
    parentNode = parentNode.parentNode;
    arg1--
  }
  return parentNode || oldParentNode;
}
节点的创建
- 
document.createElement 创建元素节点
- Document.prototype
 
 - 
document.createTextNode 创建文本节点
- Document.prototype
 
 - 
document.createComment 创建注释节点
- Document.prototype
 
 - 
parent.appendChild 增加子节点
- Node.prototype
 - 动态增加节点,动态剪切节点
- 如我们在文档中获取了某个标签,appendChild到指定节点,我们发现之前获取的哪个节点到了指定的节点中.
 - 其实我们在使用appendChild的时候,他的操作流程是,剪切过来然后复制进去
 
 - 这个方法的参数必须是节点或者元素
 
 - 
c.insterBefore(a,b) 插入节点
- Node.prototype
 - c中插入a节点,在b节点前
 
 - 
parent.removeChild() 删除子节点
- Node.prototype
 - 其实是剪切子节点,并没有删除这个节点,这个节点还在内存中,只是这个节点不再dom结构里了,他无法去删除掉存在内存中的这个dom对象
 
 - 
div.remove() 删除节点
- Node.prototype
 - 删除节点并且删除这个dom对象
 
 - 
parent.replaceElement(newEle,oldEle) 替换节点
- Node.prototype
 
 - 
div.innerHTML
- HTMLElement.prototype
 - Element.prototype
 - 可读可写
 - 赋值 取值 追加值 添加HTML字符串
 
 - 
div.innerText
 - 
火狐老版本不支持 使用 textContent 代替 textContent 老版本IE不支持
 - 
HTMLElement.prototype
 - 
div.setAttribute('type','value') 设置属性
- Element.prototype
 
 - 
div.getAttribute('type') 获取属性
- Element.prototype
 
 - 
div.dataset 获取属性
- 
获取自定义属性 data-*
<div data-name='zs' data-age='18'> 我是div </div> 通过dataset获取标签中的自定义属性 返回值是一个对象 {name:'zs',age:'18'} 
 - 
 - 
document.createDocumentFragMent() 创建文档片段**(碎片)**
- 减少回流
 
 
元素如何变成元素节点
当我们使用选择器选择了元素是,他会经历那些步骤,以div为例
- 元素 => 实例化对象 => 节点
 - 也就是说 选中div这个元素的时候 他会实例化 new HTMLDivELement,这个时候DOM对象就产生了,DOM对象等于DOM节点
 - 这个对象存在内存中,因为他是引用类型,所以存在堆中.
 
回流
滚动距离高度,可视尺寸
滚动距离
- 
window.pageXOffsetwindow.pageYOffset获取X轴滚动距离和Y轴滚动距离- IE9及IE8以下不支持
 - IE9及IE8对应的属性是 
document.documentElement.scrollTopdocument.documentElement.scrollLeftdocument.body.scrollTopdocument.body.scrollLeft - 不常见的是
window.scrollXwindow.scrollY 
// 兼容性封装 function getScroll() { if (window.pageXOffset !== undefined) { return { left: window.pageXOffset, right: window.pageYOffset } } else { return { left: document.body.scrollLeft + document.documentElement.scrollLeft, top: document.body.scrollTop + document.documentElement.scrollTop } } } 

浏览器可视区域的尺寸(窗口宽高)
- 
常规: window.innerWidth/window.innerHeight
- 获取可视区域尺寸宽/高
 
 - 
IE9/IE8及以下:
- 标准模式
- docuemnt.docuemntELement.clientWidth/clientHeight
 - 获取可视区域的宽/高
 
 - 怪异模式
- document.body.clientWidth/clientHeight
 - 获取可视区域的宽/高
 
 
// 获取浏览器可视区域尺寸兼容性封装 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 }; } } } - 标准模式
 
获取整个文档尺寸(整个html的宽度高度)
- document.body.scrollWidth/scrollHeight
- 获取文档的宽/高
 
 - document.documentElement.scrollWidth/scrollHeight
- 获取文档的宽高 IE567
 
 
获取元素的尺寸位置
- oBox.getBoundingClientRect
- 优点基本上所有尺寸都能获取的到,致命的缺点属性不实时
 - ie 678 没有宽高
 
 
{
    bottom: 150
    height: 120
    left: 30
    right: 150
    top: 30
    width: 120
    x: 30
    y: 30
}
获取元素的位置
- elem.offsetTop/offsetLeft 获取元素当前距离顶部距离左侧的位置
- 注意是获取当前元素到上一个定位父级元素,**如果父级元素没有定位则向上查找,**如果所有的父级都没有定位则找到body
 
 - elem.offsetParent 获取上一个带有定位的父级元素 如果都没有定位则找到body
 
操作滚动条
- window.scroll/scrollTo/scrollBy 操作滚动条 第一个参数是X轴第二个参数是Y轴
- scroll/scrollTo 滚动至文档中的绝对位置(当前滚动条滚动到参数的位置)
 - scrollBy 滚动指定的距离 (当前滚动条的距离加上参数的距离)
 
 
浏览器的怪异模式和标准模式
浏览器有自己的各自的兼容性模式,浏览器默认的兼容格式(向后兼容).浏览器厂商一般兼容5个版本,如果写了DOCTYPE html就得遵守W3C规范,如果不写!DOCTYPE html 则按照浏览器自己的规则兼容
写了!DOCTYPE html 则为标准模式 ,不写DOCTYPE html则为怪异模式
验证是怪异模式还是标准模式
document.compatMode
// 标准模式  || 怪异模式
// "CSS1Compat" || "BackCompat"
读写样式属性
- elem.style.CSS属性
- 可读可写
 - 注意如果CSS属性单词出现两个及以上必须使用小驼峰 如: 
borderColor - 值 需字符串 如: 
elem.style.borderWidth = '10px' - 符合值必须进行拆解 如: 
1px solid #fff需拆解成borderWidth = '1px'; borderStyle = 'solid'等 - 保留字前必须加
css如:elem.style.cssFloat = 'left' 
 - elem.style 获取当前元素可以设置的样式集合
 - window.getComputedStyle(element,null) 获取元素计算样式属性
 getComputedStyle的第二个参数如果写的话则是获取伪元素样式,例如:getComputedStyle(element,'after')- 如果该元素没有设置这个样式属性则为默认样式属性
 - IE8及以下不支持对应的属性是
- element.currentStyle
 
 
设置class属性
- element.className 获取class属性,可读可写
 
事件
- onclick = function(){}
- 此时的onclick句柄
 - onclick = function(){} 事件句柄
 - oDiv.onclick = function(){} 事件句柄的绑定形式
 
 - onclick = null
 - element.addEventListener(事件类型,事件处理函数,布尔)
- ie8及以下 element.attachEvent(事件类型,事件处理函数)
 
 - element.removeEventListener(事件类型,事件处理函数)
- ie8及以下 element.detachEvent(事件类型,事件处理函数)
 
 
事件状态冒泡与捕获
事件冒泡就是从里层元素向外层元素同事件一层一层的触发为事件冒泡反之为事件捕获
- event 事件对象的兼容
- event || window.event
 
 - event.stopPropagation 阻止事件冒泡 ie8 及以下不支持 W3C标准
- event.cancelBubble = true ie8及以下阻止事件冒泡
 
 - event.preventDefault 阻止默认事件 ie8及以下不支持 W3C标准
- event.returnValue = false 阻止默认事件 Ie8及以下
 - return false 阻止默认事件 兼容性极强 但是不常用
 
 
事件流
- IE 提出的 事件冒泡流(Event Bubbling)
 - Netscape 提出的 事件捕获流 (Event Capturing)
 
事件流的三个阶段
- 先捕获 在冒泡
 - 处于目标阶段也就是事件源不处于冒泡或者捕获问题,按照代码执行顺序执行
 
DOM级别问题
- 
DOM0
- onXXX = fun
 - elem.onXXX = fun
 
 - 
DOM1
- 没有定义事件模型
 
 - 
DOM2
- addEventListener(三个参数) W3C规范
 - removeEventListener(事件类型,事件处理函数)
 
 
事件对象
- 事件处理函数中有个参数event是事件对象
- ie8及以下的事件对象在window中
 
 - event.target || event.srcElement 是事件源
- scrElement ie9及以下
 
 
事件代理,事件委派
parentEle.onclick = function(e){
	var e = e || window.event,
        tar = e.target || e.currentElement
    
}
- 取元素列表中事件源的下标
 
parentEle.onclick = function(e){
    var e = e || window.event,
        tar = e.target || e.currentElement
    for(var i = 0; i < len; i++){
       if( oList[i] === tar ){
           console.log(i)
       }
    }
}
// 最佳解决办法
parentEle.onclick = function(e){
    var e = e || window.event,
        tar = e.target || e.currentElement
 Array.prototype.indexOf.call(oList,tar)
}
- 事件代理究竟是干什么
- 解决多次事件绑定绑定同一个回调函数,例如50个li绑定事件,如果重复绑定的话就绑定了50个回调函数并且,新增的标签没有事件
 
 
鼠标行为
坐标系
- 
event.clientX/Y 鼠标位于当前可视区域的坐标(不包含滚动条的距离)
 - 
layerX/Y 与pageX/Y相同,IE11以下同clientX/Y
 - 
screenX/Y 鼠标位于屏幕的坐标
 - 
x/y 于clientX/Y相同, FF(火狐不支持)
 - 
pageX/Y 鼠标位于文档的坐标(包含滚动条的距离)
- ie9及以下不支持(Jquery)
 
 - 
offsetX/Y 鼠标位置相对于块元素的坐标
- 
包含边框,safari不包含边框 不推荐使用
 
 - 
 
获取文档偏移量IE8及以下
- document.documentELement.clientLeftt
 
鼠标事件
- 
mousedown 鼠标按下事件
 - 
mouseup 鼠标抬起事件
- event.button 判断触发当前事件的是鼠标哪个按键
- 通常高级浏览器为 0 1 2 左中右
 
 
 - event.button 判断触发当前事件的是鼠标哪个按键
 - 
contextmenu 右键菜单事件
- 通常给他禁止掉 event.prventDefault
 
 - 
mouseover 鼠标移入
 - 
mouseout 鼠标移出
 - 
mouseenter 鼠标移入
- 与mouseover 本质的区别是在于 他不会触发冒泡及mouseenter是对被绑定的元素生效, mouseout 是对被绑定的元素及所有的子元素生效
 
 - 
mouseleave 鼠标移出
 
input事件
- IE9及以下 onpropertychange 输入时反馈
 - IE9以上 oninput 输入时反馈
 - onchange 失去焦点时反馈 如果进入焦点与失去焦点值一样则不反馈
 - onfocus 进入焦点
 - onblur 失去焦点
 
自定义事件
// 为什么要在HTML的原型上添加
// 1. HTMLElement是元素节点的直接上级 例如HTMLDivElement 我们看到他的直接上级是HTMLELement所以在HTMLELement的原型上定义是最合理的
// 2. 我们要进行判断需要绑定的事件是什么事件 需要进行什么样的处理
// 3. 我们想到了自定义事件必须使用的构造器 Event https://developer.mozilla.org/zh-CN/docs/Web/API/Event 详见MDN
HTMLElement.prototype.bindEvent = function(type,callBack){
   var elem = this, // 储存元素
	   _event = new Event(type);
    
   elem.addEventListener(type,callBack,false)
   	function dispatch(){
        elem.dispatchEvent(_event)
    }
    function remove(){
        elem.removeEventListener(type,callBack,false)
    }
    return {
        dispatch,
        remove
    }
}
监视DOM节点的变化
- MutationObserver.prototype.disconnect 阻止监听/停止监听
 - MutationObserver.prototype.observe 在DOM更改时通过其回调函数接收通知
 - MutationObserver.prototype.akeRecords 通知队列中删除所有待处理的的通知
 - 详见: developer.mozilla.org/zh-CN/docs/…
 
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
 - 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
 
- 提示下载完但解压或打开不了?
 
- 找不到素材资源介绍文章里的示例图片?
 
- 模板不会安装或需要功能定制以及二次开发?
 
                    
    
发表评论
还没有评论,快来抢沙发吧!