从JS和jQuery浅谈DOM操作,当我们在获取时,究竟获取了什么

时间:2022-08-26 13:08:05

0、写在前面的话

自己对前端的东西一直不是很熟,现在开始要想办法从前端各个地方去获取想要的属性值的时候,也基本是在网上现炒现卖,几周下来,发现自己还是迷迷糊糊,可以算是一无所获。

所以就抽时间,把这一块的东西收集整理一下,免得每次为了得到一个值要上网查询鼓捣一万年,实在是浪费时间,知其然知其所以然,才能让问题迎刃而解。

这篇博文应该说结构还不够完整,有些知识点还没提到,覆盖的内容其实主要还是为了满足我现在入门知识理解的一个需求,日后再进行完善吧,这里先贴一些相关概念的参考链接,以后方便参考和添加:

1、理解节点

HTML文档中,所有内容都是 “节点”,是一个Element,这意味着:
  • 整个文档是一个文档节点
  • 每个 HTML 元素是元素节点
  • HTML 元素内的文本是文本节点
  • 每个 HTML 属性是属性节点
  • 注释是注释节点

先看下面的片段:
<html>
<head>
<title>DOM 教程</title>
</head>
<body>
<h1>DOM 第一课</h1>
<p>Hello world!</p>
</body>
</html>
9
 
1
<html> 
2
  <head>
3
    <title>DOM 教程</title>
4
  </head>
5
  <body>
6
    <h1>DOM 第一课</h1>
7
    <p>Hello world!</p>
8
  </body>
9
</html>
从上面的 HTML 中:
  • <html> 节点没有父节点;它是根节点
  • <head> 和 <body> 的父节点是 <html> 节点
  • 文本节点 "Hello world!" 的父节点是 <p> 节点
并且:
  • <html> 节点拥有两个子节点:<head> 和 <body>
  • <head> 节点拥有一个子节点:<title> 节点
  • <title> 节点也拥有一个子节点:文本节点 "DOM 教程"
  • <h1> 和 <p> 节点是同胞节点,同时也是 <body> 的子节点
并且:
  • <head> 元素是 <html> 元素的首个子节点
  • <body> 元素是 <html> 元素的最后一个子节点
  • <h1> 元素是 <body> 元素的首个子节点
  • <p> 元素是 <body> 元素的最后一个子节点

重点:

2、JS获取节点

我们知道,HTML文档载入浏览器后,会成为Document对象,这个对象让我们可以从脚本中对HTML页面所有元素进行访问,我们经常获取元素使用的几大方法:getElementById()、 getElementsByClassName、getElementsByName()、getElementsByTagName()就归属其下,也是我们最常使用到的方法。

  • getElementById() 根据id属性
  • getElementsByName() 根据name属性
  • getElementsByClassName 根据class的名称
  • getElementsByTagName() 根据标签

2.1 获取单一节点

我们用document.getElementById(id)这个方法举例,因为是根据HTML中唯一的id来获取,所以得到的是单一节点,这个节点实际就是一个对象,也就是说,这个方法返回的是一个HTML对象。

每个标签的出现,都意味着有一个对应的对象被创建,比如 <select> 标签的存在,意味着有一个 Select对象 诞生;<option> 标签,意味着有一个 Option对象 诞生。

我们说过,每个节点,都是一个对象,是对象,就有属性,所以我们想要获取对应的值,你只要找到了这个对象,完全可以到w3school上查看下这个对象有哪些属性,直接调用就可以了。

实际上,很多属性是大部分对象都有的,也是我们所常用的:
  • id 该节点的id值
  • value 该节点的value值
  • text 节点的文本值
  • name 节点的name,名称

诸如此类,还有很多,具体的可以直接查询手册。

