DOM树:把html结构看作是一个倒挂的树状结构,树根则为document对象(有属性和方法)
document对象不需要创建,由浏览器的js解释器自动创建,且一个页面只有一个document
Document Object Model 提供了专门操作HTML文档的API
DOM
1.概念
DHTML:动态的HTML,一切实现网页动态效果的技术的统称。DHTML=HTML+CSS+JS(DOM)
HTML/XHTML/DHTML/XML
HTML:超文本标记语言,网页
XHTML:可扩展超文本标记语言,更严格的网页
DHTML:动态网页
XML:数据格式
DOM:本来可以操作一切结构化文档(XHTML/XML),分为三部分:
- 核心DOM:万能,但API繁琐
- HTML DOM:只能操作HTML文档,API简单
- XML DOM
2.DOM树
保存所有网页内容的树状结构,树根(document)不需要创建,由浏览器的js解释器自动创建
DOM节点/对象/元素:一个标签、文本、属性、注释等
每个阶段都有三大属性:
xx.nodeType获取xx的节点类型
document(9)、文本节点(3)、属性节点(2)、元素标签(1)
xx.nodeValue获取属性节点的节点值xx.nodeName获取属性节点的名字
- 应用:直接找自带可能找到多个标签,但想对不同标签做对应操作
- 注意:获取到的标签名都是大写
3.通过节点关系获取元素
- 子元素找父元素:
xx.parentNode(单个元素) - 父元素找子元素:
xx.children(集合) - 父元素找第一个子元素:
xx.firstElementChild(单个元素) - 父元素找最后一个子元素:
xx.lastElementChild(单个元素) - 前一个兄弟元素
xx.previousElementSibling(单个元素) - 后一个兄弟元素
xx.nextElementSibling(单个元素)
4.递归
函数中,再次调用自己,但会让它停下来
- 作用:专门用于遍历层级不明确的树状结构
- 步骤:
-
创建函数,传入实参树根,形参接住,直接做第一层的操作
function f1(root){第一层操作} -
调用函数
f1(实际的根元素)
-
//例:给表格添加边框
function getChildren(root){
root.style.border="solid 1px #000";
for(var i=0;i<root.children.length;i++){
getChildren(root.children[i]);
}
}
- 算法:深度优先,优先遍历当前节点的子节点,子节点遍历完才会跳到兄弟节点
- 递归优点:直观易用
- 递归缺点:效率低,占内存空间。用于遍历层级不明确的DOM
5.遍历API
用于遍历层级不明确的树状结构,步骤:
- 创建treewalker对象
var tw=document.createTreeWalker(root,NodeFilter.SHOW_ALL)
var tw=document.createTreeWalker(root,NodeFilter.SHOW_ELEMENT)找元素
- 反复调用nextNode方法
while((var node=tw.nextNode())!=null){node;//当前节点做什么操作}
注意:深度优先算法,此方法必须跳过起点
6.纯循环遍历层次不明确的树状结构
不用遍历API(只能遍历页面元素);也不用纯循环遍历(难度大);遇到层级不明确时,使用递归(不仅遍历元素,还遍历数据)
7.获取元素
通过html的属性获取元素
- id:
var elem=document.getElementById("id");- 返回的是DOM对象,可直接操作
- 若id重复,只返回第一个
- 若未找到id,返回null
- 标签名:
var elems=document.getElementsByClassName("标签名"); - class:
var elems=document.getElementsByClassName("class");- 返回的时DOM集合,不可以直接操作:添加下标可以得到某个对象/遍历 则可以操作
- 若未找到,返回空集合
- 该方法可以使用parent(已找到的某个父元素)
- name
var elems=document.getElementsByName("name");
通过节点之间的关系获取元素
前提:先找到一个元素,才能找到对应关系
- 子元素找父元素:
xx.parentNode(单个元素) - 父元素找子元素:
xx.children(集合) - 父元素找第一个子元素:
xx.firstElementChild(单个元素) - 父元素找最后一个子元素:
xx.lastElementChild(单个元素) - 前一个兄弟元素
xx.previousElementSibling(单个元素) - 后一个兄弟元素
xx.nextElementSibling(单个元素)
按css选择器进行查找
- 单个元素:未找到时null,多个元素只会找到第一个
var elem=document.querySelector("任意css选择器"); - 多个元素:找到是一个集合,未找到时一个空集合
var elems=document.querySlectorAll("任意css选择器");
getxx和querySelectorxx的区别:
- 返回结果不同
- get:返回的时一个动态集合(DOM树每次被修改,都会再次查找)
- querySelector:返回的是一个静态集合(DOM树每次被修改,不会再次查找,只管第一次找到的结果)
- 动态集合:不支持forEach;静态集合:支持forEach(类数组)
- 复杂查找时,使用querySelectorAll
8.操作元素
一切的获取都是为了判断,一切的设置都是为了修改
内容
- innerHTML 用于操作双标签,能识别标签
- 获取:
elem.innerHTML - 设置:
elem.innerHTML="新内容";
- 获取:
- innerText 用于操作双标签,不能识别标签value
- 获取:
elem.innerText - 设置:
elem.innerText="新内 容";
- 获取:
- value 用于操作input
- 获取:
elem.value - 设置:
elem.value="新内容";
- 获取:
属性
- 获取:
- 核心DOM:
elem.getAttribute("属性名"); - HTML DOM:
elem.属性名
- 核心DOM:
- 设置:
- 核心DOM:
elem.getAttribute("属性名","属性值"); - HTML DOM:
elem.属性名="属性值";
- 核心DOM:
- 删除属性值:会删除整个属性节点
- 核心DOM:
elem.removeAttribute("属性名"); - elem.属性名="";赋值为空,但未删除。有的属性仅有属性名也具有效果(disable、href)
- 核心DOM:
- 判断属性值:只能判断有无属性
- 核心DOM:
elem.hasAttribute"属性名" - if(elem.getAttribute("属性名")==值){}
- 核心DOM:
- 注意:
- class在js里面是关键字,所以要写成className
- 自定义属性只能用DOM操作
样式
- 内联样式表
- 获取:
elem.style.css属性名; - 设置:
elem.style.css属性名="css属性值"; - 注意:
- 优点:1.优先级最高,保证了用户触发一定会生效;2.只会操作当前元素
- 缺点:获取样式时,一定要保证此样式在内联样式表里面
- css属性名中若有横线需要去掉,改为小驼峰命名法
- 获取:
- 内部/外部样式表:
document.styleSheet[i].cssRules[i].style.background- 获取样式表
var sheet=document.styleSheet[i]; - 获取样式规则
var rules=sheet.cssRules; - 获取想要的操作
var rule=rules[i]; - 获取或修改样式
rule.style.background="pink";
- 获取样式表
9.创建元素&渲染页面&删除元素
- 创建元素
var 空标签=document.createElement("标签名");- 设置必要属性和方法
- 空标签.属性名="属性值";
- 空标签.on方法=function(){}
- 渲染页面
- 添加:
父元素.appendChild(新元素);新元素会插入到父元素最后 - 插入:
父元素.insertBefore(新元素,已有子元素);新元素会插入到已有子元素之前 - 替换:
父元素.replaceChild(新元素,已有子元素);新元素会替换已有子元素
- 添加:
- 删除元素
元素.remove
10.HTML DOM 提供的对象
简化部分核心DOM操作
image
简化创建var img=new Image();
- 在DOM中,不是人人都有构造函数创建方式
form
- 简化查找元素
var form=document.forms[i]; - 简化查找表单控件
var input=form.elements[i] - 专属事件
onsubmit提交时触发,可阻止提交return false
select
- 专属事件
onchange选中项发生改变时触发 - 属性
- options===children 获取到select下所有option
- selectedIndex 获取到当前选中项下标
- 方法
- select.add(option) 获取到select下所有option
- select.remove(i) 删除select中第i个option
option
- 简化创建
var opt=new Option("innerHTML","value");
select.add(new Option("innerHTML","value"))
BOM
Browser Object Model 浏览器对象模型:提供了专门用于操作浏览器的API(没有标准,且使用较少。大部分浏览器厂商已统一实现,除老IE)
BOM对象:window、history、location、navigator、event、screen...
1.window对象
- 浏览器中,window代替了ES的Global,充当全局作用域(包含了所有全局对象、变量、函数)
- 指代了当前浏览器的窗口
网页打开新链接的方式
- 替换当前页面,可以后退
- HTML
<a href="#">链接</a>//默认target="_self" - js:先添加点击事件
open("url","_self")
- HTML
- 新窗口打开,可以打开多个
- HTML
<a href="#" target="_blank">链接</a> - js:先添加点击事件
open("url","_blank")
- HTML
- 新窗口打开,只能打开一个【应用:支付结账窗口】
- HTML
<a href="#" target="自定义">链接</a> - js:先添加点击事件
open("url","自定义")
- HTML
- 替换当前页面,禁止后退【应用:结账完毕后,不允许后退】
- js:
location.replace(新url)//替换当前网址,不会产生历史记录- history对象 保存了当前窗口的历史记录,功能:前进后退
- location 保存了当前窗口正在打开的url
- js:
window对象
- 获取浏览器窗口的大小
+ 屏幕的大小
screen.width/height+ 完整浏览器的大小outerWidth/outerHeight+ 文档显示区域的大小innerWidth/innerHeight - 方法:
- 打开新窗口
open("url","自定义name","width=,height=,left=,top=");- height、width 没有单位,宽高设置不小于200
- 若未传入参数3,新窗口会和浏览器并为一体
- 若传入参数3,新窗口会脱离浏览器,可能会被浏览器拦截
- 关闭窗口
窗口.close(); - 修改窗口大小(只能用于新窗口)
新窗口.resizeTo(宽,高); - 修改窗口位置
新窗口.moveTo(x,y)
- 打开新窗口
- 定时器
- 周期性定时器(先等待,再执行一次)重复
- 开启
timer=setInterval(function(){},毫秒数) - 停止
clearInterval(timer)
- 开启
- 一次性定时器(先等待,再执行一次)
- 开启
timer=setTimeout(function(){},毫秒数) - 停止
clearTimeout(timer)
- 开启
- 周期性定时器(先等待,再执行一次)重复
窗口底层都有一个名字,若出现重复的名字则新窗口会替换掉原来的窗口
2.history
保存了当前窗口的历史记录
- 前进 history.go(1)
- 后退 history.go(-1)
- 刷新 history.go(0)
3.location
保存了当前窗口正在打开的url
一个url由5部分组成
- 协议:http/https/ftp/ws
- http/https 请求响应模式,https安全性更高
- ftp 传输文件
- ws 广播收听模式(直播)
- 主机号/域名 127.0.0.1/www.baidu.com
- 主机号不便于记忆,企业会选择购买域名
- 端口号
- http 80
- https 443
- 文件的相对路径
- 查询字符串:表单提交到服务器内容,请求信息
属性
url5部分相关,使用console.log(location)控制台查找使用
API
- 跳转
location="新url"location.href="新url"location.assign("新url")
- 替换后禁止后退
location.replace("新url") - 刷新
location.reload()
4.navigator
保存了当前浏览器的信息(浏览器版本号/名称)
navigator.userAgent根据字符串截取浏览器名称、版本号:本身目的是做兼容,但未使用,因为API都已经设置好兼容
5.event
事件:由用户触发或浏览器自动触发的事件
绑定事件
1.直接在html元素上绑定 <elem on事件名="js语句"></elem>
- 缺点:
- 没有实现js与html的分离
- 无法动态绑定事件
- 无法同时绑定多个函数对象
2.使用js的事件属性绑定 elem.on事件名=function(){js语句}
- 优点:
- js与html的分离
- 动态绑定事件
- 缺点:无法同时绑定多个函数对象
3.使用js的API属性绑定 elem.addEventListener("事件名",function(){})
- 优点:
- js与html的分离
- 动态绑定事件
- 同时绑定多个函数对象
- 缺点:兼容性问题
- IE
elem.attachEvent("on事件名",function(){})
- IE
if(elem.addEventListener){
elem.addEventListener("事件名",function(){})
}else{
elem.attachEvent("on事件名",function(){})
}
事件周期
- 主流
- 捕获阶段:由外向内,记录着要执行的事件
- 目标触发阶段:当前点击的元素优先触发
- 冒泡触发:由内向外
- 老IE 和主流相比无捕获阶段
- 目标触发阶段:当前点击的元素优先触发
- 冒泡触发:由内向外
获取到事件对象event
- 主流 事件函数中传入参数e,就可以自动接住对象event
- 老IE window.event
- 兼容
window.event - 应用
- 获取鼠标的位置
e.screen/client/page - 阻止冒泡
- 主流:
e.stopPropagation() - 老IE:
e.cancelBubble=true - 兼容:
if(e.stopPropagation){ e.stopPropagation(); }else{ e.cancelBubble=true; }
- 事件委托/利用冒泡 优化,每绑定一个事件,就相当于创建了一个事件监听对象,创建对象越多,网页效率越低下
=>把事件都绑定在自己的父元素上:获取目标元素:触发的元素
- 老IE
e.srcElement - 主流
e.target - 兼容
target=e.srcElement
- 组织浏览器的默认行为
- 老IE
e.returnValue=false - 主流
e.preventDefault() - 兼容
if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue=false; }
- 获取键盘的键码
e.keyCode