# 选择器
选择器是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服务器
- 期末总结