来看看示例,假如有下面的HTML片段,现在想获取关于 “张三” 的各类信息:
<table class="manage-table space" id="dataTable">
<tr class="center">
<th rowspan="2">学号</th>
<th rowspan="2">姓名</th>
<th rowspan="2">性别</th>
<th colspan="3">班级</th>
<th colspan="2">选课情况</th>
</tr>
<tr class="center">
<th>类别</th>
<th>学届</th>
<th>班号</th>
<th>选课数</th>
</tr>
<tr class="center" idx="89">
<td id="studentId" hidden="true">89</td>
<td>0001</td>
<td>张三</td>
<td><a>男</a></td>
<td id="classId" hidden="true">38</td>
<td>理科</td>
<td>1999</td>
<td>3</td>
<td>3</td>
</tr>
</table>
26
 
1
<table class="manage-table space" id="dataTable">
2
    <tr class="center">
3
        <th rowspan="2">学号</th>
4
        <th rowspan="2">姓名</th>
5
        <th rowspan="2">性别</th>
6
        <th colspan="3">班级</th>
7
        <th colspan="2">选课情况</th>
8
    </tr>
9
    <tr class="center">
10
        <th>类别</th>
11
        <th>学届</th>
12
        <th>班号</th>
13
        <th>选课数</th>
14
    </tr>
15
    <tr class="center" idx="89">
16
        <td id="studentId" hidden="true">89</td>
17
        <td>0001</td>
18
        <td>张三</td>
19
        <td><a>男</a></td>
20
        <td id="classId" hidden="true">38</td>
21
        <td>理科</td>
22
        <td>1999</td>
23
        <td>3</td>
24
        <td>3</td>
25
    </tr>
26
</table>

先通过之前提到的,可以通过查看网上的文档和浏览器的调试器来找元素的”位置“,最终通过遍历定位到该行 tr :
var dataTable = document.getElementById("dataTable");
var zhangsan;
for(var x in dataTable.rows) {
for(var y in dataTable.rows[x].attributes) {
if(dataTable.rows[x].attributes[y].name === "idx"
&& dataTable.rows[x].attributes[y].value === "89") {
zhangsan = dataTable.rows[x];
}
}
}
10
 
1
var dataTable = document.getElementById("dataTable");
2
var zhangsan;
3
for(var x in dataTable.rows) {
4
    for(var y in dataTable.rows[x].attributes) {
5
        if(dataTable.rows[x].attributes[y].name === "idx"
6
                && dataTable.rows[x].attributes[y].value === "89") {
7
            zhangsan = dataTable.rows[x];
8
        }
9
    }
10
}

写到这里,需要注意一点,那就是 for in 这个循环遍历,这个方法是将对象的所有属性遍历,我们知道,数组也是一个对象,索引视为其属性,所以假如数组还有额外的属性,遍历会将该属性输出。

所以,上面的写法实际上存在很大的问题,因为Array表面上看来只有索引,实际上因为原型继承的关系,它还有很多从父类继承下来的属性,在这里也会同时遍历出来,如索引遍历完后紧接着遍历了其原型对象的属性 item,这个属性就没有attributes属性的,但是这里之所以没有报错,是因为JS的灵(缺)活(陷),直接表示出undefined,所以也在我们的if条件判断中溜了过去。

正确的写法怎么写?就老老实实用for循环,后面的例子会再次提到,你只要知道这样写是存在很大风险的,不要这样做,然后继续往下看就好。

另,ES6中引入的iterable类型对象可以使用 for of 方法规避这个问题,而且直接遍历出元素,而不是索引这么麻烦。

回到正题,现在我们得到了这一排,也就是这个 tr,那么什么信息都可以得到了,比如每个单元格的文本内容:
for(var z in zhangsan.cells) {
console.log(zhangsan.cells[z].innerText);
}
3
 
1
for(var z in zhangsan.cells) {
2
    console.log(zhangsan.cells[z].innerText);
3
}

注意 innerHTML 和 innerText 的区别,比如对应zhangsan性别的那栏单元格:
innerHTML  --> "<a>男</a>"
innerText --> "男"

2.2 获取多个节点

获取多个节点的方法如 getElementsByClassName、getElementsByName()、getElementsByTagName() 等,其实也很简单,无非是获取到了HTML对象的集合,再根据情况遍历使用就可以了。

