# 選擇器
選擇器是jQuery的核心。一個選擇器寫出來類似`$('#dom-id')`。
為什么jQuery要發明選擇器?回顧一下DOM操作中我們經常使用的代碼:
```
// 按ID查找:
var a = document.getElementById('dom-id');
// 按tag查找:
var divs = document.getElementsByTagNames('div');
// 查找<p class="red">:
var ps = document.getElementsByTagNames('p');
// 過濾出class="red":
// TODO:
// 查找<table class="green">里面的所有<tr>:
var table = ...
for (var i=0; i<table.children; i++) {
// TODO: 過濾出<tr>
}
```
這些代碼實在太繁瑣了,并且,在層級關系中,例如,查找`<table class="green">`里面的所有`<tr>`,一層循環實際上是錯的,因為`<table>`的標準寫法是:
```
<table>
<tbody>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
```
很多時候,需要遞歸查找所有子節點。
jQuery的選擇器就是幫助我們快速定位到一個或多個DOM節點。
## 按ID查找
如果某個DOM節點有`id`屬性,利用jQuery查找如下:
```
// 查找<div id="abc">:
var div = $('#abc');
```
_注意_,`#abc`以`#`開頭。返回的對象是jQuery對象。
什么是jQuery對象?jQuery對象類似數組,它的每個元素都是一個引用了DOM節點的對象。
以上面的查找為例,如果`id`為`abc`的`<div>`存在,返回的jQuery對象如下:
```
[<div id="abc">...</div>]
```
如果`id`為`abc`的`<div>`不存在,返回的jQuery對象如下:
```
[]
```
總之jQuery的選擇器不會返回`undefined`或者`null`,這樣的好處是你不必在下一行判斷`if (div === undefined)`。
jQuery對象和DOM對象之間可以互相轉化:
```
var div = $('#abc'); // jQuery對象
var divDom = div.get(0); // 假設存在div,獲取第1個DOM元素
var another = $(divDom); // 重新把DOM包裝為jQuery對象
```
通常情況下你不需要獲取DOM對象,直接使用jQuery對象更加方便。如果你拿到了一個DOM對象,那可以簡單地調用`$(aDomObject)`把它變成jQuery對象,這樣就可以方便地使用jQuery的API了。
## 按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')`選擇兩次。
## 練習
使用jQuery選擇器分別選出指定元素:
* 僅選擇JavaScript
* 僅選擇Erlang
* 選擇JavaScript和Erlang
* 選擇所有編程語言
* 選擇名字input
* 選擇郵件和名字input
```
<!-- HTML結構 -->
<div id="test-jquery">
<p id="para-1" class="color-red">JavaScript</p>
<p id="para-2" class="color-green">Haskell</p>
<p class="color-red color-green">Erlang</p>
<p name="name" class="color-black">Python</p>
<form class="test-form" target="_blank" action="#0" onsubmit="return false;">
<legend>注冊新用戶</legend>
<fieldset>
<p><label>名字: <input name="name"></label></p>
<p><label>郵件: <input name="email"></label></p>
<p><label>口令: <input name="password" type="password"></label></p>
<p><button type="submit">注冊</button></p>
</fieldset>
</form>
</div>
```
運行查看結果:
```
'use strict';
var selected = null;
selected = ???;
// 高亮結果:
if (!(selected instanceof jQuery)) {
return alert('不是有效的jQuery對象!');
}
$('#test-jquery').find('*').css('background-color', '');
selected.css('background-color', '#ffd351');
```
- JavaScript教程
- JavaScript簡介
- 快速入門
- 基本語法
- 數據類型和變量
- 字符串
- 數組
- 對象
- 條件判斷
- 循環
- Map和Set
- iterable
- 函數
- 函數定義和調用
- 變量作用域
- 方法
- 高階函數
- map/reduce
- filter
- sort
- 閉包
- 箭頭函數
- generator
- 標準對象
- Date
- RegExp
- JSON
- 面向對象編程
- 創建對象
- 原型繼承
- 瀏覽器
- 瀏覽器對象
- 操作DOM
- 更新DOM
- 插入DOM
- 刪除DOM
- 操作表單
- 操作文件
- AJAX
- Promise
- Canvas
- jQuery
- 選擇器
- 層級選擇器
- 查找和過濾
- 操作DOM
- 修改DOM結構
- 事件
- 動畫
- 擴展
- underscore
- Collections
- Arrays
- Functions
- Objects
- Chaining
- Node.js
- 安裝Node.js和npm
- 第一個Node程序
- 模塊
- 基本模塊
- fs
- stream
- http
- buffer
- Web開發
- koa
- mysql
- swig
- 自動化工具
- 期末總結
- Python 2.7教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷和循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 使用__future__
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- 常用第三方模塊
- PIL
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 協程
- gevent
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫數據庫模塊
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 添加配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- 期末總結
- Python3教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- async/await
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結
- Git教程
- Git簡介
- Git的誕生
- 集中式vs分布式
- 安裝Git
- 創建版本庫
- 時光機穿梭
- 版本回退
- 工作區和暫存區
- 管理修改
- 撤銷修改
- 刪除文件
- 遠程倉庫
- 添加遠程庫
- 從遠程庫克隆
- 分支管理
- 創建與合并分支
- 解決沖突
- 分支管理策略
- Bug分支
- Feature分支
- 多人協作
- 標簽管理
- 創建標簽
- 操作標簽
- 使用GitHub
- 自定義Git
- 忽略特殊文件
- 配置別名
- 搭建Git服務器
- 期末總結