很长时间以来,我执着于写代码,看代码,不管三七二十一,咚咚咚,几行代码复制粘贴映入眼帘;也许对于我这样的新手来讲,更喜欢看别人的代码,认为别人的就是最好的,看看页面的布局,想想别人重构页面的思路。。。‘做这一行,你要有想法,没想法的人的未来是很糟糕的’,耳边经常有这样如同雷同的话语,而我就是比较喜欢看别人的代码,也许,看着看着,自己的思路也就与别人不一样啦。。。
我不是一个好的程序媛,更谈不上合格这一说,每次写代码,只知道有这个方法,但是具体怎么用,完全是一边百度一边问别人;对于JavaScript的一些方法和属性都有些模糊不清,这也是我写下这篇博客的一个原因。
做技术的人,对于JavaScript都不陌生,JavaScript是网络上最流行的脚本语言,专门实现网页的动态交互功能的;它的三大组成部分是:
① ES(ECMAScript):是JavaScript的核心语法,它就是一套标准,描述了语言的基本语法和数据类型;
② DOM(Document Object Model):文档对象模型,专门操作网页内容的一系列API;
③ BOM(Browser Object Model):浏览器对象模型,专门用来操作浏览器窗口的API;
咱们先来了解一下DOM:
⑴ 什么是DOM?
专门操作网页内容的API
⑵ 三种API
• 核心DOM:可以操作一切结构化文档,包括HTML、XML;
-- 万能的
问题:API繁琐
• HTML DOM:对核心DOM中【部分】常用的API,提供简化的版本;
-- 不是万能的
-- 专门操作HTML网页内容的API
• XML DOM:专门操作XML文档的API
温馨提示:
在实际开发中,选最简单的使用,如果简单的无法实现,就用会用的喽!
这里有必要说一下【HTML/XHTML/XML/DHTML】?
HTML:是专门编写网页内容的语言
XHTML:相对于HTML,语法更加严格
XML:专门存储和传输数据的结构化文档
DHTML:一切可以实现网页动态效果的技术的统称;包含了HTML+CSS+JS
⑶ DOM Tree
• 什么是DOM Tree?
网页的所有内容,在内存中其实是以树形结构存储的
• 什么时候创建的呢?
当浏览器读取到html内容时,会自动创建DOM树
• 如何创建的呢?
① 读到html文档时,先创建根节点对象: document 查找元素,创建元素
② 开始顺序读取html文档的内容,创建子节点:网页中一切内容,都是DOM树上的节点对象
节点对象:Node 所有节点对象的父类型
▪ 三大属性:
▫ node.nodeType:节点的类型,值为数字
何时使用:判断或者区分节点的类型时
如何使用:
document:9
元素节点:1
属性节点:2
文本节点:3
DOCTYPE:10
问题:nodeType无法细致的区分每种元素
▫ node.nodeName:节点的名称
何时使用:判断或区分节点名时,更多用于细致区分每种元素标签名
如何使用:
document:#document
元素节点:标签名 (全大写)
属性节点:属性名
文本节点:#text
DOCTYPE: html
▫ node.nodeValue:节点的值
何时使用:只用于获得属性的值和文本的内容
如何使用:
document:null
元素节点:null
属性节点:属性值
文本节点:文本内容
DOCTYPE: null
节点间关系:
▪ 节点树:
包含所有节点的树结构;任何文本,也都是节点,所以,节点树,会受到看不见的空文本的干扰
何时使用:站在现有节点,查找周边节点
建议:查找节点要就近。
▫ 父子关系:
elem.parentNode => 获得elem的父节点
elem.childNodes ->类数组对象 => 获得elem的所有*直接*子节点
✦ childNodes:返回所有直接子节点对象,保存在一个类数组对象中。
elem.firstChild => 获得elem的第一个子节点
elem.lastChild=> 获得elem的最后一个子节点
▫ 兄弟关系:
elem.previousSibling => 获得elem的前一个兄弟节点
elem.nextSibling=> 获得elem的后一个兄弟节点
▪ 元素树:
仅是节点树的一个子集
优: 仅包含元素节点,不受空文本的干扰
缺: 无法访问文本节点
解决: elem.innerHTML
▫ 父子关系:
parentElement
children
firstElementChild
lastElementChild
▫ 兄弟关系:
previousElementSibling
nextElementSibling
【对比一下】
节点树
元素树 parentNode parentElement childNodes children firstChild firstElementChild lastChild lastElementChild previousSibling previousElementSibling nextSibling nextElementSibling
• 遍历API
① NodeIterator:按照深度优先的原则,依次读取指定父节点下的每个节点
✦ 深度优先:每次都优先遍历子节点,所有子节点遍历完毕,再遍历兄弟节点
✦ 如何使用?
▪ 创建NodeIterator对象
var iterator = document.createNodeIterator(
parent,NodeFilter.SHOW_ALL
null,false.SHOW_ELEMENT
);
▪ 反复调用
var currNode = iterator.nextNode();
▫ 让iterator跳到下一个节点,到头返回null
▫ 强调: 调用一次nextNode,只向前跳一个节点。iterator.previousNode() 退一个节点
② TreeWalker:基本用法和NodeIterator完全一样
✦ 强调:
✧ 不遍历根节点,只遍历子节点
✧ 又提供了向四周跳转的方法:
walker.parentNode();
walker.firstChild();
walker.lastChild();
walker.previousSibling();
walker.nextSibling();
• 查找/修改/创建/删除API
○ 查找
▪ 按HTML属性查找:
▫ 按id查找一个元素:
var elem=document.getElementById("id")
强调:ById只能用在document对象上
▫ 按标签名查找多个子元素:
var elems=parent.getElementsByTagName("标签名")
强调:
✦ ByTagName可用在任意父元素上
✦ ByTagName不止查询直接子节点,且查询所有后代节点。
▫ 按class属性查找:
var elems=parent.getElementsByClassName("class")
▫ 按name属性查找:
var elems=parent.getElementsByName("name");
强调:
✦ 即使返回一个元素,也会放在集合中返回。必须加[0],才能去除唯一一个元素
✦ 返回值elems: 动态集合
☛动态集合:不实际存储对象的完整属性
问题:
每次访问动态集合时,都会反复去DOM树查找。
解决:
遍历,首先将length属性的值,保存在变量中。用变量作为循环的条件
▪ 用选择器查找:Selector API--jQuery的核心
▫ 找1个:
var elem=parent.querySelector("selector");
▫ 找多个:
var elems=parent.querySelectorAll("selector");
强调:
elems非动态集合,不会导致反复遍历DOM树
何时使用:
如果需要多次getxxx才能找到目标元素时
不适合使用:基于现有节点向上或向周围爬树时
getElementxxx VS SelectorAPI
效率:
getXXX的效率 比 SelectorAPI高!
getXXX返回动态集合,不需要准备所有数据就可返回结果。——快
selectorAPI,准备好所有相关数据,再返回。——慢
返回值:
getXXX -> 动态集合,可能造成反复遍历DOM树
selectorAPI -> 非动态集合,不会导致反复遍历DOM树
如何选择:
如果一次getXXX查找即可找到结果时,首选getXXX
如果需要多次getXXX才能找到目标元素时,首选selectorAPI
♕不需要查找,可直接获得的元素:
document.body -> <body>
document.head -> <head>
document.documentElement -> <html>
○ 修改
修改内容/修改属性/修改样式
▪ 修改内容:
▫ 获取或修改元素开始标签和结束标签之间的html内容:
elem.innerHTML
▫ 获取或修改元素开始标签和结束标签之间的纯文本内容(去掉标签,将特殊符号转为正文):
textContent 专门用于: 去掉内容中的标签,仅保留文字
IE8: innerText
▪ 修改属性:
▫ 获取属性值:
//获得属性节点对象:
var attrNode=
elem.attributes[i/"属性名"];
elem.getAttributeNode("属性名");
attrNode.value //获得属性节点的值
//直接获得属性值
var value=elem.getAttribute("属性名");
▫ 设置属性值:
elem.setAttribute("属性名",属性值)
▫ 移除属性:
elem.removeAttribute("属性名")
▫ 判断是否包含指定属性:
elem.hasAttribute("属性名");
❀ HTML DOM: 对部分核心DOM的简化
❀ 所有html标准的属性,自动成为元素对象的属性。可用.访问
元素对象的属性和普通对象的属性用法完全相同。
❀ 移除: 将属性赋值为""
强调: HTML DOM只能访问标准属性
自定义属性只能用核心DOM访问
❀ 特殊: HTML class -> js className
建议: 修改样式,首选className修改
❀ 自定义属性: HTML5
什么是: 开始标签中,data-开头的属性---data-i data-age
❀ 如何获取自定义属性值:
elem.dataset.i
▪ 修改样式:
▫ 修改内联样式:
获取或设置:
elem.style.css属性名=值
强调:
缺:只能获得内联样式
优:修改一个元素的样式时,又不影响其他元素。
何时使用: 只要修改一个元素的样式时,首选style.css属性名
☛强调(css属性名):
将css中的属性名去-,变驼峰,如:
font-size fontSize
background-color backgroundColor
▫ 修改内部/外部样式表里的样式:
✦ 获取最终应用到当前元素的计算后的样式
var style=getComputedStyle(elem)
style.css属性名
何时使用:
只要获得一个元素完整的样式,就用getComputedStyle
✦ 修改样式表中的样式:强烈不建议:
样式表对象模型:COM
✧ 每个样式表都是一个sheet对象:
var sheet=document.styleSheets[i]
✧ 每个选择器后的{...},就是一个cssRule对象
var cssRule=sheet.cssRules[i]
✧ 访问每个cssRule中的一个样式属性:
○ 添加元素(3步)cssRule.style.css属性
① 创建空元素:
var elem=document.createElement("标签名");
比如:
② 设置关键属性:var a=document.createElement("a");
相当于在HTML页面创建了:<a></a>
比如:
a.href="http://tmooc.cn"
a.innerHTML="go to tmooc";
相当于在HTML中创建了:<a href="http://tmooc.cn">go to tmooc</a>
※ 页面加载过程:
读html,构建DOM Tree
↓
RenderTree→layout→paint
↑
读CSS,构建cssRule
③ 将新元素添加到指定父元素下:
parent.appendChild(child);
将child追加到parent的子元素末尾:
parent.insertBefore(child,oldChild);
将child插入到oldChild之前:
parent.replaceChild(child,oldChild);
用child替换parent下的oldChild:
原则:
尽量减少layout的次数,其实就是减少appendChild的使用次数。
注意:
✦ 如果同时添加父元素和子元素时:
先创建父元素,将子元素添加到父元素
最后将父元素整体添加到页面;
✦ 如果父元素已经在页面上,需要同时添加多个同级子元素时:
文档片段:
内存中,临时存储多个子节点的虚拟父节点。
为什么:
反复向页面添加多个子节点会导致反复layout,减低效率
何时使用:
只要添加多个平级子节点时,都要先将子节点放在文档片段中,再将文档片段整体挂到页面上。
如何使用(3步):
① 创建空文档片段:
var frag=document.createDocumentFragment();
② 将多个子元素添加到文档片段下
frag.appendChild(child);
③ 将片段整体添加到页面上:
parent.appendChild(frag);
✦ 另外:【select 】片段不会成为页面上的元素,添加后,自动释放。
事件:
onchange:当选中项发生改变时
属性:
elect.selectedIndex 选中项下标
select.value:
如果option有value,就返回value
如果option没有value,就返回文本
○ 删除元素
parent.removeChild(child);
child.parentNode.removeChild(child);
• HTML DOM常用对象:
○ HTML DOM常用对象有哪些呢?
Image
Select Option
Table...
Form
✦ Image:指页面上一个img元素
✧ 创建:
var img=new Image();
相当于:document.createElement("img")
✦ Select:指一个select元素
✧ 事件:
onchange
✧ 属性:
select.selectedIndex
select.value
select.options获得select下所有option
select.options.length获取或设置选项的个数,可简写为:select.length
✧ 方法:
将opt追加到select元素下:
select.add(opt)
select.appendChild(opt);
移除select中i位置的opt
select.remove(i)
✦ Option对象:指select下一个option元素
创建:
var opt=new Option(text,value);
相当于:
var opt=document.createElement("option");
opt.innerHTML=text;
opt.value=value;
属性:opt.text
✦ 简写:
创建一个新option,同时添加到select:
sel.add(new Option(text,value));
✦ Table:指代一个table元素
行分组(tHead):
var thead=table.createTHead();
table.deleteTHead():
table.tHead
表主体(tBody):
表页脚(tFoot):var tbody=table.createTBody();
table.tBodis[i];
var tfoot=table.createTFoot():
table.deleteTFoot():
table.tFoot
行:
行分组.rows;
var tr=行分组.insertRow(i);
如果省略i,表示末尾追加一行
行分组.deleteRow(i);
如果省略i,表示删除第一行
❀ i都是相对于当前行分组内的下标位置
格:
行.cells;
var td=行.insertCell(i);
强调:只能创建td元素
行.deleteCell(i);
table->tr
table.rows;
var tr=table.insertRow(i);
table.deleteRow(i);
i是相对于整个table的下标位置
tr.rowIndex属性:
标识当前tr在整个表中的行下标;如果删除rowIndex标识的行,必须用table
✦ Form:指代页面上一个表单元素
✧ 获取表单:
var form=document.forms[i/id/name];
属性:
form.length 统计表单元素的个数
方法:
form.submit() //手动提交
✧ 获取表单中的元素:
var elem=form.elements[i/id/name];
方法:
elem.focus();
elem.blur();
强调:
elements集合仅包含表单元素
简写:
form.id/name