比如:
var trs = document.getElementsByTagName("tr");
console.log(trs);
从JS和jQuery浅谈DOM操作,当我们在获取时,究竟获取了什么
 

2.3 DOM方式的获取

上面我们提到的获取元素属性等等的方式,实际上很粗暴,就是使用对象直接获取其属性,实际上,还可以使用DOM方法来获取,而且是有一定区别的。

假如我们获取到一个HTML对象,叫做htmlObj,现在我们要获取它的id值:
htmlObj.id;  //对象方式,直接获取属性

htmlObj.getAttribute("id");  //DOM方法
3
 
1
htmlObj.id;  //对象方式,直接获取属性
2

3
htmlObj.getAttribute("id");  //DOM方法

如果你在浏览器调试的时候,没有发现获取的HTML对象有类似getAttribute()这种方法,别着急,如果你知道原型的概念,你可以顺着它的 __proto__ 属性延伸一直摸索,看到一个 ElementPrototype 的时候,这些方法就在里面。现在不理解没关系,你只要知道这些方法就是HTML DOM对象从上面继承下来的,并不是你没看见就没有。

用实际点的例子来说明,还是接刚才zhangsan的HTML作为例子,这次不磨叽,先拿到zhangsan看下属性:
var dataTable = document.getElementById("dataTable");
console.log(dataTable); var zhangsan = dataTable.rows[2];
console.log(zhangsan);
5
 
1
var dataTable = document.getElementById("dataTable");
2
console.log(dataTable);
3

4
var zhangsan = dataTable.rows[2];
5
console.log(zhangsan);

通过控制台的输出,我们可以看到,对于一些常见的属性,比如id、class等,我们可以确实可以使用 zhangsan.id 或者 zhangsan.className 来获取得到。 可是我们的zhangsan还额外自定义了一个属性idx,那么问题就来了。

问题就出在,这个idx属性并没有直接放在zhangsan这个对象下,而是作为attributes集合中的元素,所以之前我们没有办法直接使用如 zhangsan.idx 的方法获取值,而是很麻烦地再次通过遍历和条件判断来进行定位。

而实际上,DOM对象有一个 getAttribute() 方法,可以通过属性名来获取属性的值,所以之前我们定义zhangsan的方法,实际上可以改成这样:
var dataTable = document.getElementById("dataTable");
console.log(dataTable); var zhangsan; for(var x in dataTable.rows) {
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
}
} console.log(zhangsan);
13
 
1
var dataTable = document.getElementById("dataTable");
2
console.log(dataTable);
3

4
var zhangsan;
5

6
for(var x in dataTable.rows) {
7
    var person = dataTable.rows[x];
8
    if(person.getAttribute("idx") === "89") {
9
        zhangsan = person;
10
    }
11
}
12

13
console.log(zhangsan);

很不幸,会报出 person.getAttribute() is not a function 的错误,why?之前提到过,for in 会遍历其所有属性,在遍历完索引以后,它继续遍历那些从父类继承下来的属性,某些属性并不是DOM对象,是没有getAttribute方法的,循环到这里的时候,自然就报错了。

所以我们还是老老实实使用for循环:
for(var x = 0; x < dataTable.rows.length; x++ ){
if(dataTable.rows[x].getAttribute("idx") === "89") {
zhangsan = dataTable.rows[x];
} }
x
 
1
for(var x = 0; x < dataTable.rows.length; x++ ){
2
    if(dataTable.rows[x].getAttribute("idx") === "89") {
3
        zhangsan = dataTable.rows[x];
4
    }
5

6
}

或者把之前的方法改一下,找到了以后就让循环break,不再遍历后面的元素:
for(var x in dataTable.rows) {
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
break;
}
}
7
 
1
for(var x in dataTable.rows) {
2
    var person = dataTable.rows[x];
3
    if(person.getAttribute("idx") === "89") {
4
        zhangsan = person;
5
        break;
6
    }
7
}

