# jQuery 选择器与 DOM 操作
## jQuery 简介
[jquery.com](http://jquery.com) Write Less, Do More
jQuery 对象:`$()` 等价于 `jQuery()`
## jQuery 选择器
### 按 ID 查找
如果某个 DOM 节点有 `id` 属性,利用 jQuery 查找如下:
// 查找 <div id="abc">:
var div = $('#abc');
如果 `id` 为 abc 的 `<div>` 不存在,返回的 jQuery 对象如下:
[]
总之 jQuery 的选择器不会返回 `undefined` 或者 `null`
jQuery 对象和 DOM 对象之间可以互相转化:
var div = $('#abc'); // jQuery 对象
var divDom = div.get(0); // 假设存在 div,获取第 1 个 DOM 元素
var another = $(divDom); // 重新把 DOM 包装为 jQuery 对象
### 按 tag 查找
按 tag 查找只需要写上 tag 名称就可以了:
var ps = $('p'); // 返回所有 < p > 节点
ps.length; // 数一数页面有多少个 <p> 节点
### 按 class 查找
按 class 查找注意在 class 名称前加一个.:
var a = $('.red'); // 所有节点包含 `class="red"` 都将返回
// 例如:
// <div class="red">...</div>
// <p class="green red">...</p>
通常很多节点有多个 class,我们可以查找同时包含 red 和 green 的节点:
var a = $('.red.green'); // 注意没有空格!
// 符合条件的节点:
// <div class="red green">...</div>
// <div class="blue green red">...</div>
### 按属性查找
一个 DOM 节点除了 `id` 和 `class` 外还可以有很多属性,很多时候按属性查找会非常方便,比如在一个表单中按属性来查找:
var email = $('[name=email]'); // 找出 <??? name="email">
var passwordInput = $('[type=password]'); // 找出 <??? type="password">
var a = $('[items="A B"]'); // 找出 <??? items="A B">
当属性的值包含空格等特殊字符时,需要用双引号括起来。
按属性查找还可以使用前缀查找或者后缀查找:
var icons = $('[name^=icon]'); // 找出所有 name 属性值以 icon 开头的 DOM
// 例如: name="icon-1", name="icon-2"
var names = $('[name$=with]'); // 找出所有 name 属性值以 with 结尾的 DOM
// 例如: name="startswith", name="endswith"
这个方法尤其适合通过 class 属性查找,且不受 class 包含多个名称的影响:
var icons = $('[class^="icon-"]'); // 找出所有 class 包含至少一个以 `icon-` 开头的 DOM
// 例如: class="icon-clock", class="abc icon-home"
### 组合查找
组合查找就是把上述简单选择器组合起来使用。如果我们查找 `$('[name=email]')`,很可能把表单外的 `<div name="email">` 也找出来,但我们只希望查找 `<input>`,就可以这么写:
var emailInput = $('input[name=email]'); // 不会找出 < div name="email">
同样的,根据 tag 和 class 来组合查找也很常见:
var tr = $('tr.red'); // 找出 < tr class="red ...">...</tr>
### 多项选择器
多项选择器就是把多个选择器用, 组合起来一块选:
$('p,div'); // 把 < p > 和 < div > 都选出来
$('p.red,p.green'); // 把 < p class="red"> 和 < p class="green"> 都选出来
要注意的是,选出来的元素是按照它们在 HTML 中出现的顺序排列的,而且不会有重复元素。例如,`<p class="red green">` 不会被上面的 `$('p.red,p.green')` 选择两次。
### 层级选择器(Descendant Selector)
如果两个 DOM 元素具有层级关系,就可以用 `$('ancestor descendant')` 来选择,层级之间用空格隔开。例如:
<!-- HTML 结构 -->
<div class="testing">
<ul class="lang">
<li class="lang-javascript">JavaScript</li>
<li class="lang-python">Python</li>
<li class="lang-lua">Lua</li>
</ul>
</div>
要选出 JavaScript ,可以用层级选择器:
$('ul.lang li.lang-javascript'); // [<li class="lang- javascript">JavaScript</li>]
$('div.testing li.lang-javascript'); // [<li class="lang- javascript">JavaScript</li>]
因为 `<div>` 和 `<ul>` 都是 `<li>` 的祖先节点,所以上面两种方式都可以选出相应的 `<li>` 节点。
要选择所有的 `<li>` 节点,用:
$('ul.lang li');
这种层级选择器相比单个的选择器好处在于,它缩小了选择范围,因为首先要定位父节点,才能选择相应的子节点,这样避免了页面其他不相关的元素。
例如:
$('form[name=upload] input');
就把选择范围限定在 `name` 属性为 `upload` 的表单里。如果页面有很多表单,其他表单的 `<input>` 不会被选择。
多层选择也是允许的:
$('form.test p input'); // 在 form 表单选择被 < p > 包含的 < input>
### 子选择器(Child Selector)
子选择器 `$('parent>child')` 类似层级选择器,但是限定了层级关系必须是父子关系,就是 `<child>` 节点必须是 `<parent>` 节点的直属子节点。还是以上面的例子:
$('ul.lang>li.lang-javascript'); // 可以选出 [<li class="lang-javascript">JavaScript</li>]
$('div.testing>li.lang-javascript'); // [], 无法选出,因为 < div > 和 < li > 不构成父子关系
### 过滤器(Filter)
过滤器一般不单独使用,它通常附加在选择器上,帮助我们更精确地定位元素。观察过滤器的效果:
$('ul.lang li'); // 选出 JavaScript、Python 和 Lua 3 个节点
$('ul.lang li:first-child'); // 仅选出 JavaScript
$('ul.lang li:last-child'); // 仅选出 Lua
$('ul.lang li:nth-child(2)'); // 选出第 N 个元素,N 从 1 开始
$('ul.lang li:nth-child(even)'); // 选出序号为偶数的元素
$('ul.lang li:nth-child(odd)'); // 选出序号为奇数的元素
### 表单相关
针对表单元素,jQuery 还有一组特殊的选择器:
* `:input`:可以选择 `<input>`,`<textarea>`,`<select>` 和 `<button>`;
* `:file`:可以选择 `<input type="file">`,和 `input[type=file]` 一样;
* `:checkbox`:可以选择复选框,和 `input[type=checkbox]` 一样;
* `:radio`:可以选择单选框,和 `input[type=radio]` 一样;
* `:focus`:可以选择当前输入焦点的元素,例如把光标放到一个 `<input>` 上,用 `$('input:focus')` 就可以选出;
* `:checked`:选择当前勾上的单选框和复选框,用这个选择器可以立刻获得用户选择的项目,如 `$('input[type=radio]:checked')`;
* `:enabled`:可以选择可以正常输入的 `<input>`、`<select>`
等,也就是没有灰掉的输入;
* `:disabled`:和 `:enabled` 正好相反,选择那些不能输入的。
此外,jQuery 还有很多有用的选择器,例如,选出可见的或隐藏的元素:
$('div:visible'); // 所有可见的 div
$('div:hidden'); // 所有隐藏的 div
### 查找
通常情况下选择器可以直接定位到我们想要的元素,但是,当我们拿到一个 jQuery 对象后,还可以以这个对象为基准,进行查找和过滤。
最常见的查找是在某个节点的所有子节点中查找,使用 find() 方法,它本身又接收一个任意的选择器。例如如下的 HTML 结构:
<!-- HTML 结构 -->
<ul class="lang">
<li class="js dy">JavaScript</li>
<li class="dy">Python</li>
<li id="swift">Swift</li>
<li class="dy">Scheme</li>
<li name="haskell">Haskell</li>
</ul>
用 `find()` 查找:
var ul = $('ul.lang'); // 获得 < ul>
var dy = ul.find('.dy'); // 获得 JavaScript, Python, Scheme
var swf = ul.find('#swift'); // 获得 Swift
var hsk = ul.find('[name=haskell]'); // 获得 Haskell
如果要从当前节点开始向上查找,使用 `parent()` 方法:
var swf = $('#swift'); // 获得 Swift
var parent = swf.parent(); // 获得 Swift 的上层节点 < ul>
var a = swf.parent('div.red'); // 从 Swift 的父节点开始向上查找,直到找到某个符合条件的节点并返回
对于位于同一层级的节点,可以通过 next() 和 prev() 方法,例如:
当我们已经拿到 Swift 节点后:
var swift = $('#swift');
swift.next(); // Scheme
swift.next('[name=haskell]'); // Haskell,因为 Haskell 是后续第一个符合选择器条件的节点
swift.prev(); // Python
swift.prev('.js'); // JavaScript,因为 JavaScript 是往前第一个符合选择器条件的节点
### 过滤
和函数式编程的 map、filter 类似,jQuery 对象也有类似的方法。
`filter()` 方法可以过滤掉不符合选择器条件的节点:
var langs = $('ul.lang li'); // 拿到 JavaScript, Python, Swift, Scheme 和 Haskell
var a = langs.filter('.dy'); // 拿到 JavaScript, Python, Scheme
或者传入一个函数,要特别注意函数内部的 `this` 被绑定为 DOM 对象,不是 jQuery 对象:
var langs = $('ul.lang li'); // 拿到 JavaScript, Python, Swift, Scheme 和 Haskell
langs.filter(function () {
return this.innerHTML.indexOf('S') === 0; // 返回 S 开头的节点
}); // 拿到 Swift, Scheme
`map()`方法把一个 jQuery 对象包含的若干 DOM 节点转化为其他对象:
var langs = $('ul.lang li'); // 拿到 JavaScript, Python, Swift, Scheme 和 Haskell
var arr = langs.map(function () {
return this.innerHTML;
}).get(); // 用 get() 拿到包含 string 的 Array:['JavaScript', 'Python', 'Swift', 'Scheme', 'Haskell']
此外,一个 jQuery 对象如果包含了不止一个 DOM 节点,`first()`、`last()` 和 `slice()` 方法可以返回一个新的 jQuery 对象,把不需要的 DOM 节点去掉:
var langs = $('ul.lang li'); // 拿到 JavaScript, Python, Swift, Scheme 和 Haskell
var js = langs.first(); // JavaScript,相当于 $('ul.lang li:first-child')
var haskell = langs.last(); // Haskell, 相当于 $('ul.lang li:last-child')
var sub = langs.slice(2, 4); // Swift, Scheme, 参数和数组的 slice() 方法一致
## 原生 DOM 操作
### document 对象
`document` 对象表示当前页面。由于 HTML 在浏览器中以 DOM 形式表示为树形结构,`document` 对象就是整个 DOM 树的根节点。
要查找 DOM 树的某个节点,需要从 `document` 对象开始查找。最常用的查找是根据 ID 和 Tag Name。
我们先准备 HTML 数据:
<dl id="drink-menu" style="border:solid 1px #ccc;padding:6px;">
<dt>摩卡</dt>
<dd>热摩卡咖啡</dd>
<dt>酸奶</dt>
<dd>北京老酸奶</dd>
<dt>果汁</dt>
<dd>鲜榨苹果汁</dd>
</dl>
用 `document` 对象提供的 `getElementById()` 和 `getElementsByTagName()` 可以按 ID 获得一个 DOM 节点和按 Tag 名称获得一组 DOM 节点:
```
var menu = document.getElementById('drink-menu');
var drinks = document.getElementsByTagName('dt');
var i, s, menu, drinks;
menu = document.getElementById('drink-menu');
menu.tagName; // 'DL'
drinks = document.getElementsByTagName('dt');
s = '提供的饮料有:';
for (i=0; i<drinks.length; i++) {
s = s + drinks[i].innerHTML + ',';
}
alert(s);
```
### 操作 DOM
由于 HTML 文档被浏览器解析后就是一棵 DOM 树,要改变 HTML 的结构,就需要通过 JavaScript 来操作 DOM。
始终记住 DOM 是一个树形结构。操作一个 DOM 节点实际上就是这么几个操作:
* 更新:更新该 DOM 节点的内容,相当于更新了该 DOM 节点表示的 HTML 的内容;
* 遍历:遍历该 DOM 节点下的子节点,以便进行进一步操作;
* 添加:在该 DOM 节点下新增一个子节点,相当于动态增加了一个 HTML 节点;
* 删除:将该节点从 HTML 中删除,相当于删掉了该 DOM 节点的内容以及它包含的所有子节点。
在操作一个 DOM 节点前,我们需要通过各种方式先拿到这个 DOM 节点。最常用的方法是 `document.getElementById()` 和 `document.getElementsByTagName()`,以及 CSS 选择器 `document.getElementsByClassName()`。
由于 ID 在 HTML 文档中是唯一的,所以 `document.getElementById()` 可以直接定位唯一的一个 DOM 节点。`document.getElementsByTagName()` 和 `document.getElementsByClassName()` 总是返回一组 DOM 节点。要精确地选择 DOM,可以先定位父节点,再从父节点开始选择,以缩小范围。
例如:
```
// 返回 ID 为'test'的节点:
var test = document.getElementById('test');
// 先定位 ID 为'test-table'的节点,再返回其内部所有 tr 节点:
var trs = document.getElementById('test-table').getElementsByTagName('tr');
// 先定位 ID 为'test-div'的节点,再返回其内部所有 class 包含 red 的节点:
var reds = document.getElementById('test-div').getElementsByClassName('red');
// 获取节点 test 下的所有直属子节点:
var cs = test.children;
// 获取节点 test 下第一个、最后一个子节点:
var first = test.firstElementChild;
var last = test.lastElementChild;
第二种方法是使用 querySelector() 和 querySelectorAll(),需要了解 selector 语法,然后使用条件来获取节点,更加方便:
// 通过 querySelector 获取 ID 为 q1 的节点:
var q1 = document.querySelector('#q1');
// 通过 querySelectorAll 获取 q1 节点内的符合条件的所有节点:
var ps = q1.querySelectorAll('div.highlighted> p');
```
### 更新 DOM
拿到一个 DOM 节点后,我们可以对它进行更新。
可以直接修改节点的文本,方法有两种:
一种是修改 `innerHTML` 属性,这个方式非常强大,不但可以修改一个 DOM 节点的文本内容,还可以直接通过 HTML 片段修改 DOM 节点内部的子树:
```
// 获取 <p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本为 abc:
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
// 设置 HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p > 的内部结构已修改
```
用 `innerHTML` 时要注意,是否需要写入 HTML。如果写入的字符串是通过网络拿到了,要注意对字符编码来避免 XSS 攻击。
第二种是修改 `innerText` 或 `textContent` 属性,这样可以自动对字符串进行 HTML 编码,保证无法设置任何 HTML 标签:
```
// 获取 <p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML 被自动编码,无法设置一个 <script> 节点:
// <p id="p-id"><script>alert("Hi")</script></p>
```
两者的区别在于读取属性时,`innerText` 不返回隐藏元素的文本,而 `textContent` 返回所有文本。另外注意 IE<9 不支持 `textContent`。
修改 CSS 也是经常需要的操作。DOM 节点的 `style` 属性对应所有的 CSS,可以直接获取或设置。因为 CSS 允许 `font-size` 这样的名称,但它并非 JavaScript 有效的属性名,所以需要在 JavaScript 中改写为驼峰式命名 `fontSize`:
```
// 获取 <p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置 CSS:
p.style.color = '#ff0000';
p.style.fontSize = '20px';
p.style.paddingTop = '2em';
```
### 插入 DOM
当我们获得了某个 DOM 节点,想在这个 DOM 节点内插入新的 DOM,应该如何做?
如果这个 DOM 节点是空的,例如,`<div></div>`,那么,直接使用 `innerHTML = '<span>child</span>'` 就可以修改 DOM 节点的内容,相当于 “插入” 了新的 DOM 节点。
如果这个 DOM 节点不是空的,那就不能这么做,因为 `innerHTML` 会直接替换掉原来的所有子节点。
有两个办法可以插入新的节点。一个是使用 `appendChild`,把一个子节点添加到父节点的最后一个子节点。例如:
```
<!-- HTML 结构 -->
<p id="js">JavaScript</p>
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
```
把 `<p id="js">JavaScript</p>` 添加到 `<div id="list">` 的最后一项:
```
var js = document.getElementById('js'),
list = document.getElementById('list');
list.appendChild(js);
```
现在,HTML 结构变成了这样:
```
<!-- HTML 结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="js">JavaScript</p>
</div>
```
因为我们插入的 js 节点已经存在于当前的文档树,因此这个节点首先会从原先的位置删除,再插入到新的位置。
更多的时候我们会从零创建一个新的节点,然后插入到指定位置:
```
var list = document.getElementById('list'),
haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
```
这样我们就动态添加了一个新的节点:
```
<!-- HTML 结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="haskell">Haskell</p>
</div>
```
动态创建一个节点然后添加到 DOM 树中,可以实现很多功能。举个例子,下面的代码动态创建了一个 `<style>` 节点,然后把它添加到 `<head>` 节点的末尾,这样就动态地给文档添加了新的 CSS 定义:
```
var d = document.createElement('style');
d.setAttribute('type', 'text/css');
d.innerHTML = 'p {color: red}';
document.getElementsByTagName('head')[0].appendChild(d);
```
可以在 Chrome 的控制台执行上述代码,观察页面样式的变化。
#### insertBefore
如果我们要把子节点插入到指定的位置怎么办?可以使用 `parentElement.insertBefore(newElement, referenceElement);`,子节点会插入到 `referenceElement` 之前。
还是以上面的 HTML 为例,假定我们要把 Haskell 插入到 Python 之前:
```
<!-- HTML 结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
```
可以这么写:
```
var list = document.getElementById('list'),
ref = document.getElementById('python'),
haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.insertBefore(haskell, ref);
```
新的 HTML 结构如下:
```
<!-- HTML 结构 -->
<div id="list">
<p id="java">Java</p>
<p id="haskell">Haskell</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
```
可见,使用 `insertBefor` 重点是要拿到一个 “参考子节点” 的引用。很多时候,需要循环一个父节点的所有子节点,可以通过迭代 `children` 属性实现:
```
var i, c,
list = document.getElementById('list');
for (i = 0; i < list.children.length; i++) {
c = list.children[i]; // 拿到第 i 个子节点
}
```
### 删除 DOM
删除一个 DOM 节点就比插入要容易得多。
要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的 `removeChild` 把自己删掉:
```
// 拿到待删除节点:
var self = document.getElementById('to-be-removed');
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true
```
注意删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
当你遍历一个父节点的子节点并进行删除操作时,要注意,`children` 属性是一个只读属性,并且它在子节点变化时会实时更新。
例如,对于如下 HTML 结构:
```
<div id="parent">
<p>First</p>
<p>Second</p>
</div>
```
当我们用如下代码删除子节点时:
```
var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); // <-- 浏览器报错
```
浏览器报错:`parent.children[1]` 不是一个有效的节点。原因就在于,当 `<p>First</p>` 节点被删除后,`parent.children` 的节点数量已经从 2 变为了 1,索引 `[1]` 已经不存在了。
因此,删除多个节点时,要注意 `children` 属性时刻都在变化。
## jQuery DOM 操作
### 修改 Text 和 HTML
jQuery 对象的 `text()` 和 `html()` 方法分别获取节点的文本和原始 HTML 文本,例如,如下的 HTML 结构:
```
<!-- HTML 结构 -->
<ul id="test-ul">
<li class="js">JavaScript</li>
<li name="book">Java & JavaScript</li>
</ul>
```
分别获取文本和 HTML:
```
$('#test-ul li[name=book]').text(); // 'Java & JavaScript'
$('#test-ul li[name=book]').html(); // 'Java & JavaScript'
```
如何设置文本或 HTML?jQuery 的 API 设计非常巧妙,无参数调用 `text()` 是获取文本,传入参数就变成设置文本,HTML 也是类似操作,自己动手试试:
```
var j1 = $('#test-ul li.js');
var j2 = $('#test-ul li[name=book]');
j1.html('<span style="color: red">JavaScript</span>');
j2.text('JavaScript & ECMAScript');
```
一个 jQuery 对象可以包含 0 个或任意个 DOM 对象,它的方法实际上会作用在对应的每个 DOM 节点上。在上面的例子中试试:
$('#test-ul li').text('JS'); // 是不是两个节点都变成了 JS?
所以 jQuery 对象的另一个好处是我们可以执行一个操作,作用在对应的一组 DOM 节点上。即使选择器没有返回任何 DOM 节点,调用 jQuery 对象的方法仍然不会报错:
```
// 如果不存在 id 为 not-exist 的节点:
$('#not-exist').text('Hello'); // 代码不报错,没有节点被设置为'Hello'
```
这意味着 jQuery 帮你免去了许多 `if` 语句。
### 修改 CSS
jQuery 对象有 “批量操作” 的特点,这用于修改 CSS 实在是太方便了。考虑下面的 HTML 结构:
```
<!-- HTML 结构 -->
<ul id="test-css">
<li class="lang dy"><span>JavaScript</span></li>
<li class="lang"><span>Java</span></li>
<li class="lang dy"><span>Python</span></li>
<li class="lang"><span>Swift</span></li>
<li class="lang dy"><span>Scheme</span></li>
</ul>
```
要高亮显示动态语言,调用 jQuery 对象的 `css('name', 'value')` 方法,我们用一行语句实现:
$('#test-css li.dy>span').css('background-color', '#ffd351').css('color', 'red');
注意,jQuery 对象的所有方法都返回一个 jQuery 对象(可能是新的也可能是自身),这样我们可以进行链式调用,非常方便。
jQuery 对象的 `css()` 方法可以这么用:
```
var div = $('#test-div');
div.css('color'); // '#000033', 获取 CSS 属性
div.css('color', '#336699'); // 设置 CSS 属性
div.css('color', ''); // 清除 CSS 属性
```
为了和 JavaScript 保持一致,CSS 属性可以用 `'background-color'` 和 `'backgroundColor'` 两种格式。
`css()` 方法将作用于 DOM 节点的 `style` 属性,具有最高优先级。如果要修改 `class` 属性,可以用 jQuery 提供的下列方法:
```
var div = $('#test-div');
div.hasClass('highlight'); // false, class 是否包含 highlight
div.addClass('highlight'); // 添加 highlight 这个 class
div.removeClass('highlight'); // 删除 highlight 这个 class
```
### 添加 DOM
要添加新的 DOM 节点,除了通过 jQuery 的 `html()` 这种暴力方法外,还可以用 `append()` 方法,例如:
```
<div id="test-div">
<ul>
<li><span>JavaScript</span></li>
<li><span>Python</span></li>
<li><span>Swift</span></li>
</ul>
</div>
```
如何向列表新增一个语言?首先要拿到 `<ul>` 节点:
var ul = $('#test-div>ul');
然后,调用 `append()` 传入 HTML 片段:
ul.append('<li><span>Haskell</span></li>');
除了接受字符串,`append()` 还可以传入原始的 DOM 对象,jQuery 对象和函数对象:
```
// 创建 DOM 对象:
var ps = document.createElement('li');
ps.innerHTML = '<span>Pascal</span>';
// 添加 DOM 对象:
ul.append(ps);
// 添加 jQuery 对象:
ul.append($('#scheme'));
// 添加函数对象:
ul.append(function (index, html) {
return '<li><span>Language -' + index + '</span></li>';
});
```
传入函数时,要求返回一个字符串、DOM 对象或者 jQuery 对象。因为 jQuery 的 `append()` 可能作用于一组 DOM 节点,只有传入函数才能针对每个 DOM 生成不同的子节点。
`append()` 把 DOM 添加到最后,`prepend()` 则把 DOM 添加到最前。
另外注意,如果要添加的 DOM 节点已经存在于 HTML 文档中,它会首先从文档移除,然后再添加,也就是说,用 `append()`,你可以移动一个 DOM 节点。
如果要把新节点插入到指定位置,例如,JavaScript 和 Python 之间,那么,可以先定位到 JavaScript,然后用 `after()` 方法:
```
var js = $('#test-div>ul>li:first-child');
js.after('<li><span>Lua</span></li>');
```
也就是说,同级节点可以用 `after()` 或者 `before()` 方法。
### 删除 DOM 节点
要删除 DOM 节点,拿到 jQuery 对象后直接调用 `remove()` 方法就可以了。如果 jQuery 对象包含若干 DOM 节点,实际上可以一次删除多个 DOM 节点:
```
var li = $('#test-div>ul>li');
li.remove(); // 所有 < li> 全被删除
```