js--DOM
js--DOM
@(js基础部分)
DOM的基础概念
- DOM是文档对象模型(Document Object Model),js的组成部分之一。
- DOM 是HTML文档结构,其实就是为了能让js操作html元素而制定的一个规范,一套API接口。
- DOM的根本就是 document 对象,document 对象有很多属性和方法,例如获取页面上的元素、修改元素的样式、创建新的元素等。
- API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节
体会其中结构
一、节点
- 什么是节点?
- DOM树又称节点数木
- DOM树中的一个对象就称之为一个节点
- 节点有哪几种?
- 根节点:document.documentElement
- 元素节点 属性节点 文本节点
- demo :
<div class="txt" id="attr-id"> 这是文本</div>
元素节点:整个div元素;
属性节点:class/id;
文本节点:[这是文本]。
节点之间的关系
- 关系:父节点、子节点、兄弟节点
demo:
<div class="container">
<span class="txt1">TEXT1</span>
<span class="txt1">TEXT2</span>
</div>
<span></span>
div 是 span 的 父节点
span 是 div 的 子节点
两个span是兄弟节点
二、DOM查询方法(重)
- document.getElementById(id名)(常用)
- document.getElementById('id名');
元素.getElementById('id名');- document指的是在整个文档中查找元素
- 返回的是元素(可以直接进行操作)
-
document.getElementsByClassName(class名)(IE9+) (常用)通过class获取元素
- document.getElementsByClassName('class名');
元素.getElementsByClassName('class名');
1. 返回的是一个元素集合(类似于数组) 含有length和下标
2. 如果只找到一个元素,返回的仍是集合
3. 如果没找到,返回空集合
4. 如果要操作返回额元素,需要使用下标先在集合中找到对应的元素
说明:无论找到多少个元素,返回的都是集合 -
document.getElementByTagName(标签名)(常用)
- 获取相同元素(标签)的节点列表
demo:
- 获取相同元素(标签)的节点列表
var list = document.getElementByTagName('标签名')
访问第一个元素 list[0]
访问第二个元素 list[1]
- document.getElementsByName(name名)(不常用)
- 获取相同名称(name一样)的节点列表
注:不是所有标签都有name属性
某些低版本浏览器会有兼容性问题
var list = document.getElementsByName('元素的name属性值');
访问第一个元素 list[0]
访问第二个元素 list[1]
- document.querySelector(选择器)(IE8+)
- 根据选择器返回匹配到的第一个元素
- document.querySelectorAll(选择器);(IE8+)(常用)
- 根据选择器返回匹配到的所有的元素.
示例一
1、实时搜索
封装获取元素的函数$(重)
属性操作
注:
-
为什么要进行属性操作?
比如页面中往往需要添加很多自定义属性,那么怎么获取他们呢? -
获取元素的属性值
如果是元素自带的属性,我们可以通过 元素.属性名(div.className)获取,如果想获取自定义属性呢?
元素.getAttribute(属性名);
- . DOM对象的getAttribute()方法, 可以获取一个指定属性的属性值
- 参数: 字符串, 属性名称
- 作用: 就是获取指定属性的值
- 返回值: 字符串, 属性值
- 注意点:
- .如果没有指定属性, 返回null. 如果属性的值为空串返回空串
- 在IE6及以下, 如果class属性值为空字符串的话, 也返回null
- 该方法也可以用于去获取自定义属性
-
设置元素的属性值
元素.setAtrribute(属性名,属性值); (IE7+)- setAttribute方法, 可以设置一个指定属性的值参数
-
- 要设置的属性的名称
- 要设置的属性的值
- 返回值:无
- 作用:设置指定属性的值(覆盖),自定义属性也可以覆盖
- 删除元素的某个属性
元素.removeAtrribute(属性名);
- removeAttribute方法, 可以删除一个指定属性
- 参数: 要删除的属性名称
- 返回值: 无
封装attr方法和removeAttr(重)
DOM对象的style属性
-
DOM对象的style属性:
值: 对象, 对象中包括了所有行内样式的名和值
style对象下属性的值为字符串, 如果行内没有该样式, 值为空串 -
颜色: #CCC --> rgb(204, 204, 204)
red --> "red"
rgb --> rgb..
var res = div1.style.background; //rgb(204, 204, 204) -
给style对象某个属性赋值去改变样式的话, 改变的也只是行内样式
-
DOM的style对象属性名称规则:
样式表中的样式名, 如果不含-, 那么在js中style对象的属性名就是样式名
如果含有-, 那么在js中对应的style属性名就是, 样式名将所有的-去掉, 然后将后面紧跟着的字母大写
border : "1px solid black"
border-width : borderWidth
-moz-transition : MozTransition
练习更改li的样式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>test</title>
<style>
#div1 {
width : 100px;
}
</style>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<input type="button" id="btn" value="测试">
<script type="text/javascript">
window.onload = function (){
var btn = document.getElementById('btn');
btn.onclick = function (){
var lis = document.getElementsByTagName('li');
// 遍历, 改样式
for(var i = 0; i < lis.length; i++){
if(i % 2 == 0){
lis[i].style.background = "red";
} else {
lis[i].style.background = "green";
}
}
};
}
</script>
</body>
</html>
结果
DOM的四种offset···属性(重)
- offsetWidth和offsetHeight(重)
- 通过DOM对象的offWidth属性,可以获取到DOM对象的实际宽(视觉宽区域)
含义:元素边框的左边缘到变框右边缘的距离
对于没有盒布局的元素(head,link,style之类), offsetWidth属性为0
- 通过DOM对象的offsetHeight属性,可以获取到DOM对象的实际高(视觉高区域)
含义:元素的上边缘到下边缘的距离
`对于没有盒布局的元素(head,link,style之类),offsetHeight的属性为0
注: offsetWidth盒offsetHeight是只读属性,不能设置。 - offsetWidth和style.width的比较:
值的类型不一样:1、offsetWidth值位数字类型
2、style.width值位字符串
含义不同:1、offsetWidth是边框左右外边缘之间的距离
2、style.width指的是内容宽
且对于不能进行盒布局的元素(内联元素,行内元素),style.width是没有意义的,但是offsetWidth作为实际宽是有值的
- offsetParent(重)
- 通过DOM对象的offsetParent属性,可以获取到该DOM元素的参照物父元素
- 参照物父元素:定位参照物,最近有定位的(position不为static(
注:static(静态定位):默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)
))祖先元素 - 属性值是对象类型,就是参照物父元素的DOM对象
- 注:
- offsetParent属性, 要求元素是具有盒布局元素.
像head, link, meta,style等这些不具有盒布局的元素, offsetParent属性为null
2. 对于表格元素, 向td,th这种定位元素, 无论是否给上position, 都会成为参照物
3. 像table, tr, thead, tbody这些格式元素, 是不能成为参照物的(无论是否有position样式)
4. 在查找参照物父元素的时候, 如果其所有祖先元素都没有定位
其定位参照物为body元素
5. 元素的position为fixed, 那么其offsetParent属性(参照物父元素)为null
在某些版本的firefox下, 这个值可能为body
- offsetParent属性, 要求元素是具有盒布局元素.
- offsetLeft和offsetTop(重)
-
DOM对象的offsetTop属性:
值为数字类型
相对于参照物父元素在y方向的距离
含义: div2的边框的上边缘到参照物父元素border的内边缘的距离
1. 如果元素没有盒布局(如head, style,link等), offsetTop值为0
2. 如果元素的offsetParent属性为null(定位为fixed)
注意: offsetTop属性是只读的, 不能设置 -
DOM对象的offsetLeft属性:
值为数字类型
相对于参照物父元素在x方向的距离
含义: div2的边框的左边缘到参照物父元素border的内边缘的距离
- 1. 如果元素没有盒布局(如head, style,link等), offsetLeft值为0
- 2. 如果元素的offsetParent属性为null(定位为fixed)
注意: offsetLeft属性也是只读的, 不能设置
- 3. offsetleft与style.left的区别
1. 值的类型不一样
style.left 值为字符串类型, 如"100px"
offsetLeft 值为数字类型, 如 100
2. 含义有区别
style.left 指的margin最外边到border最内侧
offsetLeft 指的是border最外边到border最内侧
3. 读写性不一样
offsetLeft 是只读的, 不能设置, 设置只能通过style.left style.margin
style.left 是可读可写的
4. style.left只有在元素有定位的时候, 才有意义
offsetLeft并不需要元素有定位, 任何元素都可以获取其到参照物父元素的x方向的距离
延伸:输入框的焦点事件
- onfocus 事件在对象获得焦点时发生。
inp1.onfocus = function (){ console.log('focus');//此时会在点击输入框的时候打印 };
- onblur事件的函数会在输入框失去焦点的时候触发
inp1.onblur = function (){ console.log('blur');//此时会在当前焦点不在这个输入框的时候运行函数 };
元素的节点属性(重)
- 元素.innerHTML 获取或设置元素节点里的内容
- 这个属性可读可写,赋值的话代表覆盖原来的html
- 这个属性的类型锁定为字符串
- 元素.id元素节点的 id 名称
var res = div1.id;
div1.id = "abcdef";
console.log(res);
结果如图
找到该div,但是不能重复操作
- 元素的.className 获取元素的class内容('内容就是给class起的名字')(不可以使用class)
var res = div1.className;
console.log(res);
此时结果是id=div1的class名
通过赋值操作是可以对此元素的class属性值进行更改
div1.className = "abcde";
- outerHTML/innerText,非 W3C DOM规范
- outerHTML可以获取包括本标签在内的html格式文本
- innerText可以获取到标签其中所含的文本给它赋值代表(覆盖)
- 元素.tagName获取元素节点的标签名
- 注:就是获取这个html标签的名字(div、figure、span...)
- title元素节点的 title属性值(鼠标悬停时的提示)
- title 即是html的title设置(鼠标停留在元素上的时候的提醒)
- 注意:给其进行赋值操作是就是对其进行设置(如果原本标签上没有写title的话则会加上)
- 元素.style获取元素的内联样式
获取非行内样式的属性值的话,必须要使用currentStyle(IE特有)或者 window.getComputedStyle(元素,样式)
节点属性(重)
-
节点有哪几种?
节点可以分为元素节点、属性节点和文本节点
元素节点 :
1. nodeType属性:
是整数值1, 即dom.nodeType === 1
2. nodeName属性:
字符串, 该属性值和tagName属性的值相同, 是一个全大写的标签名
3. nodeValue属性:
元素节点, nodeValue属性一定为null
属性节点:
1. nodeType属性:
是整数值2, 即attr.nodeType === 2
2. nodeName属性:
字符串, 该属性值就是属性名, 如"id"
3. nodeValue属性:
属性节点, nodeValue属性为该节点的属性值
文本节点:
1. nodeType属性:
是整数值3, 即nodeType === 3
2. nodeName属性:
字符串, 该属性值固定为"#text"
3. nodeValue属性:
文本节点, nodeValue属性为该节点具体的文本字符串
文本节点的nodeValue是一个可读可写的属性
2. 3个非常有用的节点属性(nodeName、 nodeType、 nodeValue )
- nodeName: 节点名称()
- <span style="color:red;"> nodeType: 节点类型(判断节点是元素节点还是文本节点或者属性节点)
1 代表元素节点 2 代表属性节点 3 代表文本节点
<span style="color:red;">用途:通常用于判断一个节点是不是元素节点
- nodeValue: 获取节点的文本
<span style="color:red;"> 和innerHTML的区别:nodeValue只能获取和设置文本,innerHTML可以获取和设置元素的内容
<div><span>这是一段文本</span></div>
高级节点属性
-
childNodes 获取当前元素节点的所有元素及文本子节点
--这里面包含空白节点,在IE9之前,IE浏览器会自动忽略空白节点 -
children 获取元素的所有子 元素节点
-
firstChild 获取当前元素节点的第一个子节点
-
firstElementChild 第一个子元素节点
-
lastChild 获取当前元素节点的最后一个子节点
-
lastElementChild 最后一个子元素节点
-
parentNode 获取当前节点的父节点
-
previousSibling 获取当前节点的前一个同级节点
-
nextSibling 获取当前节点的后一个同级节点
-
attributes 获取当前元素节点的所有属性节点集合
封装方法next、prev(常用方法)
DOM的重要操作(方法)
前言:DOM 不单单可以查找节点,也可以创建节点、复制节点、插入节点、删除节点和替换节点
-
document.createElement('标签名')
//创建一个元素节点 只有document才能创建 -
document.createTextNode('文本内容')
//创建一个文本节点 -
box.appendChild(node)
//把node节点插入到box的内部最后的位置 (注:可以放文本以及标签,且是作为子节点在最后追加) -
replaceChild
方法//可以用一个新节点替换原有的子节点
- 1、 新节点
- 2、原有的子节点
- box.insertBefore(node, existNode) //把node节点插入到box中已经存在的节点前面
- 参数:1)要添加的节点
2)原有的子节点 - 注:在IE8及以下,如果原本没有子节点,name会产生参数异常的错误。
解决方法:需要配合appendChild去使用
-
box.removeChild(node) 从元素中移除某个子元素
-
hasChildNodes():判定一个节点是否有子节点
- 返回值:布尔值,true代表有,false即无
- cloneNode():复制空标签 cloneNode(true) 复制整个元素
- 参数(可选):布尔值
- DOM对象的replaceChild方法可以用一个新节点替代原有的子节点
- 参数:1)新节点
2)原有的子节点
- hasAttributes方法可以用于判断一个节点是否存在 指定属性
- 返回值:布尔值,true则有,false则无
- 例如
document.getElementsByTagName("BUTTON")[0].hasAttribute("onclick");
检测button有没有onclick属性
- 注:在js里面就节点的创建这个单一的操作来说,不会对页面产生任何影响
补充字符串的localeCompare方法
- 字符串对象的localeCompare方法,可以按照系统本地语言规则比较字符串大小
- 返回值:
- 负值:说明前面的小,后面的大
- 0:一样大
- 正值:说明前面的大,后面的小
var res = str1.localeCompare(str2);
将括号内的参数(str2)与前面str1进行比较
补充概念:文档碎片
- js操作dom时发生了什么?
每次对dom的操作都会触发"重排",这严重影响到能耗,一般通常采取的做法是尽可能的减少dom操作来减少"重排"
- 什么是文档碎片?
document.createDocumentFragment()
一个容器,用于暂时存放创建的dom元素
- 文档碎片有什么用?
将需要添加的大量元素 先添加到文档碎片 中,再将文档碎片添加到需要插入的位置,大大减少dom操作,提高性能(IE和火狐比较明显)
以上内容相关练习
一、封装一个函数(兼容所有的浏览器)需通过name属性去获取到标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- 创建几个标签以验证 -->
<input type="text" name="abc">
<input type="text" name="abc">
<div name="abc"></div>
<input type="button" id="btn" value="测试">
<script type="text/javascript">
/*思路:1、首先获取到所有的标签
2、创建空数组将所有获取到的标签导入
3、利用数组的遍历进行name属性的比较以达到过滤的效果*/
window.onload = function(){
var btn = document.getElementById('btn');
btn.onclick = function(){
//键入参数以及运行下面选择参数的功能
var res = getByName('abc');
console.log(res);
}
}
//单独写出获取标签以及判断name属性的功能
//此功能参数为name的属性值
function getByName(nameStr){
//获取所有的标签
var allEles = document.getElementsByTagName('*');//“*”号即是所有的意思
var result = [];//用来接收筛选出来的标签
//用for循环对所有的name属性进行过滤
for(var i = 0; i < allEles.length; i++){
var eleName = allEles[i].getAttribute('name');//通过getAttribute('name')拿到allEles下name属性的属性值
if( eleName == nameStr ){
//将拿到的name属性值eleName与键入的name参数(nameStr)进行比较最后放入空数组
result.push(allEles[i]);
}
}
//返回接收标签的数组
return result;
}
</script>
</body>
</html>
二、封装一个函数(兼容所有的浏览器)需通过className属性去获取到标签
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" class="abc bcd cad">
<input type="text" class="abc">
<div class="abc"></div>
<input type="button" id="btn" value="测试">
<script type="text/javascript">
//用来调用下面的功能
window.onload = function() {
var btn = document.getElementById('btn');
btn.onclick = function() {
var res = getByClassName('abc');
console.log(res);
}
}
/*总体思路:1、获取所有的标签
2、创建一个数组用于接收筛选出来的标签
3、根据class属性过滤出需要的标签*/
//选取标签功能
function getByClassName(classStr) {
//拿到所有的标签
var allEles = document.getElementsByTagName("*");
var result = []; //用于接收得出的标签
//根据class属性过滤
for(var i = 0; i < allEles.length; i++){
var className = allEles[i].getAttribute('class');
if( !className ){
className = '';
}else{
result.push(allEles[i]);
}
}
return result;
}
</script>
</body>
</html>
三,点击td元素切换图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<style type="text/css">
html,
body,
table,
div,
img {
margin: 0;
padding: 0;
}
td {
width: 100px;
height: 100px;
border: 1px solid #e8e8e8;
}
td.special {
background: blue;
}
img {
width: 900px;
height: 500px;
}
</style>
<body>
<table>
<td class="special"></td>
<td></td>
<td></td>
</table>
<div class="box"><img src="image/1.JPG" alt="" id="is"></div>
<script>
/*总体思路:1、获取td的总标签,当做循环条件。*/
function mvoeImg() {
//拿到所有的TD
var tds = document.getElementsByTagName('td');
for (var i = 0; i < tds.length; i++) {
//恢复其他td的背景
tds[i].onclick = function() {
//改掉颜色
//方法一
//给一个TD设置class,拿到这个td标签
/*var blueTd = document.getElementsByClassName('special')[0];
//拿到之后将这个TD的class属性变成空。
blueTd.className = '';
blueTd.removeAttribute('class');
this.className = 'special';*/
//方法二
for(var j = 0; j < tds.length; j++){
tds[j].className = '';
}
this.className = 'special';
//确认当前的对象(td),以确认图片的位置
var index = 0;//定义一个变量存放当前td的索引
for(var i =0 ; i < tds.length; i++){
if( tds[i] == this ){
index = i;
break;
}
}
var myImg = document.getElementById('is');
myImg.src = "image/" + (index + 1) + ".jpg";
}
}
}
mvoeImg();
</script>
</body>
</html>
四、动态表格的增删带排序功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
table {
border: 1px solid #000;
min-width: 60px;
}
table th {
border: 1px solid #000;
min-width: 60px;
}
table td {
border: 1px solid #000;
min-width: 60px;
}
</style>
</head>
<body>
姓名:
<input type="text" id="namer"> 学号:
<input type="text" id="stuNum"> 性别:
<input type="text" id="sex">
<input type="button" id="btn" value="添加">
<table id="tabs">
<tr>
<th>姓名
<input type="button" value="排序" id="rank">
</th>
<th>学号
<input type="button" value="排序" id="rank2">
</th>
<th>性别</th>
<th>操作</th>
</tr>
</table>
<script type="text/javascript">
window.onload = function() {
/*思路:在点击按钮的时候进行增加一行四列表格
*/
var btn = document.getElementById('btn');
//先获得三个输入框及表格
var namer = document.getElementById('namer');
var stuNum = document.getElementById('stuNum')
var sex = document.getElementById('sex');
var tabs = document.getElementById('tabs');
btn.onclick = function() {
//生成一个一行四列的表格
//第一步,先创建tr跟td
var tr = document.createElement('tr');
tabs.appendChild(tr);
for (var i = 0; i < 4; i++) {
var td = document.createElement('td');
tr.appendChild(td);
//将输入框的值放到表格中去
if (i == 0) {
tr.children[i].innerHTML = namer.value;
} else if (i == 1) {
tr.children[i].innerHTML = stuNum.value;
} else if (i == 2) {
tr.children[i].innerHTML = sex.value;
} else if (i == 3) {
tr.children[i].innerHTML += '<a href="javascript:;">删除<a>';
}
}
tr.children[3].children[0].onclick = function() {
this.parentNode.parentNode.remove(this.parentNode);
}
//获取当时所有tr的标签
var trs = document.getElementsByTagName('tr');
var arr = []; //定义一个空数组1来接收tr.children[0]里面的字符串内容
for (var j = 1; j < trs.length; j++) {
//注:此时作为循环条件的应该是所有tr集合的length值
arr.push(tabs.children[j].children[0].innerHTML);
}
var arr2 = [];//定义一个字符串2来保存第二列的数字内容
for (var c = 1; c < trs.length; c++) {
//注:此时作为循环条件的应该是所有tr集合的length值
arr2.push(parseInt(tabs.children[c].children[1].innerHTML));
}
//第一个排序姓名字符串的按钮
var rank = document.getElementById('rank');
rank.onclick = function() {
//用冒泡算法进行排列
for (var k = 0; k < arr.length; k++) {
for (var h = k + 1; h < arr.length; h++) {
if (arr[k] > arr[h]) {
var temp = arr[k];
arr[k] = arr[h];
arr[h] = temp;
}
}
}
//将数组中排好顺序的值添加给相应位置的td
for (var z = 0; z < arr.length; z++) {
tabs.children[z + 1].children[0].innerHTML = arr[z];//z+1是因为tbs里面的第一个下标length为th的父tr
}
}
//第二个排序数字的按钮
var rank2 = document.getElementById('rank2');
rank2.onclick = function() {
for (var k = 0; k < arr2.length; k++) {
for (var h = k + 1; h < arr.length; h++) {
if (arr2[k] > arr2[h]) {
var temp = arr2[k];
arr2[k] = arr2[h];
arr2[h] = temp;
}
}
}
for (var z = 0; z < arr2.length; z++) {
tabs.children[z + 1].children[1].innerHTML = arr2[z];
}
}
}
}
</script>
</body>
</html>