或者把继承的属性筛掉不要:
for(var x in dataTable.rows) {
if(dataTable.rows.hasOwnProperty(x)){
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
}
}
}
8
 
1
for(var x in dataTable.rows) {
2
    if(dataTable.rows.hasOwnProperty(x)){        
3
        var person = dataTable.rows[x];
4
        if(person.getAttribute("idx") === "89") {
5
            zhangsan = person;
6
        }
7
    }
8
}

这下,就正确了,代码也简单了好多,就是利用DOM方法,所以在特别是使用一些自定义标签的时候,使用DOM的方法可以更加便捷。


3、jQuery获取

3.1 认识jQuery的基本概念

我们都知道jQuery是一个JS函数库,我们也知道jQuery可以更少的代码做更多的事,我们还知道用jQuery获取节点都是通过 $(selector) 的方式。可是,这里的$号什么意思呢?

JS世界中,变量命名的规范里,$是属于合法的标识符的,jQuery的函数有两个名字,一个叫 jQuery,另一个就叫 $。所以实际上 $.ajax(options) 和 jQuery.ajax(options) 是等同的,你可以用浏览器的调试器,到控制台中去输入 $===jQuery,结果会得到 true。

我们都知道JS中函数也是一个对象,所以这里的 $ 表示函数本身,如果是 $(),那么根据函数中return,你就会得到一个对象,我们常说是一个jQuery对象。

现在你不需要去深究太多,你只用知道常见的jQuery语法最终就是得到一个jQuery对象,这个对象看似和你通过document.getElementById之类的方法得到的东西一样,实际上并不是,内容相似但完全是两种不同的对象。所以,jQuery对象没办法使用HTML DOM对象中的方法,比如 getAttribute ,同理HTML DOM对象也无法使用jQuery对象的方法。

不过不用担心,jQuery中封装了大量的方法,可以替代HTML对象中的很多操作。比如 $("#foo").html(); 等同于 document.getElementById("foo").innerHTML;

3.2 jQuery对象和DOM对象的相互转换

上面已经提到了,两者是不同的对象,方法也不能共通,但是他们两者之间是可以进行相互转换的。

jQuery对象 --> DOM对象
var $cr=$("#cr"); //jquery对象
var cr = $cr[0]; //dom对象 jQueryObj[0]也可写成 jQueryObj.get(0);
alert(cr.checked); //检测这个checkbox是否给选中
3
 
1
var $cr=$("#cr"); //jquery对象
2
var cr = $cr[0]; //dom对象 jQueryObj[0]也可写成 jQueryObj.get(0);
3
alert(cr.checked); //检测这个checkbox是否给选中

DOM对象 --> jQuery对象
//只需要用$()把dom对象包装起来
var cr=document.getElementById("cr"); //dom对象
var $cr = $(cr); //转换成jquery对象
3
 
1
//只需要用$()把dom对象包装起来
2
var cr=document.getElementById("cr"); //dom对象
3
var $cr = $(cr); //转换成jquery对象

另外,从规范命名来讲,如果获取的对象是 jQuery对象,那么在变量前面加上$,这样方便容易识别出哪些是jQuery对象。

2018.03.22补充如下
在项目中遇到了这样的问题,有这样一段代码:
function loadLimit(trainingId, departmentId) {
var trs = $("#dataTable tr");
if (trs.length > 1) {
for (var i = 1; i < trs.length; i++) {
trs[i].remove();
}
}
$().invoke("/admin/elite/join/do/loadJoin.q", {trainingId:trainingId, departmentId:departmentId}, function(html) {
$("#dataTable").append($(html).find("tr"));
});
}
11
 
1
function loadLimit(trainingId, departmentId) {
2
    var trs = $("#dataTable tr");
3
    if (trs.length > 1) {
4
        for (var i = 1; i < trs.length; i++) {
5
            trs[i].remove();
6
        }
7
    }
8
    $().invoke("/admin/elite/join/do/loadJoin.q", {trainingId:trainingId, departmentId:departmentId}, function(html) {
9
        $("#dataTable").append($(html).find("tr"));
10
    });
11
}

