# 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">&lt;script&gt;alert("Hi")&lt;/script&gt;</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 &amp; JavaScript</li> </ul> ``` 分别获取文本和 HTML: ``` $('#test-ul li[name=book]').text(); // 'Java & JavaScript' $('#test-ul li[name=book]').html(); // 'Java &amp; 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> 全被删除 ```