From a5f6ba7e0ba83eec69747c4dfaacd8ce55bc55ec Mon Sep 17 00:00:00 2001 From: LeviDing Date: Thu, 19 Mar 2020 17:51:58 +0800 Subject: [PATCH 1/4] Update article.md --- .../04-searching-elements-dom/article.md | 252 +++++++++--------- 1 file changed, 130 insertions(+), 122 deletions(-) diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index c5e52bbe2e..e0a2cb928b 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -1,13 +1,32 @@ -# 搜索: getElement* 和 querySelector* +# 搜索:getElement*,querySelector* -当元素关联较密切时,DOM 导航属性是最好的。万一不是这样该怎么办?如何去获取页面上的任意一个元素? +当元素彼此靠得近时,DOM 导航(navigation)属性是最好的。如果不是,那该怎么办?如何去获取页面上的任意一个元素? + +还有其他搜索方法。 -还有其他的搜索方法。 ## document.getElementById 或者只使用 id -如果元素有 `id` 属性,那么该 `id` 也会有一个同名全局变量。 +如果一个元素有 `id` 属性,那我们就可以使用 `document.getElementById(id)` 方法获取该元素,无论它在哪里。 -我们可以用以下方式来访问元素: +例如: + +```html run +
+
Element
+
+ + +``` + +此外,还有一个通过 `id` 命名的全局变量,它引用了元素: ```html run
@@ -15,57 +34,140 @@
``` -除非我们自己声明同名变量: +……除非我们声明一个具有相同名称的 JavaScript 变量,否则它具有优先权: ```html run untrusted height=0
``` -[在规范中](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem)描述了这种行为,主要是考虑到兼容性才对它进行了支持。为了帮助我们,浏览器尝试了混合 JS 和 DOM 的命名空间。但这仅仅对简单脚本有效,因为它们可能会产生命名冲突。同时,当我们在 JS 中查看时,因为无法在视图中查看 HTML,所以变量的来源可能会很模糊。 +```warn header="请不要使用以 id 命名的全局变量来访问元素" +[在规范中](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem) 对此行为进行了描述,所以它是一种标准。但这是注意考虑到兼容性才支持的。 -选择特殊的方法,才是最好的选择:`document.getElementById(id)`。 +浏览器尝试通过混合 JavaScript 和 DOM 的命名空间来帮助我们。对于内联到 HTML 中的简单脚本来说,这还行,但是通常来说,这不是一件好事。因为这可能会造成命名冲突。另外,当人们阅读 JavaScript 代码且看不到对应的 HTML 时,变量的来源就会不明显。 -例如: +在本教程中,我们只会在元素来源非常明显时,为了简洁起见,才会使用 `id` 直接引用对应的元素。 -```html run -
-
Element
-
+在实际开发中,`document.getElementById` 是首选方法。 +``` + +```smart header="`id` 必须是唯一的" +`id` 必须是唯一的。在文档中,只能有一个元素带有给定的 `id`。 +如果有多个元素都带有同一个 `id`,那么使用它的方法的行为是不可预测的,例如 `document.getElementById` 可能会随机返回其中一个元素。因此,请遵守规则,保持 `id` 的唯一性。 +``` + +```warn header="只有 `document.getElementById`,没有 `anyElem.getElementById`" +`getElementById` 方法只能被在 `document` 对象上调用。它会在整个文档中查找给定的 `id`。 +``` + +## querySelectorAll [#querySelectorAll] + +到目前为止,最通用的方法是 `elem.querySelectorAll(css)`,它返回 `elem` 中与给定 CSS 选择器匹配的所有元素。 + +在这里,我们查找所有为最后一个子元素的 `
  • ` 元素: + +```html run + + ``` -本教程中,我们经常使用 `id` 来直接引用属性,但这仅仅是为了简化。实际开发中,使用 `document.getElementById` 才是最佳选择。 +这个方法确实功能强大,因为可以使用任何 CSS 选择器。 + +```smart header="也可以使用伪类" +CSS 选择器的伪类,例如 `:hover` 和 `:active` 也都是被支持的。例如,`document.querySelectorAll(':hover')` 将会返回指针现在已经结束的元素的集合(按嵌套顺序:从最外层 `` 到嵌套最多的元素)。 +``` + +## querySelector [#querySelector] + +`elem.querySelector(css)` 调用返回给定 CSS 选择器的第一个元素。 -```smart header="There can be only one" -`id` 必须唯一,文档中给定的 `id` 只能有唯一一个元素。 +换句话说,结果与 `elem.querySelectorAll(css)[0]` 相同,但是后者会从**所有**找到的元素中选取一个,而 `elem.querySelector` 只会查找一个。因此编写会更快更简洁。 + +## matches + +之前的方法是搜索 DOM 的。 + +[elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) 不会查找任何内容,它只会检查 `elem` 是否匹配给定的 CSS 选择器。它返回 `true` 或者 `false`。 + +当我们迭代元素(例如数组或者一些其他内容)并试图过滤那些我们感兴趣的元素时,这个方法会很方便。 -如果有多个元素具有同名 `id`,那么对应方法的行为将不可预测。浏览器将随机返回其他的一个。因此未来保证 `id` 的唯一性,请严格遵守规则。 +例如: + +```html run +... +... + + ``` -```warn header="Only `document.getElementById`, not `anyNode.getElementById`" -`getElementById` 只能在 `document` 对象上调用。它会在整个文档中查找给定的 `id`。 +## closest + +所有直接在给定元素之上的元素都被称为它的“祖先”。 + +换句话说,祖先是:父类,父类的父类,它的父类等。祖先们一起组成了从元素到顶端的父类链。 + +`elem.closest(css)` 方法会查找与 CSS 选择器匹配的最接近的祖先。`elem` 自己也会被搜索。 + +换句话说,方法 `closest` 在元素中得到了提升,并检查每个父类。如果与选择器匹配,则停止搜索并返回祖先。 + +例如: + +```html run +

    Contents

    + +
    +
      +
    • Chapter 1
    • +
    • Chapter 1
    • +
    +
    + + ``` ## getElementsBy* @@ -161,104 +263,10 @@ document.getElementsByTagName('input')[0].value = 5; ``` -## querySelectorAll [#querySelectorAll] - -现在将进行重要的内容 -`elem.querySelectorAll(css)` 的调用将返回与给定 CSS 选择器匹配 `elem` 中的所有元素。这是最常用和最有力的方法。 -我们将查找所有为最后一个子元素的 `
  • ` 元素: -```html run - - - -``` - -因为可以使用任何 CSS 选择器,所以这种方法很有用。 - -```smart header="Can use pseudo-classes as well" -CSS 选择器的伪类,如 `:hover` 和 `:active` 都是被支持的。例如,`document.querySelectorAll(':hover')` 将会返回指针现在已经结束的集合(按嵌套顺序:从最外层 `` 到嵌套最多的元素)。 -``` - - -## querySelector [#querySelector] - -调用 `elem.querySelector(css)` 后,它会返回给定 CSS 选择器的第一个元素。 - -换句话说,结果与 `elem.querySelectorAll(css)[0]` 相同,但是后者会从**所有**找到的元素中选取一个,而 `elem.querySelector` 只会查找一个。因此编写会更快更简洁。 - -## matches - -之前的方法是搜索 DOM 的。 - -[elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) 不会查找任何内容,它只会检查 `elem` 是否匹配给定的 CSS 选择器。它返回 `true` 或者 `false`。 - -当我们迭代元素(例如数组或者一些其他内容)并试图过滤那些我们感兴趣的元素时,这个方法会很方便。 - -例如: - -```html run -... -... - - -``` - -## closest - -所有直接在给定元素之上的元素都被称为它的“祖先”。 - -换句话说,祖先是:父类,父类的父类,它的父类等。祖先们一起组成了从元素到顶端的父类链。 - -`elem.closest(css)` 方法会查找与 CSS 选择器匹配的最接近的祖先。`elem` 自己也会被搜索。 - -换句话说,方法 `closest` 在元素中得到了提升,并检查每个父类。如果与选择器匹配,则停止搜索并返回祖先。 - -例如: - -```html run -

    Contents

    - -
    -
      -
    • Chapter 1
    • -
    • Chapter 1
    • -
    -
    - - -``` ## Live 集合 From 4af3dd8aab0742cd99ae5cf1d77bcedc807063b1 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Thu, 19 Mar 2020 19:50:55 +0800 Subject: [PATCH 2/4] Update article.md --- .../04-searching-elements-dom/article.md | 122 ++++++++---------- 1 file changed, 55 insertions(+), 67 deletions(-) diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index e0a2cb928b..f0729aa565 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -108,17 +108,17 @@ CSS 选择器的伪类,例如 `:hover` 和 `:active` 也都是被支持的。 ## querySelector [#querySelector] -`elem.querySelector(css)` 调用返回给定 CSS 选择器的第一个元素。 +`elem.querySelector(css)` 调用会返回给定 CSS 选择器的第一个元素。 -换句话说,结果与 `elem.querySelectorAll(css)[0]` 相同,但是后者会从**所有**找到的元素中选取一个,而 `elem.querySelector` 只会查找一个。因此编写会更快更简洁。 +换句话说,结果与 `elem.querySelectorAll(css)[0]` 相同,但是后者会查找 **所有** 元素,并从中选取一个,而 `elem.querySelector` 只会查找一个。因此它在速度上更快,并且写起来更短。 ## matches -之前的方法是搜索 DOM 的。 +之前的方法是搜索 DOM。 -[elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) 不会查找任何内容,它只会检查 `elem` 是否匹配给定的 CSS 选择器。它返回 `true` 或者 `false`。 +[elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) 不会查找任何内容,它只会检查 `elem` 是否与给定的 CSS 选择器匹配。它返回 `true` 或 `false`。 -当我们迭代元素(例如数组或者一些其他内容)并试图过滤那些我们感兴趣的元素时,这个方法会很方便。 +当我们遍历元素(例如数组或其他内容)并试图过滤那些我们感兴趣的元素时,这个方法会很有用。 例如: @@ -127,7 +127,7 @@ CSS 选择器的伪类,例如 `:hover` 和 `:active` 也都是被支持的。 ... ``` -```warn header="Don't forget the `\"s\"` letter!" -初级开发者会忽略字符 `"s"`。也就是说,它们会调用 `getElementByTagName` 而不是 getElementsByTagName。 +```warn header="不要忘记字母 `\"s\"`!" +新手开发者有时会忘记字符 `"s"`。也就是说,他们会调用 `getElementByTagName` 而不是 getElementsByTagName。 -`"s"` 字符并不存在于 `getElementById`,因为它只返回单个元素。但是 `getElementsByTagName` 返回的是一个元素集合,所以 `"s"` 包含在内。 +`getElementById` 中没有字母 `"s"`,是因为它只返回单个元素。但是 `getElementsByTagName` 返回的是元素的集合,所以里面有 `"s"`。 ``` -````warn header="It returns a collection, not an element!" -另一个普遍存在的错误写法是: +````warn header="它返回的是一个集合,不是一个元素!" +新手的另一个普遍的错误是写: ```js -// 无法运行 +// 行不通 document.getElementsByTagName('input').value = 5; ``` -这无法运行,因为它接受输入的**集合**然后将值赋给它,而不是它里面的元素。 +这是行不通的,因为它需要的是一个 input 的 **集合**,并将值赋(assign)给它,而不是赋值给其中的一个元素。 -我们应该迭代集合或者按给定索引来获取元素,然后赋值,就像下述所示: +我们应该遍历集合或通过对应的索引来获取元素,然后赋值,如下所示: ```js -// 应该可以运行(如果有输入) +// 应该可以运行(如果有 input) document.getElementsByTagName('input')[0].value = 5; ``` ```` -还有其他很少使用的方法: - -- `elem.getElementsByClassName(className)` 返回具有给定 CSS 类的元素。元素也可能含有其他的类。 -- `document.getElementsByName(name)` 返回具有给定 `name` 属性的元素,文档范围。因为历史原因而很少使用。在这里提出,只是考虑到了完整性。 - -例如: +查找 `.article` 元素: ```html run height=50
    @@ -254,28 +251,23 @@ document.getElementsByTagName('input')[0].value = 5;
    ``` +## 实时的集合 +所有的 `"getElementsBy*"` 方法都会返回一个 **实时的(live)** 集合。这样的集合始终反映的是文档的当前状态,并且在文档发生更改时会“自动更新”。 +在下面的例子中,有两个脚本。 - - -## Live 集合 - -所有的 `"getElementsBy*"` 方法都会返回 **live** 集合。这类集合总是可以反映出文档的当前状态而且在文档变化时,可以自动更新。 - -下面的实例中,有两个脚本。 - -1. 第一个方法创建了对集合 `
    ` 的引用。到目前为止,它的长度是 `1`。 -2. 第二个脚本在浏览器再遇到一个 `
    ` 时,它的长度会变成 `2`。 +1. 第一个创建了对 `
    ` 的集合的引用。截至目前,它的长度是 `1`。 +2. 第二个脚本在浏览器再遇到一个 `
    ` 时运行,所以它的长度是 `2`。 ```html run
    First div
    @@ -294,7 +286,7 @@ document.getElementsByTagName('input')[0].value = 5; ``` -相反,`querySelectorAll` 会返回一个**static**集合。就像一个固定的元素数字。 +相反,`querySelectorAll` 返回的是一个 **静态的** 集合。就像元素的固定数组。 如果我们使用它,那么两个脚本都会输出 `1`: @@ -316,13 +308,11 @@ document.getElementsByTagName('input')[0].value = 5; ``` -现在我们可以很容易地看到不同之处。在文档中出现一个新的 `div` 后,静态集合并没有增加。 - -我们在这里使用独立的脚本来说明元素添加是如何影响集合的,但是在此之后的任何 DOM 操作都会影响它们。很快我们就可以看到更多的细节。 +现在我们可以很容易地看到不同之处。在文档中出现新的 `div` 后,静态集合并没有增加。 ## 总结 -有 6 种主要的方法,可以在 DOM 中进行搜素: +有 6 种主要的方法,可以在 DOM 中搜素节点: @@ -335,6 +325,18 @@ document.getElementsByTagName('input')[0].value = 5; + + + + + + + + + + + + @@ -358,29 +360,15 @@ document.getElementsByTagName('input')[0].value = 5; - - - - - - - - - - - -
    querySelectorCSS-selector-
    querySelectorAllCSS-selector-
    getElementById id -
    querySelectorCSS-selector-
    querySelectorAllCSS-selector-
    -请注意,只有在文档 `document.getElementById(...)` 的上下文中才能调用 `getElementById` 和 `getElementsByName`。但元素中没有 `elem.getElementById(...)` 会报错。 - -也可以在元素上调用其他方法,例如 `elem.querySelectorAll(...)` 将会在 `elem`(在 DOM 子树中)内部进行搜素。 +目前为止,最常用的是 `querySelector` 和 `querySelectorAll`,但是 `getElementBy*` 可能会偶尔有用,或者可以在就脚本中找到。 -除此以外: +此外: - `elem.matches(css)` 用于检查 `elem` 与给定的 CSS 选择器是否匹配。 - `elem.closest(css)` 用于查找与给定 CSS 选择器相匹配的最近的祖先。`elem` 本身也会被检查。 -最后我们在提一种检查父子关系的方法: -- 如果 `elemB` 在 `elemA`(`elemA` 的后代)中或者当 `elemA==elemB` 时 `elemA.contains(elemB)` 将返回 true。 +让我们在这里提一下另一种用来检查子级与父级之间关系的方法,因为它有时很有用: +- 如果 `elemB` 在 `elemA` 内(`elemA` 的后代)或者 `elemA==elemB`,`elemA.contains(elemB)` 将返回 true。 From e1a7a66c59bfd9a51842e6c0c556dc3301d7fbee Mon Sep 17 00:00:00 2001 From: LeviDing Date: Thu, 19 Mar 2020 19:59:17 +0800 Subject: [PATCH 3/4] Update task.md --- .../1-find-elements/task.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/2-ui/1-document/04-searching-elements-dom/1-find-elements/task.md b/2-ui/1-document/04-searching-elements-dom/1-find-elements/task.md index ef01ae7f4a..71024c7b4f 100644 --- a/2-ui/1-document/04-searching-elements-dom/1-find-elements/task.md +++ b/2-ui/1-document/04-searching-elements-dom/1-find-elements/task.md @@ -4,15 +4,15 @@ importance: 4 # 搜索元素 -这是带有表格和表单的文档。 +这是带有表格(table)和表单(form)的文档。 -如何查找? +如何查找?…… -1. `id="age-table"` 的表格。 -2. 所有的 `label` 元素都内嵌于表格(应该有三个)。 -3. 表格中的第一个 `td`(字段是 "Age")。 -4. `form` 的一个字段是 `search`。 -5. 第一个 `input` 在表单中。 -6. 最后一个 `input` 在表单中。 +1. 带有 `id="age-table"` 的表格。 +2. 表格内的所有 `label` 元素(应该有三个)。 +3. 表格中的第一个 `td`(带有 "Age" 字段)。 +4. 带有 `name="search"` 的 `form`。 +5. 表单中的第一个 `input`。 +6. 表单中的最后一个 `input`。 -新开一个独立的窗口,打开页面 [table.html](table.html),然后再此页面上使用开发者工具。 +在一个单独的窗口中打开 [table.html](table.html) 页面,并对此页面使用浏览器开发者工具。 From 372997f94e8ce750cb3d2c92431974e5e7d04e20 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Thu, 19 Mar 2020 20:45:15 +0800 Subject: [PATCH 4/4] Update solution.md --- .../1-find-elements/solution.md | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/2-ui/1-document/04-searching-elements-dom/1-find-elements/solution.md b/2-ui/1-document/04-searching-elements-dom/1-find-elements/solution.md index 1ec4ebf131..cefc4a2443 100644 --- a/2-ui/1-document/04-searching-elements-dom/1-find-elements/solution.md +++ b/2-ui/1-document/04-searching-elements-dom/1-find-elements/solution.md @@ -1,36 +1,35 @@ 实现的方式有很多种。 -以下是列举的一些方法: +以下列举的是其中一些方法: ```js -// 1. The table with `id="age-table"`. +// 1. 带有 id="age-table" 的表格。 let table = document.getElementById('age-table') -// 2. All label elements inside that table +// 2. 表格内的所有 label 元素 table.getElementsByTagName('label') -// or +// 或 document.querySelectorAll('#age-table label') -// 3. The first td in that table (with the word "Age"). +// 3. 表格中的第一个 td(带有 "Age" 字段) table.rows[0].cells[0] -// or +// 或 table.getElementsByTagName('td')[0] -// or +// 或 table.querySelector('td') -// 4. The form with the name "search". -// assuming there's only one element with name="search" +// 4. 带有 name="search" 的 form。 +// 假设文档中只有一个 name="search" 的元素 let form = document.getElementsByName('search')[0] -// or, form specifically +// 或者,专门对于 form document.querySelector('form[name="search"]') -// 5. The first input in that form. -form.getElementsByTagName('input') -// or +// 5. 表单中的第一个 input +form.getElementsByTagName('input')[0] +// 或 form.querySelector('input') -// 6. The last input in that form. -// there's no direct query for that -let inputs = form.querySelectorAll('input') // search all -inputs[inputs.length-1] // take last +// 6. 表单中的最后一个 input +let inputs = form.querySelectorAll('input') // 查找所有 input +inputs[inputs.length-1] // 取出最后一个 ```