这段代码在Chrome中运行正常,后来在IE中出错,这才发现了问题。当时误以为获取的多标签集合jQuery对象,其子元素也是jQuery对象,所以自然而然使用了remove(),实际上trs[i]获得的已经是DOM对象,不支持jQuery方法,故报错。我试着打印了结果,如下图中,上为DOM对象,下为jQuery对象:
从JS和jQuery浅谈DOM操作,当我们在获取时,究竟获取了什么
可以看到,jQuery对象中index为0的子元素,包含典型的innerHTML等属性,这显然是DOM对象的东西。也印证了之前写过的笔记jQueyr对象转DOM对象只需要类似var cr = $cr[0];即可。所以我自己的错误应该这样修改:
$(trs[i]).remove();
1
 
1
$(trs[i]).remove();

亦或者有这样的方法eq(),表示将匹配元素集缩减值制定index上的一个:
trs.eq(i).remove();
1
 
1
trs.eq(i).remove();

3.3 jQuery的选择器和方法

jQuery的选择方式和CSS的选择器方式类似,完整版你可以参考这里:(1)jQuery的选择器 (2)jQuery 参考手册 - 选择器
至于jQuery的方法,还是直接丢链接比较方便:(1)jQuery API 中文文档 (2)w3school的jQuery教程

3.4 jQuery选择示例

还是zhangsan的例子,我们再贴一次代码,免得拉上去再看:
<table class="manage-table space" id="dataTable">
<tr class="center">
<th rowspan="2">学号</th>
<th rowspan="2">姓名</th>
<th rowspan="2">性别</th>
<th colspan="3">班级</th>
<th colspan="2">选课情况</th>
</tr>
<tr class="center">
<th>类别</th>
<th>学届</th>
<th>班号</th>
<th>选课数</th>
</tr>
<tr class="center" idx="89">
<td id="studentId" hidden="true">89</td>
<td>0001</td>
<td>张三</td>
<td><a>男</a></td>
<td id="classId" hidden="true">38</td>
<td>理科</td>
<td>1999</td>
<td>3</td>
<td>3</td>
</tr>
</table>
26
 
1
<table class="manage-table space" id="dataTable">
2
    <tr class="center">
3
        <th rowspan="2">学号</th>
4
        <th rowspan="2">姓名</th>
5
        <th rowspan="2">性别</th>
6
        <th colspan="3">班级</th>
7
        <th colspan="2">选课情况</th>
8
    </tr>
9
    <tr class="center">
10
        <th>类别</th>
11
        <th>学届</th>
12
        <th>班号</th>
13
        <th>选课数</th>
14
    </tr>
15
    <tr class="center" idx="89">
16
        <td id="studentId" hidden="true">89</td>
17
        <td>0001</td>
18
        <td>张三</td>
19
        <td><a>男</a></td>
20
        <td id="classId" hidden="true">38</td>
21
        <td>理科</td>
22
        <td>1999</td>
23
        <td>3</td>
24
        <td>3</td>
25
    </tr>
26
</table>

我们要获得zhangsan,用jQuery的方式就是:
var zhangsan = $("[idx='89']");  //表示通过属性查找,属性idx为89的
 
1
var zhangsan = $("[idx='89']");  //表示通过属性查找,属性idx为89的

没错,就是这么简单... 

然后你要么使用jQuery的一些方法来获取里面的内容,或者粗暴地将它转换为DOM对象再操作。

从JS和jQuery浅谈DOM操作,当我们在获取时,究竟获取了什么的更多相关文章

  1. Js之浅谈dom操作

    JavaScript之浅谈dom操作 1.理解dom: DOM(Document Object Model ,文档对象模型)一种独立于语言,用于操作xml,html文档的应用编程接口. 怎么说,我从两 ...

  2. 将原生JS和jquery里面的DOM操作进行了一下整理

    创建元素节点 1.原生: document.createElement("div") 2.jquery: $("<div></div>" ...

  3. JavaScript--浅谈DOM操作

    JavaScript之浅谈DOM操作 1.理解DOM: DOM(Document Object Model ,文档对象模型)一种独立于语言,用于操作xml,html文档的应用编程接口. 怎么说,我从两 ...

  4. 前端性能优化--为什么DOM操作慢? 浅谈DOM的操作以及性能优化问题-重绘重排 为什么要减少DOM操作 为什么要减少操作DOM

    前端性能优化--为什么DOM操作慢?   作为一个前端,不能不考虑性能问题.对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩( ...

  5. 浅谈DOM性能考虑

    浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记    访问DOM的方式对脚本性 ...

  6. JQuery中的DOM操作

    JQuery中有很多DOM操作,但是因为之前没有总结过,所以用来用去都是那几个,一写html中的表单交互,尤其是那些复杂的表单交互,就是一大坨的js,我自己看着都费劲. 所以我感觉有必要总结一下 &l ...

  7. dom core&comma;html dom&comma;css dom&comma;jquery 中的dom操作

    前端开发中为达到某种目的,往往有很多方法:dom core,html dom,jquery; dom core/jquery主要通过函数调用的方式(getAttribute("属性名&quo ...

  8. jQuery中的DOM操作总结

    jQuery中的DOM操作 DOM是Document Object Medel的缩写,它的意思是文档对象模型,根据W3C的官方说法,DOM是一种跟浏览器,平台以及语言都没有关系的一种规范,也就是一种接 ...

  9. jQuery中的DOM操作《思维导图》

    首先,是关于jQuery中的DOM操作的<思维导图>,请点击这里:jQuery中的DOM操作 列表框的左右选项移动 <html> <head> <title& ...

随机推荐

  1. css1-css3的那些模糊点

    css很重要, 但也不是万能的, 也不能抛弃dom 元素和 元素的属性!! 很多时候, dom "元素" 的 "属性" 也很重要 也很实用! 要结合属性来写 包 ...

  2. FragmentPagerAdapter与FragmentStatePagerAdapter区别

    在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...

  3. HTML之一 符号实体

    符号实体和”语言代码“以及”字符集“无关.

  4. Ambari:Provide ability to apply single patches on top of RU release

    https://issues.apache.org/jira/browse/AMBARI-12556 Provide ability to apply single patches on top of ...

  5. 兹瓷查rank和kth的STL平衡树

    兹瓷查rank和kth的STL平衡树 明天就是一轮省选了啊..这可能是退役前的最后一篇博文了吧(如果心情不好怕是连游记都会咕) 众周所知stl中有一个依靠红黑树实现的nb数据结构-std::set 但 ...

  6. 用word发CSDN blog,免去插图片的烦恼

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  7. grid - 隐式网格

    当网格项目确认在显式网格之外时就会创建隐性网格,当没有足够的空间或者显式的网格轨道来设置网格项目,此时网格项目就会自动创建隐式网格. 隐式网格可以定义:grid-auto-rows.grid-auto ...

  8. &lbrack;CTSC2018&rsqb; 假面 &vert; 期望 DP

    题目链接 LOJ 2552 Luogu P4564 考场上这道题我先是写了个70分暴力,然后发现似乎可以NTT,然鹅问题是--我没学过NTT,遂脑补之,脑补出来了,下午出成绩一看,卡成暴力分(70)- ...

  9. 物联网架构成长之路&lpar;3&rpar;-EMQ消息服务器了解

    1. 了解 物联网最基础的就是通信了.通信协议,物联网协议好像有那么几个,以前各个协议都有优劣,最近一段时间,好像各大厂商都采用MQTT协议,所以我也不例外,不搞特殊,采用MQTT协议,选定了协议,接 ...

  10. (网络流)ACM Computer Factory --POJ --3436

    链接: http://poj.org/problem?id=3436 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#probl ...