chore(i18n,learn): processed translations (#41378)
* chore(i8n,learn): processed translations * Update curriculum/challenges/chinese/01-responsive-web-design/applied-visual-design/use-the-u-tag-to-underline-text.md Co-authored-by: Randell Dawson <5313213+RandellDawson@users.noreply.github.com> Co-authored-by: Crowdin Bot <support+bot@crowdin.com> Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com> Co-authored-by: Randell Dawson <5313213+RandellDawson@users.noreply.github.com>
This commit is contained in:
@ -11,11 +11,11 @@ dashedName: jump-straight-to-the-content-using-the-main-element
|
|||||||
|
|
||||||
HTML5 引入了一些新元素,其中包括无障碍特性,给予开发者更多的选择。 HTML5 引入了诸如 `main`、`header`、`footer`、`nav`、`article`、`section` 等大量新标签。
|
HTML5 引入了一些新元素,其中包括无障碍特性,给予开发者更多的选择。 HTML5 引入了诸如 `main`、`header`、`footer`、`nav`、`article`、`section` 等大量新标签。
|
||||||
|
|
||||||
默认情况下,浏览器呈现这些新标签的方式与 `div` 相似。 但是,在适当的地方使用它们,会给标签额外的意义。 仅标签名称就可以表示它所包含的信息类型,这给内容增加了语义含义。 辅助技术可以获取这种信息,为用户提供更好的页面摘要或导航选项。
|
默认情况下,浏览器呈现这些元素的方式类似于普通的 `div`。 但是,在适当的地方使用它们会让标记文本具有更多的含义。 仅标签名称就可以表示它所包含的信息类型,这给内容增加了语义含义。 辅助技术可以获取这种信息,为用户提供更好的页面摘要或导航选项。
|
||||||
|
|
||||||
`main` 标签用于呈现网页的主体内容,且每个页面应只有一个。 这意味着它只应包含与页面中心主题相关的信息, 而不应包含如导航连接、网页横幅等需要在多个页面中重复出现的内容。
|
`main` 标签用于呈现网页的主体内容,且每个页面应只有一个。 这意味着它只应包含与页面中心主题相关的信息, 而不应包含如导航连接、网页横幅等需要在多个页面中重复出现的内容。
|
||||||
|
|
||||||
`main` 标签的语义化特性可以让辅助工具快速定位到页面的主体。 如果你在页面的顶部看到“跳转到主要内容”的链接,使用 `main` 标签可以自动让辅助设备提供那个功能。
|
`main` 标签的语义化特性可以让辅助工具快速定位到页面的主体。 如果你在页面顶部看到过“跳转到主要内容”链接,那么使用 `main` 标签会自动让辅助设备具有这个跳转的功能。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ dashedName: use-tabindex-to-add-keyboard-focus-to-an-element
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
HTML 的 `tabindex` 属性有三种与标签焦点相关的功能。 给标签加上 tabindex,表示该标签可以获得焦点。 tabindex 的值(可以是零、负整数或正整数)定义了行为。
|
HTML 的 `tabindex` 属性有三种与标签焦点相关的功能。 当它在一个元素上时,表示该元素可以获得焦点。 tabindex 的值(可以是零、负整数或正整数)定义了行为。
|
||||||
|
|
||||||
当用户使用键盘浏览页面时,诸如链接、表单控件等元素可以自动获得焦点。 它们获得焦点的顺序与它们出现在 HTML 文档流中的顺序一致。 我们可以通过将其他标签(如 `div`、`span`、`p` 等)的 `tabindex` 属性值设为 0 来让它们实现类似的效果。 比如:
|
当用户使用键盘浏览页面时,诸如链接、表单控件等元素可以自动获得焦点。 它们获得焦点的顺序与它们出现在 HTML 文档流中的顺序一致。 我们可以通过将其他标签(如 `div`、`span`、`p` 等)的 `tabindex` 属性值设为 0 来让它们实现类似的效果。 比如:
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ dashedName: wrap-radio-buttons-in-a-fieldset-element-for-better-accessibility
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
下一个表单主题涵盖单选按钮的可访问性。 在上一个挑战中,每个单选按钮都有一个包含 `for` 属性的 `label` 标签,这些属性值指向相关选项的 `id`。 然而单选按钮通常成组出现,而且用户必须选择其中一项。
|
接下来的表单主题是关于单选按钮的可访问性。 在上一个挑战中,每个单选按钮都有一个包含 `for` 属性的 `label` 标签,这些属性值指向相关选项的 `id`。 然而单选按钮通常成组出现,而且用户必须选择其中一项。
|
||||||
|
|
||||||
`fieldset` 标签包裹整组单选按钮,实现这个功能。 我们可以使用 `fieldset` 标签将单选按钮组包含在里面,通常还会使用 `legend` 标签来为单选按钮组提供文字说明。 屏幕阅读器也可以朗读这些文字。
|
`fieldset` 标签包裹整组单选按钮,实现这个功能。 我们可以使用 `fieldset` 标签将单选按钮组包含在里面,通常还会使用 `legend` 标签来为单选按钮组提供文字说明。 屏幕阅读器也可以朗读这些文字。
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ dashedName: adjust-the-tone-of-a-color
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
所有元素的默认 `background-color` 都是 `transparent`。 当前页面的导航栏 `nav` 背景色之所以看起来是蓝绿色,是因为它背后的 `header` 的 `background-color` 属性值为 `cyan`。 请将 `nav` 的 `background-color` 也设置为 `cyan`,但把它的饱和度调整为 `80% saturation`,亮度调整为 `25% lightness`。
|
所有元素的默认 `background-color` 都是 `transparent`。 当前页面的导航栏 `nav` 背景色之所以看起来是蓝绿色,是因为它背后的 `header` 的 `background-color` 属性值为 `cyan`。 给 `nav` 元素增加一个 `background-color`,使它的颜色也为 `cyan`,饱和度为 `80%`,亮度为 `25%`,以修改它的色调和阴影。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ dashedName: use-the-u-tag-to-underline-text
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
|
`u` 标签包裹的文本内容应为 `Ph.D. students`。
|
||||||
|
|
||||||
**注意:** 如果使用 `u` 标签添加下划线,可能混淆文本和链接,则应避免使用它。 锚标签也有默认的下划线格式。
|
**注意:** 如果使用 `u` 标签添加下划线,可能混淆文本和链接,则应避免使用它。 锚标签也有默认的下划线格式。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
@ -23,7 +25,7 @@ dashedName: use-the-u-tag-to-underline-text
|
|||||||
assert($('u').length === 1);
|
assert($('u').length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
`u` 标签的内容文本应为 `Ph.D. students`。
|
`u` 标签的文本内容应为 `Ph.D. students`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('u').text() === 'Ph.D. students');
|
assert($('u').text() === 'Ph.D. students');
|
||||||
@ -107,12 +109,12 @@ assert($('u').text() === 'Ph.D. students');
|
|||||||
<div class="cardContent">
|
<div class="cardContent">
|
||||||
<div class="cardText">
|
<div class="cardText">
|
||||||
<h4>Google</h4>
|
<h4>Google</h4>
|
||||||
<p>Google was founded by Larry Page and Sergey Brin while they were <u>Ph.D.
|
<p>Google was founded by Larry Page and Sergey Brin while they were <u>Ph.D. students</u> at <strong>Stanford University</strong>.</p>
|
||||||
students</u> at <strong>Stanford University</strong>.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cardLinks">
|
<div class="cardLinks">
|
||||||
<a href="https://en.wikipedia.org/wiki/Larry_Page" target="_blank" class="links">Larry Page</a><br><br>
|
<a href="https://en.wikipedia.org/wiki/Larry_Page" target="_blank" class="links">Larry Page</a><br><br>
|
||||||
<a href="https://en.wikipedia.org/wiki/Sergey_Brin" target="_blank" class="links">Sergey Brin</a>
|
<a href="https://en.wikipedia.org/wiki/Sergey_Brin" target="_blank" class="links">Sergey Brin</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
@ -9,7 +9,7 @@ dashedName: add-flex-superpowers-to-the-tweet-embed
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
我们以右边的嵌入推文为例, 一些元素换一个布局方式或许更好看。 上一个挑战演示了 `display: flex`, 现在你需要把它添加到推文内嵌的多个组件中,调整它们的位置。
|
以右边的嵌入推文为例, 一些元素换一个布局方式或许更好看。 上一个挑战演示了 `display: flex`, 现在你需要把它添加到推文内嵌的多个组件中,调整它们的位置。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ dashedName: add-gaps-faster-with-grid-gap
|
|||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
class 为 `container` 的元素应具有 `grid-gap` 属性,并将行间距设置为 `10px`,列间距设置为 `20px`。
|
`container` class 应该有一个 `grid-gap` 属性,在行之间设置 `10px` 的间距,在列之间设置 `20px` 的间距。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -9,7 +9,7 @@ dashedName: add-rows-with-grid-template-rows
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
在上个挑战中,你创建的网格会自动设置行数。 你可以用 `grid-template-rows` 设置网格的行,就像用 `grid-template-columns` 设置网格的列那样。
|
在上个挑战中,你创建的网格会自动设置行数。 要手动调整行,请使用 `grid-template-rows` 属性,就像在上一个挑战中使用 `grid-template-columns` 属性一样。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ dashedName: create-flexible-layouts-using-auto-fit
|
|||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
class 为 `container2` 的元素应具有 `grid-template-columns` 属性,且属性值应使用 `repeat` 和 `auto-fit`,以便将最小宽度为 `60px`、最大宽度为 `1fr` 的列填充至网格。
|
`container2` class 应该有一个 `grid-template-columns` 属性,通过 `repeat` 和 `auto-fit` 将网格中的列的宽度设置为最小 `60px`,最大 `1fr`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -9,7 +9,7 @@ dashedName: place-items-in-grid-areas-using-the-grid-area-property
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
像上一个挑战那样,在为网格添加区域模板后,你可以通过引用你所定义的区域的名称,将元素放入相应的区域。 为此,你需要对网格项使用 `grid-area`:
|
像上一个挑战那样,在为网格添加区域模板后,可以通过引用你所定义的区域的名称,将元素放入相应的区域。 为此,你需要对网格项使用 `grid-area`:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.item1 {
|
.item1 {
|
||||||
|
@ -17,7 +17,7 @@ dashedName: use-grid-column-to-control-spacing
|
|||||||
|
|
||||||
<div style='position:relative;margin:auto;background:Gainsboro;display:block;margin-top:100px;margin-bottom:50px;width:200px;height:200px;'><p style='left:25%;top:-30%;font-size:130%;position:absolute;color:RoyalBlue;'>列线</p><p style='left:0%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>1</p><p style='left:30%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>2</p><p style='left:63%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>3</p><p style='left:95%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>4</p><p style='left:-40%;top:45%;font-size:130%;transform:rotateZ(-90deg);position:absolute;'>行线</p><p style='left:-10%;top:-10%;font-size:130%;position:absolute;'>1</p><p style='left:-10%;top:21%;font-size:130%;position:absolute;'>2</p><p style='left:-10%;top:53%;font-size:130%;position:absolute;'>3</p><p style='left:-10%;top:85%;font-size:130%;position:absolute;'>4</p><div style='left:0%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:31%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:63%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:95%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:0%;top:0%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:31%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:63%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:95%;width:100%;height:5%;background:black;position:absolute;'></div></div>
|
<div style='position:relative;margin:auto;background:Gainsboro;display:block;margin-top:100px;margin-bottom:50px;width:200px;height:200px;'><p style='left:25%;top:-30%;font-size:130%;position:absolute;color:RoyalBlue;'>列线</p><p style='left:0%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>1</p><p style='left:30%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>2</p><p style='left:63%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>3</p><p style='left:95%;top:-15%;font-size:130%;position:absolute;color:RoyalBlue;'>4</p><p style='left:-40%;top:45%;font-size:130%;transform:rotateZ(-90deg);position:absolute;'>行线</p><p style='left:-10%;top:-10%;font-size:130%;position:absolute;'>1</p><p style='left:-10%;top:21%;font-size:130%;position:absolute;'>2</p><p style='left:-10%;top:53%;font-size:130%;position:absolute;'>3</p><p style='left:-10%;top:85%;font-size:130%;position:absolute;'>4</p><div style='left:0%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:31%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:63%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:95%;top:0%;width:5%;height:100%;background:RoyalBlue;position:absolute;'></div><div style='left:0%;top:0%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:31%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:63%;width:100%;height:5%;background:black;position:absolute;'></div><div style='left:0%;top:95%;width:100%;height:5%;background:black;position:absolute;'></div></div>
|
||||||
|
|
||||||
你可以用 `grid-column` 属性定义网格项开始和结束的位置,进而控制每个网格项占用的列数。
|
要设置一个网格项占据几列,你可以使用 `grid-column` 属性加上网格线条的编号来定义网格项开始和结束的位置。
|
||||||
|
|
||||||
示例如下:
|
示例如下:
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bd7158d8c442eddfaeb5bd0f
|
id: bd7158d8c442eddfaeb5bd0f
|
||||||
title: Build a 25 + 5 Clock
|
title: 构建一个番茄时钟
|
||||||
challengeType: 3
|
challengeType: 3
|
||||||
forumTopicId: 301373
|
forumTopicId: 301373
|
||||||
dashedName: build-a-25--5-clock
|
dashedName: build-a-25--5-clock
|
||||||
@ -8,71 +8,71 @@ dashedName: build-a-25--5-clock
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/XpKrrW>.
|
**目标:** 在 [CodePen.io](https://codepen.io) 上实现一个功能类似 <https://codepen.io/freeCodeCamp/full/XpKrrW> 的 App。
|
||||||
|
|
||||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
在满足以下[需求](https://en.wikipedia.org/wiki/User_story)并能通过所有测试的前提下, 可以根据自己的喜好来美化 app。
|
||||||
|
|
||||||
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
可以使用 HTML、JavaScript、CSS、Bootstrap、SASS、React、Redux、jQuery 来完成这个挑战。 但鉴于这个章节的学习内容与前端框架相关,推荐使用一款前端框架(比如 React)来完成这个挑战。 不推荐使用前面没有提到的技术,否则风险自负。 我们有计划新增其他前端框架课程,例如 Angular 和 Vue,不过目前还没有这些内容。 如果使用建议的技术栈完成这个项目,我们会接受并尝试修复相关的问题反馈。 编码愉快!
|
||||||
|
|
||||||
**User Story #1:** I can see an element with `id="break-label"` that contains a string (e.g. "Break Length").
|
**需求 1:** 应该能看到一个具有`id="break-label"`属性的元素,这个元素的内容应该是一个字符串(例如:"Break Length")。
|
||||||
|
|
||||||
**User Story #2:** I can see an element with `id="session-label"` that contains a string (e.g. "Session Length").
|
**需求 2:** 应该能看到一个具有`id="session-label"`属性的元素,这个元素的内容应该是一个字符串(例如:"Session Length")。
|
||||||
|
|
||||||
**User Story #3:** I can see two clickable elements with corresponding IDs: `id="break-decrement"` and `id="session-decrement"`.
|
**需求 3:** 应该能看到两个可以点击的元素,他们分别具有如下 id:`id="break-decrement"` 和 `id="session-decrement"`。
|
||||||
|
|
||||||
**User Story #4:** I can see two clickable elements with corresponding IDs: `id="break-increment"` and `id="session-increment"`.
|
**需求 4:** 应该能看到两个可以点击的元素,它们分别具有如下 id:`id="break-increment"` 和 `id="session-increment"`。
|
||||||
|
|
||||||
**User Story #5:** I can see an element with a corresponding `id="break-length"`, which by default (on load) displays a value of 5.
|
**需求 5:** 应该能看到一个具有 `id="break-length"` 属性的元素,这个元素默认展示数值应该为 5(加载后)。
|
||||||
|
|
||||||
**User Story #6:** I can see an element with a corresponding `id="session-length"`, which by default displays a value of 25.
|
**需求 6:** 应该能看到一个具有 `id="session-length"` 属性的元素,这个元素默认展示数值应该为 25(加载后)。
|
||||||
|
|
||||||
**User Story #7:** I can see an element with a corresponding `id="timer-label"`, that contains a string indicating a session is initialized (e.g. "Session").
|
**需求 7:** 应该能看到一个具有 `id="timer-label"` 属性的元素,这个元素包含一个表示当前状态的字符串(例如:"Session")。
|
||||||
|
|
||||||
**User Story #8:** I can see an element with corresponding `id="time-left"`. NOTE: Paused or running, the value in this field should always be displayed in `mm:ss` format (i.e. 25:00).
|
**需求 8:** 应该能看到一个具有 `id="time-left"` 属性的元素。 注意:暂停或者运行时,该元素的内容应始终以 `mm:ss` 格式显示(如 25:00)。
|
||||||
|
|
||||||
**User Story #9:** I can see a clickable element with a corresponding `id="start_stop"`.
|
**需求 9:** 应该能看到一个具有 `id="start_stop"` 属性的可点击的元素。
|
||||||
|
|
||||||
**User Story #10:** I can see a clickable element with a corresponding `id="reset"`.
|
**需求 10:** 应该能看到一个具有 `id="reset"` 属性的可点击的元素。
|
||||||
|
|
||||||
**User Story #11:** When I click the element with the id of `reset`, any running timer should be stopped, the value within `id="break-length"` should return to `5`, the value within `id="session-length"` should return to 25, and the element with `id="time-left"` should reset to it's default state.
|
**需求 11:** 当点击 id 属性为 `reset` 的元素时,运行中的计时器都应该停止,`id="break-length"` 元素中的值应该重新回到 `5`,`id="session-length"` 元素中的值应该重新回到 25,且 `id="time-left"` 元素应该重置为默认状态。
|
||||||
|
|
||||||
**User Story #12:** When I click the element with the id of `break-decrement`, the value within `id="break-length"` decrements by a value of 1, and I can see the updated value.
|
**需求 12:** 当点击 id 属性为 `break-decrement` 的元素时,`id="break-length"` 元素的值应该减去 1,且我应该能看到更新后的值。
|
||||||
|
|
||||||
**User Story #13:** When I click the element with the id of `break-increment`, the value within `id="break-length"` increments by a value of 1, and I can see the updated value.
|
**需求 13:** 当点击 id 属性为 `break-increment` 的元素时,`id="break-length"` 元素的值应该增加 1,且应该能看到更新后的值。
|
||||||
|
|
||||||
**User Story #14:** When I click the element with the id of `session-decrement`, the value within `id="session-length"` decrements by a value of 1, and I can see the updated value.
|
**需求 14:** 当点击 id 属性为 `session-decrement` 的元素时,`id="session-length"` 元素的值应该减去 1,且应该能看到更新后的值。
|
||||||
|
|
||||||
**User Story #15:** When I click the element with the id of `session-increment`, the value within `id="session-length"` increments by a value of 1, and I can see the updated value.
|
**需求 15:** 当点击 id 属性为 `session-increment` 的元素时,`id="session-length"` 元素的值应该增加 1,且应该能看到更新后的值。
|
||||||
|
|
||||||
**User Story #16:** I should not be able to set a session or break length to <= 0.
|
**需求 16:** 工作或者休息长度不应该可以设置为 <= 0 的值。
|
||||||
|
|
||||||
**User Story #17:** I should not be able to set a session or break length to > 60.
|
**需求 17:** 工作或者休息长度比应该可以设置为 > 60 的值。
|
||||||
|
|
||||||
**User Story #18:** When I first click the element with `id="start_stop"`, the timer should begin running from the value currently displayed in `id="session-length"`, even if the value has been incremented or decremented from the original value of 25.
|
**需求 18:** 当首次点击具有 `id="start_stop"` 属性的元素时,计时器应该根据 `id="session-length"` 元素当前显示的值开始运行,即使该值已从原始值 25 递增过或递减过。
|
||||||
|
|
||||||
**User Story #19:** If the timer is running, the element with the id of `time-left` should display the remaining time in `mm:ss` format (decrementing by a value of 1 and updating the display every 1000ms).
|
**需求 19:** 如果计时器正在运行,id 属性为 `time-left` 的元素应该以 `mm:ss` 的格式展示剩余的时间(按1递减并且每秒更新一次显示的值)。
|
||||||
|
|
||||||
**User Story #20:** If the timer is running and I click the element with `id="start_stop"`, the countdown should pause.
|
**需求 20:** 如果计时器正在运行,当点击 `id="start_stop"` 元素时,倒计时应该暂停。
|
||||||
|
|
||||||
**User Story #21:** If the timer is paused and I click the element with `id="start_stop"`, the countdown should resume running from the point at which it was paused.
|
**需求 21:** 如果计时器已经暂停,当点击 `id="start_stop"` 元素时,倒计时应该从暂停的时间点恢复运行。
|
||||||
|
|
||||||
**User Story #22:** When a session countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of `timer-label` should display a string indicating a break has begun.
|
**需求 22:** 当一个工作倒计时结束(注意:计时器必须达到 00:00),并且新的倒计时开始运行时,id 属性为 `timer-label` 的元素应该显示一个表示已经开始休息的字符串。
|
||||||
|
|
||||||
**User Story #23:** When a session countdown reaches zero (NOTE: timer MUST reach 00:00), a new break countdown should begin, counting down from the value currently displayed in the `id="break-length"` element.
|
**需求 23:** 当一个工作倒计时结束(注意:计时器必须达到 00:00),应该开始一个新的休息倒计时,时间应该从 `id="break-length"` 元素中当前显示的值开始计算。
|
||||||
|
|
||||||
**User Story #24:** When a break countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of `timer-label` should display a string indicating a session has begun.
|
**需求 24:** 当一个休息倒计时结束(注意:计时器必须达到 00:00),并且新的倒计时开始运行时,id 属性为 `timer-label` 的元素应该显示一个表示已经开始工作的字符串。
|
||||||
|
|
||||||
**User Story #25:** When a break countdown reaches zero (NOTE: timer MUST reach 00:00), a new session countdown should begin, counting down from the value currently displayed in the `id="session-length"` element.
|
**需求 25:** 当一个休息倒计时结束(注意:计时器必须达到 00:00),应该开始一个新的工作倒计时,时间应该从 `id="session-length"` 元素中当前显示的值开始计算。
|
||||||
|
|
||||||
**User Story #26:** When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 `audio` tag and have a corresponding `id="beep"`.
|
**需求 26:** 当一个倒计时结束(注意:计时器必须达到 00:00),应该播放一个表示时间到了的声音提示。 这个提示音应该使用 HTML5 的 `audio`标签并有一个 `id="beep"` 属性。
|
||||||
|
|
||||||
**User Story #27:** The audio element with `id="beep"` must be 1 second or longer.
|
**需求 27:** 具有`id="beep"`属性的音频元素时长应该至少有一秒。
|
||||||
|
|
||||||
**User Story #28:** The audio element with id of `beep` must stop playing and be rewound to the beginning when the element with the id of `reset` is clicked.
|
**需求 28:** 当点击 id 属性为 `reset` 的元素时,id 属性为 `beep` 的音频元素必须停止播放并回到开头。
|
||||||
|
|
||||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
你可以 fork [这个 CodePen 项目](https://codepen.io/freeCodeCamp/pen/MJjpwO) 来构建你的项目。 或者你可以在任何你喜欢的环境中使用以下 CDN 链接来运行测试:`https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`。
|
||||||
|
|
||||||
Once you're done, submit the URL to your working project with all its tests passing.
|
当你完成了本项目,并且该项目所有测试运行通过, 请提交项目的 URL。
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 587d7dbc367417b2b2512bae
|
id: 587d7dbc367417b2b2512bae
|
||||||
title: Build a Drum Machine
|
title: 构建一台鼓式机器
|
||||||
challengeType: 3
|
challengeType: 3
|
||||||
forumTopicId: 301370
|
forumTopicId: 301370
|
||||||
dashedName: build-a-drum-machine
|
dashedName: build-a-drum-machine
|
||||||
@ -8,29 +8,29 @@ dashedName: build-a-drum-machine
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/MJyNMd>.
|
**目标:** 在 [CodePen.io](https://codepen.io) 上实现一个功能类似 <https://codepen.io/freeCodeCamp/full/MJyNMd> 的 App。
|
||||||
|
|
||||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
在满足以下[需求](https://en.wikipedia.org/wiki/User_story)并能通过所有测试的前提下, 可以根据自己的喜好来美化 app。
|
||||||
|
|
||||||
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
可以使用 HTML、JavaScript、CSS、Bootstrap、SASS、React、Redux、jQuery 来完成这个挑战。 但鉴于这个章节的学习内容与前端框架相关,推荐使用一款前端框架(比如 React)来完成这个挑战。 不推荐使用前面没有提到的技术,否则风险自负。 我们有计划新增其他前端框架课程,例如 Angular 和 Vue,不过目前还没有这些内容。 我们会接受并尝试修复使用推荐技术栈遇到的反馈问题。 编码愉快!
|
||||||
|
|
||||||
**User Story #1:** I should be able to see an outer container with a corresponding `id="drum-machine"` that contains all other elements.
|
**需求 1:** 应该可以看到一个具有 `id="drum-machine"` 属性的外层容器,该容器包含了其它所有元素。
|
||||||
|
|
||||||
**User Story #2:** Within `#drum-machine` I can see an element with a corresponding `id="display"`.
|
**需求 2:** 在具有 `#drum-machine` 属性的元素内,应该能看到一个具有 `id="display"` 属性的元素。
|
||||||
|
|
||||||
**User Story #3:** Within `#drum-machine` I can see 9 clickable drum pad elements, each with a class name of `drum-pad`, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order.
|
**需求 3:** 在具有 `#drum-machine` 属性的元素内,应该能看到 9 个可以点击的鼓垫元素,且每个鼓垫元素都应该有一个值为 `drum-pad` 的 class 属性, 一个用于描述触发鼓垫音频片段的特殊 id,以及以下键值之一的文本内容:`Q`、`W`、`E`、`A`、`S`、`D`、`Z`、`X`、`C`。 这些鼓垫必须按照以上顺序排列。
|
||||||
|
|
||||||
**User Story #4:** Within each `.drum-pad`, there should be an HTML5 `audio` element which has a `src` attribute pointing to an audio clip, a class name of `clip`, and an id corresponding to the inner text of its parent `.drum-pad` (e.g. `id="Q"`, `id="W"`, `id="E"` etc.).
|
**需求 4:** 在每一个具有 `.drum-pad` 属性的元素内,应该有一个具有指向音频片段地址的 `src` 属性的 HTML5 `audio` 元素,一个值为 `clip` 的 class 属性,以及一个 id 属性,它的值应该是其父元素 `.drum-pad` 的文本内容(例如 `id="Q"`、`id="W"`、`id="E"` 等等)。
|
||||||
|
|
||||||
**User Story #5:** When I click on a `.drum-pad` element, the audio clip contained in its child `audio` element should be triggered.
|
**需求 5:** 当点击一个具有 `.drum-pad` 属性的元素时,应该触发它的子元素 `audio` 包含的音频片段。
|
||||||
|
|
||||||
**User Story #6:** When I press the trigger key associated with each `.drum-pad`, the audio clip contained in its child `audio` element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string "Q", pressing the W key should trigger the drum pad which contains the string "W", etc.).
|
**需求 6:** 当按下每一个 `.drum-pad` 元素的关联键时,应该触发其子元素 `audio` 包含的音频片段(例如:按下 `Q` 键应该触发包含字符串 `Q` 的鼓垫,按下 `W` 键应该触发包含字符串 `W` 的鼓垫等等)。
|
||||||
|
|
||||||
**User Story #7:** When a `.drum-pad` is triggered, a string describing the associated audio clip is displayed as the inner text of the `#display` element (each string must be unique).
|
**需求 7:** 当触发一个具有 `.drum-pad` 属性的元素时,`#display` 元素内应该展示这个触发元素关联音频片段的描述字符串(每一个字符串都应该是独一无二的)。
|
||||||
|
|
||||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
可以 fork [这个 CodePen 项目](https://codepen.io/freeCodeCamp/pen/MJjpwO) 来构建你的项目。 或者可以在任何喜欢的环境中使用以下 CDN 链接来运行测试:`https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`。
|
||||||
|
|
||||||
Once you're done, submit the URL to your working project with all its tests passing.
|
当你完成了本项目,并且该项目所有测试运行通过,请提交项目的 URL。
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bd7158d8c442eddfaeb5bd17
|
id: bd7158d8c442eddfaeb5bd17
|
||||||
title: Build a JavaScript Calculator
|
title: 构建一个 JavaScript 计算器
|
||||||
challengeType: 3
|
challengeType: 3
|
||||||
forumTopicId: 301371
|
forumTopicId: 301371
|
||||||
dashedName: build-a-javascript-calculator
|
dashedName: build-a-javascript-calculator
|
||||||
@ -8,52 +8,52 @@ dashedName: build-a-javascript-calculator
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/wgGVVX>.
|
**目标:** 在 [CodePen.io](https://codepen.io) 上实现一个功能类似 <https://codepen.io/freeCodeCamp/full/wgGVVX> 的 App。
|
||||||
|
|
||||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
在满足以下[需求](https://en.wikipedia.org/wiki/User_story)并能通过所有测试的前提下, 可以根据自己的喜好来美化 app。
|
||||||
|
|
||||||
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
可以使用 HTML、JavaScript、CSS、Bootstrap、SASS、React、Redux、jQuery 来完成这个挑战。 但鉴于这个章节的学习内容与前端框架相关,推荐使用一款前端框架(比如 React)来完成这个挑战。 不推荐使用前面没有提到的技术,否则风险自负。 我们有计划新增其他前端框架课程,例如 Angular 和 Vue,不过目前还没有这些内容。 我们会接受并尝试修复使用推荐技术栈遇到的反馈问题。 编码愉快!
|
||||||
|
|
||||||
**User Story #1:** My calculator should contain a clickable element containing an `=` (equal sign) with a corresponding `id="equals"`.
|
**需求 1:** 计算器应该包含一个具有 `id="equals"` 属性的可以点击的元素,元素的文本内容为 `=`(等于符号)。
|
||||||
|
|
||||||
**User Story #2:** My calculator should contain 10 clickable elements containing one number each from 0-9, with the following corresponding IDs: `id="zero"`, `id="one"`, `id="two"`, `id="three"`, `id="four"`, `id="five"`, `id="six"`, `id="seven"`, `id="eight"`, and `id="nine"`.
|
**需求 2:** 计算器应该包含 10 个具有如下 id 属性的可以点击的元素,每个元素的文本内容对应 0-9 的数字:`id="zero"`、`id="one"`、`id="two"`、`id="three"`、`id="four"`、`id="five"`、`id="six"`、`id="seven"`、`id="eight"`、`id="nine"`。
|
||||||
|
|
||||||
**User Story #3:** My calculator should contain 4 clickable elements each containing one of the 4 primary mathematical operators with the following corresponding IDs: `id="add"`, `id="subtract"`, `id="multiply"`, `id="divide"`.
|
**需求 3:** 计算器应该包含四个可以点击的元素,文本内容对应4个主要数学运算符,且应具有如下 id 属性: `id="add"`, `id="subtract"`, `id="multiply"`, `id="divide"`。
|
||||||
|
|
||||||
**User Story #4:** My calculator should contain a clickable element containing a `.` (decimal point) symbol with a corresponding `id="decimal"`.
|
**需求 4:** 计算器应该包含一个可点击的 `.`(小数点)符号,对应的 `id="decimal"`。
|
||||||
|
|
||||||
**User Story #5:** My calculator should contain a clickable element with an `id="clear"`.
|
**需求 5:** 计算器应该包含一个具有 `id="clear"` 属性的可以点击的元素。
|
||||||
|
|
||||||
**User Story #6:** My calculator should contain an element to display values with a corresponding `id="display"`.
|
**需求 6:** 我的计算器应该包含一个用于展示数值的元素,这个元素具有 `id="display"` 属性。
|
||||||
|
|
||||||
**User Story #7:** At any time, pressing the clear button clears the input and output values, and returns the calculator to its initialized state; 0 should be shown in the element with the id of `display`.
|
**需求 7:** 在任何时候按下 `clear` 键,都会清空输入和输出的数值并且使计算器回到初始状态;此时在 id 为 `display` 的元素中应该显示数字 0。
|
||||||
|
|
||||||
**User Story #8:** As I input numbers, I should be able to see my input in the element with the id of `display`.
|
**需求 8:** 在输入数字的同时,应该能看到输入的数字展示在 id 为 `display` 的元素中。
|
||||||
|
|
||||||
**User Story #9:** In any order, I should be able to add, subtract, multiply and divide a chain of numbers of any length, and when I hit `=`, the correct result should be shown in the element with the id of `display`.
|
**需求 9:** 应该可以在任意顺序下对一串任意长度的数字执行加、减、乘、除操作,并且当按下 `=` 时,正确答案应该显示在 id 为 `display` 的元素中。
|
||||||
|
|
||||||
**User Story #10:** When inputting numbers, my calculator should not allow a number to begin with multiple zeros.
|
**需求 10:** 在输入数字的同时,计算器应该不允许一个数字以多个零开头。
|
||||||
|
|
||||||
**User Story #11:** When the decimal element is clicked, a `.` should append to the currently displayed value; two `.` in one number should not be accepted.
|
**需求 11:** 当点击小数点元素时,当前展示的数值后面应该添加一个 `.` 符号;数字中不允许出现两个 `.` 符号。
|
||||||
|
|
||||||
**User Story #12:** I should be able to perform any operation (+, -, \*, /) on numbers containing decimal points.
|
**需求 12:** 我可以对包含小数点的数字执行任何四则运算(`+`、`-`、`*`、`/`)。
|
||||||
|
|
||||||
**User Story #13:** If 2 or more operators are entered consecutively, the operation performed should be the last operator entered (excluding the negative (-) sign). For example, if `5 + * 7 =` is entered, the result should be `35` (i.e. 5 \* 7); if `5 * - 5 =` is entered, the result should be `-25` (i.e. 5 x (-5)).
|
**需求 13:** 如果连续键入了两个及以上的运算符,应该执行最后一次键入的运算符(负数(`-`)运算符除外)。 例如,如果输入 `5 + * 7 =`,结果应该是 `35` (等同于 `5 * 7`);如果输入 `5 * - 5 =`,结果应该是 `-25`(等同于 `5 * (-5)`)。
|
||||||
|
|
||||||
**User Story #14:** Pressing an operator immediately following `=` should start a new calculation that operates on the result of the previous evaluation.
|
**需求 14:** 如果在按下 `=` 符号后继续按一个运算符,则应该在上一次计算结果的基础上进行新的计算。
|
||||||
|
|
||||||
**User Story #15:** My calculator should have several decimal places of precision when it comes to rounding (note that there is no exact standard, but you should be able to handle calculations like `2 / 7` with reasonable precision to at least 4 decimal places).
|
**需求 15:** 当需要四舍五入时,计算器可以处理结果的精度(注意:处理到多少位没有一个准确的标准,但是至少能处理类似 `2 / 7` 这样的计算,使之至少有 4 位小数的精度)。
|
||||||
|
|
||||||
**Note On Calculator Logic:** It should be noted that there are two main schools of thought on calculator input logic: <dfn>immediate execution logic</dfn> and <dfn>formula logic</dfn>. Our example utilizes formula logic and observes order of operation precedence, immediate execution does not. Either is acceptable, but please note that depending on which you choose, your calculator may yield different results than ours for certain equations (see below example). As long as your math can be verified by another production calculator, please do not consider this a bug.
|
**注意计算器的逻辑:** 应当注意的是,计算器输入逻辑主要有两种思路:<dfn>立即执行逻辑</dfn> 和 <dfn>公式逻辑</dfn>。 我们的示例使用公式逻辑并遵守运算优先顺序,而立即执行则不然。 两者都是可以接受的,但请注意,根据你的选择,你的计算器对于某些算式可能会得到与示例不同的计算结果(参见下面的示例)。 只要数学计算可以通过其它现实中计算器的验证,那么代码就是合理的。
|
||||||
|
|
||||||
**EXAMPLE:** `3 + 5 x 6 - 2 / 4 =`
|
**示例:** `3 + 5 x 6 - 2 / 4 =`
|
||||||
|
|
||||||
- **Immediate Execution Logic:** `11.5`
|
- **立即执行逻辑:** `11.5`
|
||||||
- **Formula/Expression Logic:** `32.5`
|
- **公式/表达式逻辑:** `32.5`
|
||||||
|
|
||||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
可以 fork [这个 CodePen 项目](https://codepen.io/freeCodeCamp/pen/MJjpwO) 来构建项目。 或者可以在任何喜欢的环境中使用以下 CDN 链接来运行测试:`https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`。
|
||||||
|
|
||||||
Once you're done, submit the URL to your working project with all its tests passing.
|
当你完成了本项目,并且该项目所有测试运行通过,请提交项目的 URL。
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bd7157d8c242eddfaeb5bd13
|
id: bd7157d8c242eddfaeb5bd13
|
||||||
title: Build a Markdown Previewer
|
title: 构建一个 Markdown 文件预览器
|
||||||
challengeType: 3
|
challengeType: 3
|
||||||
forumTopicId: 301372
|
forumTopicId: 301372
|
||||||
dashedName: build-a-markdown-previewer
|
dashedName: build-a-markdown-previewer
|
||||||
@ -8,29 +8,29 @@ dashedName: build-a-markdown-previewer
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/GrZVVO>.
|
**目标:** 在 [CodePen.io](https://codepen.io) 上实现一个功能类似 <https://codepen.io/freeCodeCamp/full/GrZVVO> 的 App。
|
||||||
|
|
||||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
在满足以下[需求](https://en.wikipedia.org/wiki/User_story)并能通过所有测试的前提下, 你可以根据自己的喜好来美化 app。
|
||||||
|
|
||||||
You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
|
可以使用 HTML、JavaScript、CSS、Bootstrap、SASS、React、Redux、jQuery 来完成这个挑战。 但鉴于这个章节的学习内容与前端框架相关,推荐使用一款前端框架(比如 React)来完成这个挑战。 不推荐使用前面没有提到的技术,否则风险自负。 我们有计划新增其他前端框架课程,例如 Angular 和 Vue,不过目前还没有这些内容。 我们会接受并尝试修复使用推荐技术栈遇到的反馈问题。 编码愉快!
|
||||||
|
|
||||||
**User Story #1:** I can see a `textarea` element with a corresponding `id="editor"`.
|
**需求 1:** 应该能看到一个具有 `id="editor"` 属性的 `textarea` 元素。
|
||||||
|
|
||||||
**User Story #2:** I can see an element with a corresponding `id="preview"`.
|
**需求 2:** 应该能看到一个具有 `id="preview"` 属性的元素。
|
||||||
|
|
||||||
**User Story #3:** When I enter text into the `#editor` element, the `#preview` element is updated as I type to display the content of the textarea.
|
**需求 3:** 当在具有 `#editor` 属性的元素内输入文本时,具有 `#preview` 属性的元素应该同步更新展示键入的内容。
|
||||||
|
|
||||||
**User Story #4:** When I enter GitHub flavored markdown into the `#editor` element, the text is rendered as HTML in the `#preview` element as I type (HINT: You don't need to parse Markdown yourself - you can import the Marked library for this: <https://cdnjs.com/libraries/marked>).
|
**需求 4:** 当在具有 `#editor` 属性的元素内输入 GitHub 风格的 markdown 内容时,文本应该以 HTML 的形式,把所键入的内容渲染在具有 `#preview` 属性的元素中(提示:不需要自己解析 Markdown——可以引入一个叫做 Marked 的库来完成这项工作:<https://cdnjs.com/libraries/marked>)。
|
||||||
|
|
||||||
**User Story #5:** When my markdown previewer first loads, the default text in the `#editor` field should contain valid markdown that represents at least one of each of the following elements: a header (H1 size), a sub header (H2 size), a link, inline code, a code block, a list item, a blockquote, an image, and bolded text.
|
**需求 5:** 当 Markdown 预览器首次加载时,具有 `#editor` 属性的元素内的默认内容应该包含以下每个种类的至少一段有效的 Markdown 代码:标题(H1 标签)、次级标题(H2 标签)、链接、行内代码、代码块、列表、引用块、图片、加粗文本。
|
||||||
|
|
||||||
**User Story #6:** When my markdown previewer first loads, the default markdown in the `#editor` field should be rendered as HTML in the `#preview` element.
|
**需求 6:** 当 Markdown 预览器首次加载时,具有 `#editor` 属性的元素内容应该以 HTML 的形式渲染在具有 `#preview` 属性的元素中。
|
||||||
|
|
||||||
**Optional Bonus (you do not need to make this test pass):** My markdown previewer interprets carriage returns and renders them as `br` (line break) elements.
|
**可选需求(你无需通过这项测试):** Markdown 预览器能够解析回车符并且将他们以 `br`(换行)元素的形式渲染出来。
|
||||||
|
|
||||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
可以 fork [这个 CodePen 项目](https://codepen.io/freeCodeCamp/pen/MJjpwO) 来构建项目。 或者可以在任何喜欢的环境中使用以下 CDN 链接来运行测试:`https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`。
|
||||||
|
|
||||||
Once you're done, submit the URL to your working project with all its tests passing.
|
当你完成了本项目,并且该项目所有测试运行通过,请提交项目的 URL。
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 564944c91be2204b269d51e3
|
id: 564944c91be2204b269d51e3
|
||||||
title: Change Text Inside an Element Using jQuery
|
title: 使用 jQuery 更改元素内部的文本
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 16773
|
forumTopicId: 16773
|
||||||
dashedName: change-text-inside-an-element-using-jquery
|
dashedName: change-text-inside-an-element-using-jquery
|
||||||
@ -8,25 +8,25 @@ dashedName: change-text-inside-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Using jQuery, you can change the text between the start and end tags of an element. You can even change HTML markup.
|
可以通过 jQuery 改变元素开始和结束标签之间的文本。 甚至改变 HTML 标签。
|
||||||
|
|
||||||
jQuery has a function called `.html()` that lets you add HTML tags and text within an element. Any content previously within the element will be completely replaced with the content you provide using this function.
|
jQuery 有一个 `.html()` 函数,能用其在标签里添加 HTML 标签和文本, 函数提供的内容将完全替换之前标签的内容。
|
||||||
|
|
||||||
Here's how you would rewrite and emphasize the text of our heading:
|
下面是重写并强调标题文本的代码:
|
||||||
|
|
||||||
`$("h3").html("<em>jQuery Playground</em>");`
|
`$("h3").html("<em>jQuery Playground</em>");`
|
||||||
|
|
||||||
jQuery also has a similar function called `.text()` that only alters text without adding tags. In other words, this function will not evaluate any HTML tags passed to it, but will instead treat it as the text you want to replace the existing content with.
|
jQuery 还有一个类似的函数 `.text()` 可以在不添加标签的前提下改变标签内的文本。 换言之,这个函数不会识别传入的任何 HTML 标签,而会把它当做想要替换现有内容的文本。
|
||||||
|
|
||||||
Change the button with id `target4` by emphasizing its text.
|
给 id 为 `target4` 的按钮的文本添加强调效果。
|
||||||
|
|
||||||
[View our news article for <em>](https://www.freecodecamp.org/news/html-elements-explained-what-are-html-tags/#em-element) to learn the difference between `<i>` and `<em>` and their uses.
|
查看此[关于 <em> 的文章](https://www.freecodecamp.org/news/html-elements-explained-what-are-html-tags/#em-element)来了解更多 `<i>` 和 `<em>` 的区别和用法。
|
||||||
|
|
||||||
Note that while the `<i>` tag has traditionally been used to emphasize text, it has since been adopted for use as a tag for icons. The `<em>` tag is now widely accepted as the tag for emphasis. Either will work for this challenge.
|
注意,`<i>` 标签虽然传统上用来强调文本,但此后常用作图标的标签。 `<em>` 标签作为强调标签现在已被广泛接受。 使用这两个标签中的任一个都可以完成本次挑战。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should emphasize the text in your `target4` button by adding HTML tags.
|
应该通过添加 HTML 标签强调 `target4` 按钮中的文本。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.isTrue(
|
assert.isTrue(
|
||||||
@ -34,25 +34,25 @@ assert.isTrue(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The text should otherwise remain unchanged.
|
文本应该保持不变。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#target4') && $('#target4').text().trim() === '#target4');
|
assert($('#target4') && $('#target4').text().trim() === '#target4');
|
||||||
```
|
```
|
||||||
|
|
||||||
You should not alter any other text.
|
不应该改变其它任何文本内容。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.isFalse(/<em>|<i>/gi.test($('h3').html()));
|
assert.isFalse(/<em>|<i>/gi.test($('h3').html()));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should be using `.html()` and not `.text()`.
|
应该使用 `.html()` 方法而不是 `.text()` 方法。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\.html\(/g));
|
assert(code.match(/\.html\(/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should select `button id="target4"` with jQuery.
|
应该使用 jQuery 选取 `button id="target4"`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\$\(\s*?(\"|\')#target4(\"|\')\s*?\)\.html\(/));
|
assert(code.match(/\$\(\s*?(\"|\')#target4(\"|\')\s*?\)\.html\(/));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed908826
|
id: bad87fee1348bd9aed908826
|
||||||
title: Change the CSS of an Element Using jQuery
|
title: 使用 jQuery 更改元素的 CSS
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 16776
|
forumTopicId: 16776
|
||||||
required:
|
required:
|
||||||
@ -11,29 +11,29 @@ dashedName: change-the-css-of-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
We can also change the CSS of an HTML element directly with jQuery.
|
也能用 jQuery 直接改变 HTML 标签的 CSS。
|
||||||
|
|
||||||
jQuery has a function called `.css()` that allows you to change the CSS of an element.
|
jQuery 有一个 `.css()` 方法,能改变标签的 CSS。
|
||||||
|
|
||||||
Here's how we would change its color to blue:
|
下面的代码效果是把颜色变蓝:
|
||||||
|
|
||||||
`$("#target1").css("color", "blue");`
|
`$("#target1").css("color", "blue");`
|
||||||
|
|
||||||
This is slightly different from a normal CSS declaration, because the CSS property and its value are in quotes, and separated with a comma instead of a colon.
|
这与通常的 CSS 声明略有不同,因为这个 CSS 属性和它的值在英文引号里,并且它们用逗号而不是冒号间隔开。
|
||||||
|
|
||||||
Delete your jQuery selectors, leaving an empty `document ready function`.
|
删除 jQuery 选择器,并留下空的 `document ready function`。
|
||||||
|
|
||||||
Select `target1` and change its color to red.
|
选择 `target1` 并将其颜色变为红色(red)。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your `target1` element should have red text.
|
`target1` 标签应该有红色文本。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#target1').css('color') === 'rgb(255, 0, 0)');
|
assert($('#target1').css('color') === 'rgb(255, 0, 0)');
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed508826
|
id: bad87fee1348bd9aed508826
|
||||||
title: Clone an Element Using jQuery
|
title: 使用 jQuery 克隆元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 16780
|
forumTopicId: 16780
|
||||||
dashedName: clone-an-element-using-jquery
|
dashedName: clone-an-element-using-jquery
|
||||||
@ -8,33 +8,33 @@ dashedName: clone-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
In addition to moving elements, you can also copy them from one place to another.
|
除了移动标签,也可以把元素从一个地方复制到另一地方。
|
||||||
|
|
||||||
jQuery has a function called `clone()` that makes a copy of an element.
|
jQuery 有一个 `clone()` 方法,可以复制标签。
|
||||||
|
|
||||||
For example, if we wanted to copy `target2` from our `left-well` to our `right-well`, we would use:
|
例如,如果想把 `target2` 从 `left-well` 复制到 `right-well`,可以设置如下:
|
||||||
|
|
||||||
`$("#target2").clone().appendTo("#right-well");`
|
`$("#target2").clone().appendTo("#right-well");`
|
||||||
|
|
||||||
Did you notice this involves sticking two jQuery functions together? This is called <dfn>function chaining</dfn> and it's a convenient way to get things done with jQuery.
|
是否注意到这两个 jQuery 方法连在一起了? 这被称为 <dfn>链式调用(function chaining)</dfn>,是一种用 jQuery 实现效果的简便方法。
|
||||||
|
|
||||||
Clone your `target5` element and append it to your `left-well`.
|
克隆 `target5` 标签并附加到 `left-well`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your `target5` element should be inside your `right-well`.
|
`target5` 标签应该在 `right-well` 内。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#right-well').children('#target5').length > 0);
|
assert($('#right-well').children('#target5').length > 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
A copy of your `target5` element should also be inside your `left-well`.
|
应该克隆 `target5` 标签并放在 `left-well` 内。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#left-well').children('#target5').length > 0);
|
assert($('#left-well').children('#target5').length > 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to move these elements.
|
应该仅用 jQuery 移动这些标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aeda08726
|
id: bad87fee1348bd9aeda08726
|
||||||
title: Delete Your jQuery Functions
|
title: 删除 jQuery 函数
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 17561
|
forumTopicId: 17561
|
||||||
required:
|
required:
|
||||||
@ -11,37 +11,37 @@ dashedName: delete-your-jquery-functions
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
These animations were cool at first, but now they're getting kind of distracting.
|
这些动画开始看起来很酷,但是有时可能会让用户分心。
|
||||||
|
|
||||||
Delete all three of these jQuery functions from your `document ready function`, but leave your `document ready function` itself intact.
|
请删除 `document ready function` 内的三个 jQuery 函数,但保留 `document ready function` 本身。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
All three of your jQuery functions should be deleted from your `document ready function`.
|
应该删除 `document ready function` 中的三个 jQuery 函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\{\s*\}\);/g));
|
assert(code.match(/\{\s*\}\);/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should leave your `script` element intact.
|
应该保持 `script` 标签不变。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/<script>/g));
|
assert(code.match(/<script>/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should leave your `$(document).ready(function() {` at the beginning of your `script` element.
|
应该保持 `$(document).ready(function() {` 在 `script` 标签的开头不变。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\$\(document\)\.ready\(function\(\)\s?\{/g));
|
assert(code.match(/\$\(document\)\.ready\(function\(\)\s?\{/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should leave your "document ready function" closing `})` intact.
|
应该保持 `document.ready` function 用 `})` 闭合。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/.*\s*\}\);/g));
|
assert(code.match(/.*\s*\}\);/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should leave your `script` element closing tag intact.
|
应该保持 `script` 标签闭合。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed808826
|
id: bad87fee1348bd9aed808826
|
||||||
title: Disable an Element Using jQuery
|
title: 使用 jQuery 禁用元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 17563
|
forumTopicId: 17563
|
||||||
dashedName: disable-an-element-using-jquery
|
dashedName: disable-an-element-using-jquery
|
||||||
@ -8,21 +8,21 @@ dashedName: disable-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You can also change the non-CSS properties of HTML elements with jQuery. For example, you can disable buttons.
|
还能用 jQuery 改变 HTML 标签的非 CSS 属性, 例如:禁用按钮。
|
||||||
|
|
||||||
When you disable a button, it will become grayed-out and can no longer be clicked.
|
当禁用按钮时,它将变成灰色并无法点击。
|
||||||
|
|
||||||
jQuery has a function called `.prop()` that allows you to adjust the properties of elements.
|
jQuery 有一个 `.prop()` 方法,可以用其调整标签的属性。
|
||||||
|
|
||||||
Here's how you would disable all buttons:
|
下面是禁用所有的按钮的代码:
|
||||||
|
|
||||||
`$("button").prop("disabled", true);`
|
`$("button").prop("disabled", true);`
|
||||||
|
|
||||||
Disable only the `target1` button.
|
禁用 `target1` 按钮。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your `target1` button should be disabled.
|
应该禁用 `target1` 按钮。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -32,13 +32,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
No other buttons should be disabled.
|
不应该禁用其它的按钮。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#target2') && !$('#target2').prop('disabled'));
|
assert($('#target2') && !$('#target2').prop('disabled'));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 更改元素属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/disabled[^<]*>/g));
|
assert(!code.match(/disabled[^<]*>/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9acdd08826
|
id: bad87fee1348bd9acdd08826
|
||||||
title: Learn How Script Tags and Document Ready Work
|
title: 了解 script 和 document.ready 是如何工作的
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18224
|
forumTopicId: 18224
|
||||||
dashedName: learn-how-script-tags-and-document-ready-work
|
dashedName: learn-how-script-tags-and-document-ready-work
|
||||||
@ -8,23 +8,23 @@ dashedName: learn-how-script-tags-and-document-ready-work
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now we're ready to learn jQuery, the most popular JavaScript tool of all time.
|
马上就要学习有史以来最受欢迎的 JavaScript 框架——jQuery 了。
|
||||||
|
|
||||||
Before we can start using jQuery, we need to add some things to our HTML.
|
在使用 jQuery 之前,需要在 HTML 页面中添加一些东西。
|
||||||
|
|
||||||
First, add a `script` element at the top of your page. Be sure to close it on the following line.
|
首先,在页面顶部添加 `script` 标签, 记得在后面为它添加结束标签。
|
||||||
|
|
||||||
Your browser will run any JavaScript inside a `script` element, including jQuery.
|
浏览器会运行 `script` 标签所有的 JavaScript 脚本包括 jQuery。
|
||||||
|
|
||||||
Inside your `script` element, add this code: `$(document).ready(function() {` to your `script`. Then close it on the following line (still inside your `script` element) with: `});`
|
在 `script` 标签中添加代码 `$(document).ready(function() {`。 然后在后面(仍在该 `script` 标签内)用 `});` 闭合它。
|
||||||
|
|
||||||
We'll learn more about `functions` later. The important thing to know is that code you put inside this `function` will run as soon as your browser has loaded your page.
|
稍后将详细介绍 `functions`, 现在需要知道的是,只要浏览器加载页面,`function` 中放入的代码就会运行。
|
||||||
|
|
||||||
This is important because without your `document ready function`, your code may run before your HTML is rendered, which would cause bugs.
|
有一点很重要,如果没有 `document ready function`,代码将在 HTML 页面呈现之前运行,这可能会导致错误。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should create a `script` element making sure it is valid and has a closing tag.
|
应该创建一个 `script` 标签,确保其有效并具有闭合标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -39,7 +39,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should add `$(document).ready(function() {` to the beginning of your `script` element.
|
应该在 `script` 的开头添加 `$(document).ready(function() {`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -49,7 +49,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should close your `$(document).ready(function() {` function with `});`
|
应该用 `});` 闭合 `$(document).ready(function() {` 函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\n*?\s*?\}\s*?\);/g));
|
assert(code.match(/\n*?\s*?\}\s*?\);/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed708826
|
id: bad87fee1348bd9aed708826
|
||||||
title: Remove an Element Using jQuery
|
title: 使用 jQuery 删除元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18262
|
forumTopicId: 18262
|
||||||
dashedName: remove-an-element-using-jquery
|
dashedName: remove-an-element-using-jquery
|
||||||
@ -8,15 +8,15 @@ dashedName: remove-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now let's remove an HTML element from your page using jQuery.
|
现在学习用 jQuery 从页面移除 HTML 标签。
|
||||||
|
|
||||||
jQuery has a function called `.remove()` that will remove an HTML element entirely
|
jQuery 有一个 `.remove()` 方法,能完全移除 HTML 标签。
|
||||||
|
|
||||||
Remove element `target4` from the page by using the `.remove()` function.
|
用 `.remove()` 方法从页面移除 `target4` 标签。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should use jQuery to remove your `target4` element from your page.
|
应该用 jQuery 从页面中移除 `target4`标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -24,7 +24,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to remove this element.
|
应该仅用 jQuery 移除该标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed918626
|
id: bad87fee1348bd9aed918626
|
||||||
title: Remove Classes from an Element with jQuery
|
title: 使用 jQuery 从元素中移除 class
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18264
|
forumTopicId: 18264
|
||||||
required:
|
required:
|
||||||
@ -11,29 +11,29 @@ dashedName: remove-classes-from-an-element-with-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
In the same way you can add classes to an element with jQuery's `addClass()` function, you can remove them with jQuery's `removeClass()` function.
|
和用 jQuery 的 `addClass()` 方法给标签添加类一样,也可以利用 jQuery 的 `removeClass()` 方法移除它们。
|
||||||
|
|
||||||
Here's how you would do this for a specific button:
|
下面是为指定按钮执行上面的操作的代码:
|
||||||
|
|
||||||
`$("#target2").removeClass("btn-default");`
|
`$("#target2").removeClass("btn-default");`
|
||||||
|
|
||||||
Let's remove the `btn-default` class from all of our `button` elements.
|
请把所有 `button` 标签的 `btn-default` 类移除。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `btn-default` class should be removed from all of your `button` elements.
|
应该移除所有 `button` 标签 `btn-default` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('.btn-default').length === 0);
|
assert($('.btn-default').length === 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to remove this class from the element.
|
应该仅用 jQuery 从标签中移除类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/btn btn-default/g));
|
assert(code.match(/btn btn-default/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only remove the `btn-default` class.
|
应该仅移除 `btn-default` 类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed108826
|
id: bad87fee1348bd9aed108826
|
||||||
title: Target a Specific Child of an Element Using jQuery
|
title: 使用 jQuery 选择元素的特定子元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18315
|
forumTopicId: 18315
|
||||||
required:
|
required:
|
||||||
@ -11,21 +11,21 @@ dashedName: target-a-specific-child-of-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You've seen why id attributes are so convenient for targeting with jQuery selectors. But you won't always have such neat ids to work with.
|
已经看到了 id 属性对于 jQuery 选择器选取标签的便利, 但这并不适用于所有情景。
|
||||||
|
|
||||||
Fortunately, jQuery has some other tricks for targeting the right elements.
|
幸运的是,jQuery 有一些其他的方法可以选取正确的标签。
|
||||||
|
|
||||||
jQuery uses CSS Selectors to target elements. The `target:nth-child(n)` CSS selector allows you to select all the nth elements with the target class or element type.
|
jQuery 可以用 CSS 选择器(CSS Selectors)选取标签。 `target:nth-child(n)` CSS 选择器可以选取指定 class 或者元素类型的的第 n 个标签。
|
||||||
|
|
||||||
Here's how you would give the third element in each well the bounce class:
|
下面的代码展示了给每个区域(well)的第 3 个标签设置弹跳(bounce)动画效果:
|
||||||
|
|
||||||
`$(".target:nth-child(3)").addClass("animated bounce");`
|
`$(".target:nth-child(3)").addClass("animated bounce");`
|
||||||
|
|
||||||
Make the second child in each of your well elements bounce. You must select the elements' children with the `target` class.
|
给 well 元素的第二个子元素添加弹跳(bounce)动画效果。 必须选择具有 `target` class 的子元素。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The second element in your `target` elements should bounce.
|
`target` 元素中的第二个元素应该有弹跳(bounce)动画效果。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -34,19 +34,19 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Only two elements should bounce.
|
应该仅两个标签有弹跳(bounce)动画效果。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('.animated.bounce').length === 2);
|
assert($('.animated.bounce').length === 2);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should use the `:nth-child()` selector to modify these elements.
|
应该用 `:nth-child()` 选择器修改这些标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\:nth-child\(/g));
|
assert(code.match(/\:nth-child\(/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aedc08826
|
id: bad87fee1348bd9aedc08826
|
||||||
title: Target Elements by Class Using jQuery
|
title: 使用 jQuery class 选择器选择元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18316
|
forumTopicId: 18316
|
||||||
required:
|
required:
|
||||||
@ -11,29 +11,29 @@ dashedName: target-elements-by-class-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You see how we made all of your `button` elements bounce? We selected them with `$("button")`, then we added some CSS classes to them with `.addClass("animated bounce");`.
|
如何使所有的 `button` 标签都有弹跳的动画效果? 用 `$("button")` 选取所有的 button 标签,并用 `.addClass("animated bounce");` 给其添加一些 CSS 属性。
|
||||||
|
|
||||||
You just used jQuery's `.addClass()` function, which allows you to add classes to elements.
|
jQuery 的 `.addClass()` 方法用来给标签添加类。
|
||||||
|
|
||||||
First, let's target your `div` elements with the class `well` by using the `$(".well")` selector.
|
首先,使用 `$(".well")` 选取类为 `well` 的 `div` 标签。
|
||||||
|
|
||||||
Note that, just like with CSS declarations, you type a `.` before the class's name.
|
值得注意的是,和 CSS 声明一样,在类名前需要添加 `.`。
|
||||||
|
|
||||||
Then use jQuery's `.addClass()` function to add the classes `animated` and `shake`.
|
然后,用 jQuery 的 `.addClass()` 方法添加 `animated` 和 `shake` class。
|
||||||
|
|
||||||
For example, you could make all the elements with the class `text-primary` shake by adding the following to your `document ready function`:
|
例如,在 `document ready function` 中添加下面的代码,使所有类为 `text-primary` 的标签抖动:
|
||||||
|
|
||||||
`$(".text-primary").addClass("animated shake");`
|
`$(".text-primary").addClass("animated shake");`
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should use the jQuery `addClass()` function to give the classes `animated` and `shake` to all your elements with the class `well`.
|
应该用 jQuery 的 `addClass()` 方法给所有 class 为 `well` 的标签添加 `animated` 和 `shake` 类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('.well').hasClass('animated') && $('.well').hasClass('shake'));
|
assert($('.well').hasClass('animated') && $('.well').hasClass('shake'));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加 class。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class\.\*animated/g));
|
assert(!code.match(/class\.\*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aeda08826
|
id: bad87fee1348bd9aeda08826
|
||||||
title: Target Elements by id Using jQuery
|
title: 使用 jQuery id 选择器选择元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18317
|
forumTopicId: 18317
|
||||||
required:
|
required:
|
||||||
@ -11,27 +11,27 @@ dashedName: target-elements-by-id-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You can also target elements by their id attributes.
|
也能通过 id 属性选取标签。
|
||||||
|
|
||||||
First target your `button` element with the id `target3` by using the `$("#target3")` selector.
|
首先,用 `$("#target3")` 选择器选取 id 为 `target3` 的 `button` 标签。
|
||||||
|
|
||||||
Note that, just like with CSS declarations, you type a `#` before the id's name.
|
注意,和 CSS 声明一样,在 id 名前需要添加 `#`。
|
||||||
|
|
||||||
Then use jQuery's `.addClass()` function to add the classes `animated` and `fadeOut`.
|
然后,用 jQuery 的 `.addClass()` 方法添加 `animated` 和 `fadeOut` 类。
|
||||||
|
|
||||||
Here's how you'd make the `button` element with the id `target6` fade out:
|
下面的代码的效果是使 id 为 `target6` 的 `button` 标签淡出:
|
||||||
|
|
||||||
`$("#target6").addClass("animated fadeOut")`.
|
`$("#target6").addClass("animated fadeOut")`.
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should select the `button` element with the `id` of `target3` and use the jQuery `addClass()` function to give it the class of `animated`.
|
应该用 jQuery 的 `addClass()` 方法给 `id` 为 `target3` 的 `button` 标签添加 `animated` 类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#target3').hasClass('animated'));
|
assert($('#target3').hasClass('animated'));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should target the element with the id `target3` and use the jQuery `addClass()` function to give it the class `fadeOut`.
|
应该用 jQuery 的 `addClass()` 方法给 id 为 `target3` 的标签的类添加 `fadeOut` 类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签设置类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed008826
|
id: bad87fee1348bd9aed008826
|
||||||
title: Target Even Elements Using jQuery
|
title: 使用 jQuery 选择偶数元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18318
|
forumTopicId: 18318
|
||||||
required:
|
required:
|
||||||
@ -11,19 +11,19 @@ dashedName: target-even-elements-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You can also target elements based on their positions using `:odd` or `:even` selectors.
|
也可以用基于位置的奇 `:odd` 和偶 `:even` 选择器选取标签。
|
||||||
|
|
||||||
Note that jQuery is zero-indexed which means the first element in a selection has a position of 0. This can be a little confusing as, counter-intuitively, `:odd` selects the second element (position 1), fourth element (position 3), and so on.
|
注意,jQuery 是零索引(zero-indexed)的,这意味着第 1 个标签的位置编号是 0。 这有点混乱和反常——`:odd` 表示选择第 2 个标签(位置编号 1),第 4 个标签(位置编号 3)……等等,以此类推。
|
||||||
|
|
||||||
Here's how you would target all the odd elements with class `target` and give them classes:
|
下面的代码展示了选取所有 `target` class 元素的奇数元素并设置 sheke 效果:
|
||||||
|
|
||||||
`$(".target:odd").addClass("animated shake");`
|
`$(".target:odd").addClass("animated shake");`
|
||||||
|
|
||||||
Try selecting all the even `target` elements and giving them the classes of `animated` and `shake`. Remember that **even** refers to the position of elements with a zero-based system in mind.
|
尝试选取所有 `target` class 元素的偶数元素并给它们设置 `animated` 和 `shake` class。 要考虑到**偶(even)**指的是标签位置编号是从 0 开始的。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
All of the `target` elements that jQuery considers to be even should shake.
|
所有的 `target` 标签应该抖动。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,13 +31,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should use the `:even` selector to modify these elements.
|
应该用 `:even` 选择器修改这些标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\:even/g));
|
assert(code.match(/\:even/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9bedc08826
|
id: bad87fee1348bd9bedc08826
|
||||||
title: Target HTML Elements with Selectors Using jQuery
|
title: 使用 jQuery 选择器选择元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18319
|
forumTopicId: 18319
|
||||||
required:
|
required:
|
||||||
@ -11,33 +11,33 @@ dashedName: target-html-elements-with-selectors-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now we have a `document ready function`.
|
现在已经有了 `document ready function`。
|
||||||
|
|
||||||
Now let's write our first jQuery statement. All jQuery functions start with a `$`, usually referred to as a dollar sign operator, or as bling.
|
首先,完成第一个 jQuery 语句。 所有的 jQuery 函数都以 `$` 开头,这个符号通常被称为美元符号(dollar sign operator)或 bling。
|
||||||
|
|
||||||
jQuery often selects an HTML element with a <dfn>selector</dfn>, then does something to that element.
|
jQuery 通常选取并操作带有<dfn>选择器(selector)</dfn>的 HTML 标签。
|
||||||
|
|
||||||
For example, let's make all of your `button` elements bounce. Just add this code inside your document ready function:
|
比如,想要给 `button` 元素添加跳跃效果。 只需要在 document ready 函数内添加如下代码:
|
||||||
|
|
||||||
`$("button").addClass("animated bounce");`
|
`$("button").addClass("animated bounce");`
|
||||||
|
|
||||||
Note that we've already included both the jQuery library and the Animate.css library in the background so that you can use them in the editor. So you are using jQuery to apply the Animate.css `bounce` class to your `button` elements.
|
请注意,已经在后台引入了 jQuery 库和 Animate.css 库,所以可以在编辑器里直接使用 jQuery 和动画。 因此,只需要通过 jQuery 给 `button` 元素添加 `bounce` 类就可以了。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should use the jQuery `addClass()` function to give the classes `animated` and `bounce` to your `button` elements.
|
应该用 jQuery 的 `addClass()` 方法给 `button` 标签添加 `animated` 和 `bounce` 类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('button').hasClass('animated') && $('button').hasClass('bounce'));
|
assert($('button').hasClass('animated') && $('button').hasClass('bounce'));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加这些 class。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
Your jQuery code should be within the `$(document).ready();` function.
|
jQuery 代码应该放在 `$(document).ready();` 函数里。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed208826
|
id: bad87fee1348bd9aed208826
|
||||||
title: Target the Children of an Element Using jQuery
|
title: 使用 jQuery 选择元素的子元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18320
|
forumTopicId: 18320
|
||||||
dashedName: target-the-children-of-an-element-using-jquery
|
dashedName: target-the-children-of-an-element-using-jquery
|
||||||
@ -8,33 +8,33 @@ dashedName: target-the-children-of-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
When HTML elements are placed one level below another they are called <dfn>children</dfn> of that element. For example, the button elements in this challenge with the text "#target1", "#target2", and "#target3" are all children of the `<div class="well" id="left-well">` element.
|
把 HTML 标签放到另一个级别的标签里,这些 HTML 标签被称为该标签的<dfn>子标签(children element)</dfn>。 例如,本次挑战中文本为 `#target1`、`#target2` 和 `#target3` 的按钮都是 `<div class="well" id="left-well">` 标签的子标签。
|
||||||
|
|
||||||
jQuery has a function called `children()` that allows you to access the children of whichever element you've selected.
|
jQuery 有一个 `children()` 方法,可以访问被选取标签的子标签。
|
||||||
|
|
||||||
Here's an example of how you would use the `children()` function to give the children of your `left-well` element the color `blue`:
|
下面的代码展示了用 `children()` 方法把 `left-well` 标签的子标签的颜色设置成 `blue`(蓝色):
|
||||||
|
|
||||||
`$("#left-well").children().css("color", "blue")`
|
`$("#left-well").children().css("color", "blue")`
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Give all the children of your `right-well` element the color orange.
|
把 `right-well` 标签的所有子标签颜色设置成橙色(orange)。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
All children of `#right-well` should have orange text.
|
`#right-well` 所有的子标签文本应该是橙色。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#right-well').children().css('color') === 'rgb(255, 165, 0)');
|
assert($('#right-well').children().css('color') === 'rgb(255, 165, 0)');
|
||||||
```
|
```
|
||||||
|
|
||||||
You should use the `children()` function to modify these elements.
|
应该用 `children()` 方法修改标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\.children\(\)\.css/g));
|
assert(code.match(/\.children\(\)\.css/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/<div class="well" id="right-well">/g));
|
assert(code.match(/<div class="well" id="right-well">/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed308826
|
id: bad87fee1348bd9aed308826
|
||||||
title: Target the Parent of an Element Using jQuery
|
title: 使用 jQuery 选择元素的父元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18321
|
forumTopicId: 18321
|
||||||
dashedName: target-the-parent-of-an-element-using-jquery
|
dashedName: target-the-parent-of-an-element-using-jquery
|
||||||
@ -8,21 +8,21 @@ dashedName: target-the-parent-of-an-element-using-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Every HTML element has a `parent` element from which it `inherits` properties.
|
每个 HTML 标签都默认 `inherits`(继承)其 `parent`(父标签)的 CSS 属性。
|
||||||
|
|
||||||
For example, your `jQuery Playground` `h3` element has the parent element of `<div class="container-fluid">`, which itself has the parent `body`.
|
例如,`h3` 标签 `jQuery Playground` 的父标签是 `<div class="container-fluid">`,而这个标签的父标签是 `body`。
|
||||||
|
|
||||||
jQuery has a function called `parent()` that allows you to access the parent of whichever element you've selected.
|
jQuery 有一个 `parent()` 方法,可以访问被选取标签的父标签。
|
||||||
|
|
||||||
Here's an example of how you would use the `parent()` function if you wanted to give the parent element of the `left-well` element a background color of blue:
|
下面的代码展示了使用 `parent()` 方法把 `left-well` 标签的父标签背景色设置成蓝色(blue):
|
||||||
|
|
||||||
`$("#left-well").parent().css("background-color", "blue")`
|
`$("#left-well").parent().css("background-color", "blue")`
|
||||||
|
|
||||||
Give the parent of the `#target1` element a background-color of red.
|
把 `#target1` 标签的父标签背景色设置成红色(red)。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your `left-well` element should have a red background.
|
`left-well` 标签应该有红色的背景。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,13 +33,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should use the `.parent()` function to modify this element.
|
应该用 `.parent()` 方法修改该标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\.parent\s*\(\s*\)\s*\.css/g));
|
assert(code.match(/\.parent\s*\(\s*\)\s*\.css/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `.parent()` method should be called on the `#target1` element.
|
应该在 `#target1` 标签上调用 `.parent()` 方法。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -47,7 +47,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/<div class="well" id="left-well">/g));
|
assert(code.match(/<div class="well" id="left-well">/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed908626
|
id: bad87fee1348bd9aed908626
|
||||||
title: Target the Same Element with Multiple jQuery Selectors
|
title: 用多个 jQuery 选择器选择同一个元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18322
|
forumTopicId: 18322
|
||||||
required:
|
required:
|
||||||
@ -11,42 +11,41 @@ dashedName: target-the-same-element-with-multiple-jquery-selectors
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now you know three ways of targeting elements: by type: `$("button")`, by class: `$(".btn")`, and by id `$("#target1")`.
|
现在学写了三种选取标签的方法:用标签选择器: `$("button")`,用类选择器:`$(".btn")` 以及用 id 选择器:`$("#target1")` 。
|
||||||
|
|
||||||
Although it is possible to add multiple classes in a single `.addClass()` call, let's add them to the same element in *three separate ways*.
|
虽然可以在单个 `.addClass()` 内添加多个类,但是我们可以用*三种不同的方式*给一种标签添加类。
|
||||||
|
|
||||||
Using `.addClass()`, add only one class at a time to the same element, three different ways:
|
以三种不同的方式用 `.addClass()` 方法每次只给一种标签添加一个类:
|
||||||
|
|
||||||
Add the `animated` class to all elements with type `button`.
|
给所有的 `button` 标签添加 `animated` 类。
|
||||||
|
|
||||||
Add the `shake` class to all the buttons with class `.btn`.
|
给所有类为 `.btn` 的 button 标签添加 `shake` 类。
|
||||||
|
|
||||||
Add the `btn-primary` class to the button with id `#target1`.
|
给所有 id 为 `#target1` 的 button 标签添加 `btn-primary` 类。
|
||||||
|
|
||||||
**Note**
|
**注意:**只针对一个元素并且一次只能添加一个 class。 总之,三个选择器最终将添加三个 class `shake`、`animated` 以及 `btn-primary` 到 `#target1` 上。
|
||||||
You should only be targeting one element and adding only one class at a time. Altogether, your three individual selectors will end up adding the three classes `shake`, `animated`, and `btn-primary` to `#target1`.
|
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your code should use the `$("button")` selector.
|
应该使用 `$("button")` 选择器。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?button\s*?(?:'|")/gi));
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?button\s*?(?:'|")/gi));
|
||||||
```
|
```
|
||||||
|
|
||||||
Your code should use the `$(".btn")` selector.
|
应该使用 `$(".btn")` 选择器。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?\.btn\s*?(?:'|")/gi));
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?\.btn\s*?(?:'|")/gi));
|
||||||
```
|
```
|
||||||
|
|
||||||
Your code should use the `$("#target1")` selector.
|
应该使用 `$("#target1")` 选择器。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?#target1\s*?(?:'|")/gi));
|
assert(code.match(/\$\s*?\(\s*?(?:'|")\s*?#target1\s*?(?:'|")/gi));
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only add one class with each of your three selectors.
|
三个选择器每个应该只添加一个类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -55,7 +54,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Your `#target1` element should have the classes `animated`‚ `shake` and `btn-primary`.
|
`#target1` 标签应具有 `animated`、`shake` 和 `btn-primary` 三个类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -65,7 +64,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to add these classes to the element.
|
应该仅用 jQuery 给标签添加类。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aed608826
|
id: bad87fee1348bd9aed608826
|
||||||
title: Use appendTo to Move Elements with jQuery
|
title: 使用 jQuery 的 appendTo 方法移动元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18340
|
forumTopicId: 18340
|
||||||
dashedName: use-appendto-to-move-elements-with-jquery
|
dashedName: use-appendto-to-move-elements-with-jquery
|
||||||
@ -8,31 +8,31 @@ dashedName: use-appendto-to-move-elements-with-jquery
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now let's try moving elements from one `div` to another.
|
现在来把标签从一个 `div` 移动到另一个里。
|
||||||
|
|
||||||
jQuery has a function called `appendTo()` that allows you to select HTML elements and append them to another element.
|
jQuery 有一个 `appendTo()` 方法,可以选取 HTML 标签并将其添加到另一个标签里面。
|
||||||
|
|
||||||
For example, if we wanted to move `target4` from our right well to our left well, we would use:
|
例如,如果要把 `target4` 从 right well 移到 left well,可以设置如下:
|
||||||
|
|
||||||
`$("#target4").appendTo("#left-well");`
|
`$("#target4").appendTo("#left-well");`
|
||||||
|
|
||||||
Move your `target2` element from your `left-well` to your `right-well`.
|
把 `target2` 标签从 `left-well` 移动到 `right-well`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Your `target2` element should not be inside your `left-well`.
|
`target2` 标签不应该在 `left-well` 内。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#left-well').children('#target2').length === 0);
|
assert($('#left-well').children('#target2').length === 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
Your `target2` element should be inside your `right-well`.
|
`target2` 标签应该在 `right-well` 内。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('#right-well').children('#target2').length > 0);
|
assert($('#right-well').children('#target2').length > 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
You should only use jQuery to move these elements.
|
应该仅用 jQuery 移动这些标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!code.match(/class.*animated/g));
|
assert(!code.match(/class.*animated/g));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: bad87fee1348bd9aecb08826
|
id: bad87fee1348bd9aecb08826
|
||||||
title: Use jQuery to Modify the Entire Page
|
title: 使用 jQuery 修改整个页面
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 18361
|
forumTopicId: 18361
|
||||||
required:
|
required:
|
||||||
@ -11,17 +11,17 @@ dashedName: use-jquery-to-modify-the-entire-page
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
We're done playing with our jQuery playground. Let's tear it down!
|
目前,已经完成了 jQuery playground。 把它移除吧。
|
||||||
|
|
||||||
jQuery can target the `body` element as well.
|
jQuery 也能选取 `body` 标签。
|
||||||
|
|
||||||
Here's how we would make the entire body fade out: `$("body").addClass("animated fadeOut");`
|
这是使整个 body 淡出的代码:`$("body").addClass("animated fadeOut");`
|
||||||
|
|
||||||
But let's do something more dramatic. Add the classes `animated` and `hinge` to your `body` element.
|
来做一些更好玩的事。 给 `body` 标签添加 `animated` 和 `hinge` class。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
You should add the classes `animated` and `hinge` to your `body` element.
|
应该给 `body` 标签添加 `animated` 和 `hinge` class。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert($('body').hasClass('animated') && $('body').hasClass('hinge'));
|
assert($('body').hasClass('animated') && $('body').hasClass('hinge'));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036147
|
id: 5a24c314108439a4d4036147
|
||||||
title: Connect Redux to React
|
title: 连接 Redux 和 React
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301426
|
forumTopicId: 301426
|
||||||
dashedName: connect-redux-to-react
|
dashedName: connect-redux-to-react
|
||||||
@ -8,21 +8,21 @@ dashedName: connect-redux-to-react
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now that you've written both the `mapStateToProps()` and the `mapDispatchToProps()` functions, you can use them to map `state` and `dispatch` to the `props` of one of your React components. The `connect` method from React Redux can handle this task. This method takes two optional arguments, `mapStateToProps()` and `mapDispatchToProps()`. They are optional because you may have a component that only needs access to `state` but doesn't need to dispatch any actions, or vice versa.
|
你已经写了`mapStateToProps()`、`mapDispatchToProps()` 两个函数,现在可以用它们来把 `state` 和 `dispatch` 映射到 React 组件的 `props` 了。 React Redux 的 `connect` 方法可以完成这个任务。 此方法有 `mapStateToProps()`、`mapDispatchToProps()` 两个可选参数, 它们是可选的,原因是你的组件可能仅需要访问 `state` 但不需要分发任何 actions,反之亦然。
|
||||||
|
|
||||||
To use this method, pass in the functions as arguments, and immediately call the result with your component. This syntax is a little unusual and looks like:
|
为了使用此方法,需要传入函数参数并在调用时传入组件。 这种语法有些不寻常,如下所示:
|
||||||
|
|
||||||
`connect(mapStateToProps, mapDispatchToProps)(MyComponent)`
|
`connect(mapStateToProps, mapDispatchToProps)(MyComponent)`
|
||||||
|
|
||||||
**Note:** If you want to omit one of the arguments to the `connect` method, you pass `null` in its place.
|
**注意:** 如果要省略 `connect` 方法中的某个参数,则应当用 `null` 替换这个参数。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has the `mapStateToProps()` and `mapDispatchToProps()` functions and a new React component called `Presentational`. Connect this component to Redux with the `connect` method from the `ReactRedux` global object, and call it immediately on the `Presentational` component. Assign the result to a new `const` called `ConnectedComponent` that represents the connected component. That's it, now you're connected to Redux! Try changing either of `connect`'s arguments to `null` and observe the test results.
|
在编辑器上有两个函数:`mapStateToProps()`、`mapDispatchToProps()`,还有一个叫 `Presentational` 的 React 组件。 用 `ReactRedux` 全局对象中的 `connect` 方法将此组件连接到 Redux,并立即在 `Presentational` 组件中调用, 把结果赋值给一个名为 `ConnectedComponent` 的代表已连接组件的新 `const`。 大功告成,已成功把 React 连接到 Redux! 尝试更改任何一个 `connect` 参数为 `null` 并观察测试结果。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `Presentational` component should render.
|
应渲染 `Presentational` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,7 +33,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive a prop `messages` via `connect`.
|
`Presentational` 组件应通过 `connect` 接收一个 `messages` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -45,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive a prop `submitNewMessage` via `connect`.
|
`Presentational` 组件应通过 `connect` 接收一个 `submitNewMessage` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036148
|
id: 5a24c314108439a4d4036148
|
||||||
title: Connect Redux to the Messages App
|
title: 将 Redux 连接到 Messages App
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301427
|
forumTopicId: 301427
|
||||||
dashedName: connect-redux-to-the-messages-app
|
dashedName: connect-redux-to-the-messages-app
|
||||||
@ -8,17 +8,17 @@ dashedName: connect-redux-to-the-messages-app
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now that you understand how to use `connect` to connect React to Redux, you can apply what you've learned to your React component that handles messages.
|
知道如何使用 `connect` 连接 React 和 Redux 后,我们可以在 React 组件中应用上面学到的内容。
|
||||||
|
|
||||||
In the last lesson, the component you connected to Redux was named `Presentational`, and this wasn't arbitrary. This term *generally* refers to React components that are not directly connected to Redux. They are simply responsible for the presentation of UI and do this as a function of the props they receive. By contrast, container components are connected to Redux. These are typically responsible for dispatching actions to the store and often pass store state to child components as props.
|
在上一课,连接到 Redux 的组件命名为 `Presentational`,这个命名不是任意的, 这样的术语*通常*是指未直接连接到 Redux 的 React 组件, 它们只负责执行接收 props 的函数来实现 UI 的呈现。 相比之下,容器组件用来连接到 Redux 上。 这些组件通常负责把 actions 分派给 store,且经常给子组件传入 store state 属性。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has all the code you've written in this section so far. The only change is that the React component is renamed to `Presentational`. Create a new component held in a constant called `Container` that uses `connect` to connect the `Presentational` component to Redux. Then, in the `AppWrapper`, render the React Redux `Provider` component. Pass `Provider` the Redux `store` as a prop and render `Container` as a child. Once everything is setup, you will see the messages app rendered to the page again.
|
到目前为止,我们的编辑器上已包含了整个章节的代码, 唯一不同的是,React 组件被重新命名为 `Presentational`,即展示层组件。 创建一个新组件,保存在名为 `Container` 的常量中。 这个常量用 `connect` 把 `Presentational` 组件和 Redux 连接起来。 然后,在`AppWrapper` 中渲染 React Redux 的 `Provider`组件, 给 `Provider` 传入 Redux `store` 属性并渲染 `Container` 为子组件。 设置完所有内容后,将再次看到消息应用程序渲染到页面上。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `AppWrapper` should render to the page.
|
`AppWrapper` 应渲染该页面上。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should render to page.
|
`Presentational` 组件应该渲染到页面上。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should render an `h2`, `input`, `button`, and `ul` elements.
|
`Presentational` 组件应渲染 `h2`、`input`、`button`、`ul` 四个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -57,7 +57,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive `messages` from the Redux store as a prop.
|
`Presentational` 组件应接收 Redux store 的 `messages` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -70,7 +70,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive the `submitMessage` action creator as a prop.
|
`Presentational` 组件应接收创建 action 的函数 `submitMessage` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036149
|
id: 5a24c314108439a4d4036149
|
||||||
title: Extract Local State into Redux
|
title: 将局部状态提取到 Redux 中
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301428
|
forumTopicId: 301428
|
||||||
dashedName: extract-local-state-into-redux
|
dashedName: extract-local-state-into-redux
|
||||||
@ -8,17 +8,17 @@ dashedName: extract-local-state-into-redux
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You're almost done! Recall that you wrote all the Redux code so that Redux could control the state management of your React messages app. Now that Redux is connected, you need to extract the state management out of the `Presentational` component and into Redux. Currently, you have Redux connected, but you are handling the state locally within the `Presentational` component.
|
马上就完成了! 请回顾一下为管理 React messages app 的状态写的 Redux 代码。 现在有了连接好的 Redux,还要从`Presentational`组件中提取状态管理到 Redux, 目前,已连接 Redux,但正在 `Presentational` 组件中本地处理状态。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the `Presentational` component, first, remove the `messages` property in the local `state`. These messages will be managed by Redux. Next, modify the `submitMessage()` method so that it dispatches `submitNewMessage()` from `this.props`, and pass in the current message input from local `state` as an argument. Because you removed `messages` from local state, remove the `messages` property from the call to `this.setState()` here as well. Finally, modify the `render()` method so that it maps over the messages received from `props` rather than `state`.
|
在 `Presentational` 组件中,先删除本地 `state` 中的 `messages` 属性, 被删的 messages 将由 Redux 管理。 接着,修改 `submitMessage()` 方法,使该方法从 `this.props` 那里分发 `submitNewMessage()`;从本地 `state` 中传入当前消息输入作为参数。 因本地状态删除了 `messages` 属性,所以在调用 `this.setState()` 时也要删除 `messages` 属性。 最后,修改 `render()` 方法,使其所映射的消息是从 `props` 接收的,而不是 `state`
|
||||||
|
|
||||||
Once these changes are made, the app will continue to function the same, except Redux manages the state. This example also illustrates how a component may have local `state`: your component still tracks user input locally in its own `state`. You can see how Redux provides a useful state management framework on top of React. You achieved the same result using only React's local state at first, and this is usually possible with simple apps. However, as your apps become larger and more complex, so does your state management, and this is the problem Redux solves.
|
完成这些更改后,我们的应用会实现 Redux 管理应用的状态,但它继续运行着相同的功能。 此示例还阐明了组件获得本地 `state` 的方式,即在自己的 `state` 中继续跟踪用户本地输入。 由此可见,Redux 为 React 提供了很有用的状态管理框架。 先前,仅使用 React 的本地状态也实现了相同的结果,这在应付简单的应用时通常是可行的。 但是,随着应用变得越来越大,越来越复杂,应用的状态管理也变得非常困难,Redux 就是为解决这样的问题而诞生的。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `AppWrapper` should render to the page.
|
`AppWrapper` 应该渲染该到页面上。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should render to page.
|
`Presentational` 应该渲染到页面上.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should render an `h2`, `input`, `button`, and `ul` elements.
|
`Presentational` 组件应渲染 `h2`、`input`、`button`、`ul` 四个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -57,7 +57,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive `messages` from the Redux store as a prop.
|
`Presentational` 组件应接收 Redux store 的 `messages` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -70,7 +70,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should receive the `submitMessage` action creator as a prop.
|
`Presentational` 组件应接收创建 action 的函数的 `submitMessage` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -83,7 +83,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of the `Presentational` component should contain one property, `input`, which is initialized to an empty string.
|
`Presentational` 组件的状态应包含一个初始化为空字符串的 `input` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -100,7 +100,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Typing in the `input` element should update the state of the `Presentational` component.
|
键入 `input` 元素应更新 `Presentational` 组件的状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -124,7 +124,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching the `submitMessage` on the `Presentational` component should update Redux store and clear the input in local state.
|
在 `Presentational` 组件上 dispatch `submitMessage` 应更新 Redux store 并清除本地状态中的输入。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -156,7 +156,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Presentational` component should render the `messages` from the Redux store.
|
`Presentational` 组件应渲染 Redux store 中的 `messages`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036143
|
id: 5a24c314108439a4d4036143
|
||||||
title: Extract State Logic to Redux
|
title: 提取状态逻辑给 Redux
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301429
|
forumTopicId: 301429
|
||||||
dashedName: extract-state-logic-to-redux
|
dashedName: extract-state-logic-to-redux
|
||||||
@ -8,23 +8,23 @@ dashedName: extract-state-logic-to-redux
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now that you finished the React component, you need to move the logic it's performing locally in its `state` into Redux. This is the first step to connect the simple React app to Redux. The only functionality your app has is to add new messages from the user to an unordered list. The example is simple in order to demonstrate how React and Redux work together.
|
完成 React 组件后,我们需要把在本地 `state` 执行的逻辑移到 Redux 中, 这是为小规模 React 应用添加 Redux 的第一步。 该应用的唯一功能是把用户的新消息添加到无序列表中。 下面我们用简单的示例来演示 React 和 Redux 之间的配合。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
First, define an action type 'ADD' and set it to a const `ADD`. Next, define an action creator `addMessage()` which creates the action to add a message. You'll need to pass a `message` to this action creator and include the message in the returned `action`.
|
首先,定义 action 的类型 `ADD`,将其设置为常量 `ADD`。 接着,定义创建 action 的函数`addMessage()`,用该函数创建添加消息的 action, 把 `message` 传给创建 action 的函数并返回包含该消息的 `action`
|
||||||
|
|
||||||
Then create a reducer called `messageReducer()` that handles the state for the messages. The initial state should equal an empty array. This reducer should add a message to the array of messages held in state, or return the current state. Finally, create your Redux store and pass it the reducer.
|
接着,创建名为 `messageReducer()` 的 reducer 方法,为这些消息处理状态。 初始状态应为空数组。 reducer 向状态中的消息数组添加消息,或返回当前状态。 最后,创建 Redux store 并传给 reducer。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The const `ADD` should exist and hold a value equal to the string `ADD`
|
应存在一个值为字符串 `ADD` 的常量 `ADD`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(ADD === 'ADD');
|
assert(ADD === 'ADD');
|
||||||
```
|
```
|
||||||
|
|
||||||
The action creator `addMessage` should return an object with `type` equal to `ADD` and `message` equal to the message that is passed in.
|
创建 action 的函数 `addMessage` 应返回 `type` 等于 `ADD` 的对象,其返回的 `message` 即被传入的消息。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -35,13 +35,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`messageReducer` should be a function.
|
`messageReducer` 应是一个函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof messageReducer === 'function');
|
assert(typeof messageReducer === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
The store should exist and have an initial state set to an empty array.
|
存在一个 store 且其初始状态为空数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -52,7 +52,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching `addMessage` against the store should immutably add a new message to the array of messages held in state.
|
分发 `addMessage` 到 store 应添加新消息到状态中消息数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -66,7 +66,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `messageReducer` should return the current state if called with any other actions.
|
`messageReducer` 被其它任何 actions 调用时应返回当前状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036141
|
id: 5a24c314108439a4d4036141
|
||||||
title: Getting Started with React Redux
|
title: React 和 Redux 入门
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301430
|
forumTopicId: 301430
|
||||||
dashedName: getting-started-with-react-redux
|
dashedName: getting-started-with-react-redux
|
||||||
@ -8,19 +8,19 @@ dashedName: getting-started-with-react-redux
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
This series of challenges introduces how to use Redux with React. First, here's a review of some of the key principles of each technology. React is a view library that you provide with data, then it renders the view in an efficient, predictable way. Redux is a state management framework that you can use to simplify the management of your application's state. Typically, in a React Redux app, you create a single Redux store that manages the state of your entire app. Your React components subscribe to only the pieces of data in the store that are relevant to their role. Then, you dispatch actions directly from React components, which then trigger store updates.
|
这一系列挑战介绍的是 Redux 和 React 的配合, 我们先来回顾一下这两种技术的关键原则是什么。 React 是提供数据的视图库,能以高效、可预测的方式渲染视图。 Redux 是状态管理框架,可用于简化 APP 应用状态的管理。 在 React Redux app 应用中,通常可创建单一的 Redux store 来管理整个应用的状态。 React 组件仅订阅 store 中与其角色相关的数据, 可直接从 React 组件中分发 actions 以触发 store 对象的更新。
|
||||||
|
|
||||||
Although React components can manage their own state locally, when you have a complex app, it's generally better to keep the app state in a single location with Redux. There are exceptions when individual components may have local state specific only to them. Finally, because Redux is not designed to work with React out of the box, you need to use the `react-redux` package. It provides a way for you to pass Redux `state` and `dispatch` to your React components as `props`.
|
React 组件可以在本地管理自己的状态,但是对于复杂的应用来说,它的状态最好是用 Redux 保存在单一位置,有特定本地状态的独立组件例外。 当单个组件可能仅具有特定于其的本地状态时,算是例外。 最后一点是,Redux 没有内置的 React 支持,需要安装 `react-redux`包, 通过这个方式把 Redux 的 `state` 和 `dispatch` 作为 `props` 传给组件。
|
||||||
|
|
||||||
Over the next few challenges, first, you'll create a simple React component which allows you to input new text messages. These are added to an array that's displayed in the view. This should be a nice review of what you learned in the React lessons. Next, you'll create a Redux store and actions that manage the state of the messages array. Finally, you'll use `react-redux` to connect the Redux store with your component, thereby extracting the local state into the Redux store.
|
在接下来的挑战中,先要创建一个可输入新文本消息的 React 组件, 添加这些消息到数组里,在视图上显示数组。 这应该是 React 课程中的一个很好的回顾。 接着,创建 Redux store 和 actions 来管理消息数组的状态。 最后,使用 `react-redux` 连接 Redux store 和组件,从而将本地状态提取到 Redux store 中。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Start with a `DisplayMessages` component. Add a constructor to this component and initialize it with a state that has two properties: `input`, that's set to an empty string, and `messages`, that's set to an empty array.
|
从 `DisplayMessages` 组件开始。 把构造函数添加到此组件中,使用含两个属性的状态初始化该组件,这两个属性为:`input`(设置为空字符串),`messages`(设置为空数组)。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `DisplayMessages` component should render an empty `div` element.
|
`DisplayMessages` 组件应渲染空的 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,7 +31,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `DisplayMessages` constructor should be called properly with `super`, passing in `props`.
|
`DisplayMessages` 组件的构造函数应调用 `super`,传入 `props`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
@ -46,7 +46,7 @@ The `DisplayMessages` constructor should be called properly with `super`, passin
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `DisplayMessages` component should have an initial state equal to `{input: "", messages: []}`.
|
`DisplayMessages` 组件的初始状态应是 `{input: "", messages: []}`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036142
|
id: 5a24c314108439a4d4036142
|
||||||
title: Manage State Locally First
|
title: 首先在本地管理状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301431
|
forumTopicId: 301431
|
||||||
dashedName: manage-state-locally-first
|
dashedName: manage-state-locally-first
|
||||||
@ -8,19 +8,19 @@ dashedName: manage-state-locally-first
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Here you'll finish creating the `DisplayMessages` component.
|
这一关的任务是完成 `DisplayMessages` 组件的创建。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
First, in the `render()` method, have the component render an `input` element, `button` element, and `ul` element. When the `input` element changes, it should trigger a `handleChange()` method. Also, the `input` element should render the value of `input` that's in the component's state. The `button` element should trigger a `submitMessage()` method when it's clicked.
|
首先,在 `render()` 方法中,让组件渲染 `input`、`button`、`ul` 三个元素。 `input` 元素的改变会触发 `handleChange()` 方法。 此外,`input` 元素会渲染组件状态中 `input` 的值。 点击按钮 `button` 需触发 `submitMessage()` 方法。
|
||||||
|
|
||||||
Second, write these two methods. The `handleChange()` method should update the `input` with what the user is typing. The `submitMessage()` method should concatenate the current message (stored in `input`) to the `messages` array in local state, and clear the value of the `input`.
|
接着,写出这两种方法。 `handleChange()` 方法会更新 `input` 为用户正在输入的内容。 `submitMessage()` 方法把当前存储在 `input` 的消息与本地状态的 `messages` 数组连接起来,并清除 `input` 的值。
|
||||||
|
|
||||||
Finally, use the `ul` to map over the array of `messages` and render it to the screen as a list of `li` elements.
|
最后,在 `ul` 中展示 `messages` 数组,其中每个元素内容需放到 `li` 元素内。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `DisplayMessages` component should initialize with a state equal to `{ input: "", messages: [] }`.
|
`DisplayMessages` 组件的初始状态应是 `{ input: "", messages: [] }`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -36,7 +36,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `DisplayMessages` component should render a `div` containing an `h2` element, a `button` element, a `ul` element, and `li` elements as children.
|
`DisplayMessages` 组件应渲染含 `h2`、`button`、`ul`、`li` 四个子元素的`div`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -58,13 +58,13 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`.map` should be used on the `messages` array.
|
`.map` 应该用于 `messages` 数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(code.match(/this\.state\.messages\.map/g));
|
assert(code.match(/this\.state\.messages\.map/g));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `input` element should render the value of `input` in local state.
|
`input` 元素应渲染本地状态中的 `input` 值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -83,7 +83,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Calling the method `handleChange` should update the `input` value in state to the current input.
|
调用 `handleChange` 方法时应更新状态中的 `input` 值为当前输入。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -106,7 +106,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the `Add message` button should call the method `submitMessage` which should add the current `input` to the `messages` array in state.
|
单击 `Add message` 按钮应调用 `submitMessage` 方法,添加当前 `input` 到状态中的 `messages` 数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -149,7 +149,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The `submitMessage` method should clear the current input.
|
`submitMessage` 方法应清除当前输入。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036146
|
id: 5a24c314108439a4d4036146
|
||||||
title: Map Dispatch to Props
|
title: 映射 Dispatch 到 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301432
|
forumTopicId: 301432
|
||||||
dashedName: map-dispatch-to-props
|
dashedName: map-dispatch-to-props
|
||||||
@ -8,9 +8,9 @@ dashedName: map-dispatch-to-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The `mapDispatchToProps()` function is used to provide specific action creators to your React components so they can dispatch actions against the Redux store. It's similar in structure to the `mapStateToProps()` function you wrote in the last challenge. It returns an object that maps dispatch actions to property names, which become component `props`. However, instead of returning a piece of `state`, each property returns a function that calls `dispatch` with an action creator and any relevant action data. You have access to this `dispatch` because it's passed in to `mapDispatchToProps()` as a parameter when you define the function, just like you passed `state` to `mapStateToProps()`. Behind the scenes, React Redux is using Redux's `store.dispatch()` to conduct these dispatches with `mapDispatchToProps()`. This is similar to how it uses `store.subscribe()` for components that are mapped to `state`.
|
`mapDispatchToProps()` 函数可为 React 组件提供特定的创建 action 的函数,以便组件可 dispatch actions,从而更改 Redux store 中的数据。 该函数的结构跟上一挑战中的`mapStateToProps()`函数相似, 它返回一个对象,把 dispatch actions 映射到属性名上,该属性名成为`props`。 然而,每个属性都返回一个用 action creator 及与 action 相关的所有数据调用 `dispatch` 的函数,而不是返回 `state` 的一部分。 可以访问 `dispatch`,因为在定义函数时,我们以参数形式把它传入 `mapDispatchToProps()` 了,这跟 `state` 传入 `mapStateToProps()` 是一样的。 在幕后,React Redux 用 Redux 的 `store.dispatch()` 来管理这些含 `mapDispatchToProps()` 的dispatches, 这跟它使用 `store.subscribe()` 来订阅映射到 `state` 的组件的方式类似。
|
||||||
|
|
||||||
For example, you have a `loginUser()` action creator that takes a `username` as an action payload. The object returned from `mapDispatchToProps()` for this action creator would look something like:
|
例如,创建 action 的函数 `loginUser()` 把 `username` 作为 action payload, `mapDispatchToProps()` 返回给创建 action 的函数的对象如下:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
{
|
{
|
||||||
@ -22,11 +22,11 @@ For example, you have a `loginUser()` action creator that takes a `username` as
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor provides an action creator called `addMessage()`. Write the function `mapDispatchToProps()` that takes `dispatch` as an argument, then returns an object. The object should have a property `submitNewMessage` set to the dispatch function, which takes a parameter for the new message to add when it dispatches `addMessage()`.
|
编辑器上提供的是创建 action 的函数 `addMessage()`。 写出接收 `dispatch` 为参数的函数 `mapDispatchToProps()`,返回一个 dispatch 函数对象, 其属性为 `submitNewMessage`。该函数在 dispatch `addMessage()` 时为新消息提供一个参数。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`addMessage` should return an object with keys `type` and `message`.
|
`addMessage` 应返回含 `type` 和 `message` 两个键的对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,19 +40,19 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`mapDispatchToProps` should be a function.
|
`mapDispatchToProps` 应为函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof mapDispatchToProps === 'function');
|
assert(typeof mapDispatchToProps === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
`mapDispatchToProps` should return an object.
|
`mapDispatchToProps` 应返回一个对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof mapDispatchToProps() === 'object');
|
assert(typeof mapDispatchToProps() === 'object');
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching `addMessage` with `submitNewMessage` from `mapDispatchToProps` should return a message to the dispatch function.
|
从 `mapDispatchToProps` 通过 `submitNewMessage` 分发 `addMessage`,应向 dispatch 函数返回一条消息。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036145
|
id: 5a24c314108439a4d4036145
|
||||||
title: Map State to Props
|
title: 映射 State 到 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301433
|
forumTopicId: 301433
|
||||||
dashedName: map-state-to-props
|
dashedName: map-state-to-props
|
||||||
@ -8,37 +8,37 @@ dashedName: map-state-to-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The `Provider` component allows you to provide `state` and `dispatch` to your React components, but you must specify exactly what state and actions you want. This way, you make sure that each component only has access to the state it needs. You accomplish this by creating two functions: `mapStateToProps()` and `mapDispatchToProps()`.
|
`Provider`可向 React 组件提供 `state` 和 `dispatch` ,但必须确切地指定所需要的 state 和 actions, 以确保每个组件只能访问所需的 state。 完成这个任务,需要创建两个函数:`mapStateToProps()`、`mapDispatchToProps()`。
|
||||||
|
|
||||||
In these functions, you declare what pieces of state you want to have access to and which action creators you need to be able to dispatch. Once these functions are in place, you'll see how to use the React Redux `connect` method to connect them to your components in another challenge.
|
在这两个函数中,声明 state 中函数所要访问的部分及需要 dispatch 的创建 action 的函数。 完成这些,我们就可以迎接下一个挑战,学习如何使用 React Redux 的 `connect` 方法来把函数连接到组件了。
|
||||||
|
|
||||||
**Note:** Behind the scenes, React Redux uses the `store.subscribe()` method to implement `mapStateToProps()`.
|
**注意:** 在幕后,React Redux 用 `store.subscribe()` 方法来实现 `mapStateToProps()`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Create a function `mapStateToProps()`. This function should take `state` as an argument, then return an object which maps that state to specific property names. These properties will become accessible to your component via `props`. Since this example keeps the entire state of the app in a single array, you can pass that entire state to your component. Create a property `messages` in the object that's being returned, and set it to `state`.
|
创建 `mapStateToProps()` 函数, 以 `state` 为参数,然后返回一个对象,该对象把 state 映射到特定属性名上, 这些属性能通过 `props` 访问组件。 由于此示例把 app 应用的整个状态保存在单一数组中,可把整个状态传给组件。 在返回的对象中创建 `messages` 属性,并设置为 `state`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The const `state` should be an empty array.
|
常量 `state` 应为空数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Array.isArray(state) && state.length === 0);
|
assert(Array.isArray(state) && state.length === 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
`mapStateToProps` should be a function.
|
`mapStateToProps` 应为函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof mapStateToProps === 'function');
|
assert(typeof mapStateToProps === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
`mapStateToProps` should return an object.
|
`mapStateToProps` 应返回一个对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof mapStateToProps() === 'object');
|
assert(typeof mapStateToProps() === 'object');
|
||||||
```
|
```
|
||||||
|
|
||||||
Passing an array as state to `mapStateToProps` should return this array assigned to a key of `messages`.
|
把 state 数组传入 `mapStateToProps` 后应返回赋值给 `messages` 键的数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(mapStateToProps(['messages']).messages.pop() === 'messages');
|
assert(mapStateToProps(['messages']).messages.pop() === 'messages');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614a
|
id: 5a24c314108439a4d403614a
|
||||||
title: Moving Forward From Here
|
title: 从这里前进
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301434
|
forumTopicId: 301434
|
||||||
dashedName: moving-forward-from-here
|
dashedName: moving-forward-from-here
|
||||||
@ -8,21 +8,21 @@ dashedName: moving-forward-from-here
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Congratulations! You finished the lessons on React and Redux. There's one last item worth pointing out before you move on. Typically, you won't write React apps in a code editor like this. This challenge gives you a glimpse of what the syntax looks like if you're working with npm and a file system on your own machine. The code should look similar, except for the use of `import` statements (these pull in all of the dependencies that have been provided for you in the challenges). The "Managing Packages with npm" section covers npm in more detail.
|
恭喜! 你完成了 React 和 Redux 的所有课程! 结束之前,还要再提一点。 通常,我们不会在这样的编辑器中编写 React 应用代码。 如果你在自己的计算机上使用 npm 和文件系统,这个挑战可让你一瞥 React 应用的语法之貌。 除了使用 `import` 语句(这些语句引入了各挑战中提供的所有依赖关系),其代码看起来类似。 “管理包(含 npm)”这一节更详细地介绍了 npm。
|
||||||
|
|
||||||
Finally, writing React and Redux code generally requires some configuration. This can get complicated quickly. If you are interested in experimenting on your own machine, the
|
最后,写 React 和 Redux 的代码通常需要一些配置, 且很快会变得复杂起来。 如果你有兴趣在自己的计算机上试试,
|
||||||
|
|
||||||
[Create React App](https://github.com/facebookincubator/create-react-app) comes configured and ready to go.
|
[Create React App](https://github.com/facebookincubator/create-react-app) 可获取已配置好的现成代码。
|
||||||
|
|
||||||
Alternatively, you can enable Babel as a JavaScript Preprocessor in CodePen, add React and ReactDOM as external JavaScript resources, and work there as well.
|
另一种做法是在 CodePen 中启用 Babel 作为 JavaScript 预处理器,将 React 和 ReactDOM 添加为外部 JavaScript 资源,在那里编写应用。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Log the message `'Now I know React and Redux!'` to the console.
|
把 `'Now I know React and Redux!'` 这一消息输出到控制台。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The message `Now I know React and Redux!` should be logged to the console.
|
应该将 `Now I know React and Redux!` 这一消息应输出到控制台。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036144
|
id: 5a24c314108439a4d4036144
|
||||||
title: Use Provider to Connect Redux to React
|
title: 使用 Provider 连接 Redux 和 React
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301435
|
forumTopicId: 301435
|
||||||
dashedName: use-provider-to-connect-redux-to-react
|
dashedName: use-provider-to-connect-redux-to-react
|
||||||
@ -8,9 +8,9 @@ dashedName: use-provider-to-connect-redux-to-react
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
In the last challenge, you created a Redux store to handle the messages array and created an action for adding new messages. The next step is to provide React access to the Redux store and the actions it needs to dispatch updates. React Redux provides its `react-redux` package to help accomplish these tasks.
|
在上一挑战中,创建了 Redux store 和 action,分别用于处理消息数组和添加新消息。 下一步要为 React 提供访问 Redux store 及发起更新所需的 actions。 `react-redux` 包可帮助我们完成这些任务。
|
||||||
|
|
||||||
React Redux provides a small API with two key features: `Provider` and `connect`. Another challenge covers `connect`. The `Provider` is a wrapper component from React Redux that wraps your React app. This wrapper then allows you to access the Redux `store` and `dispatch` functions throughout your component tree. `Provider` takes two props, the Redux store and the child components of your app. Defining the `Provider` for an App component might look like this:
|
React Redux 提供的 API 有两个关键的功能:`Provider` 和 `connect`。 会在另一个挑战会介绍 `connect`。 `Provider`是 React Redux 包装 React 应用的 wrapper 组件, 它允许访问整个组件树中的 Redux `store` 及 `dispatch`(分发)方法。 `Provider` 需要两个 props:Redux store 和 App 应用的子组件。 用于 App 组件的 `Provider` 可这样定义:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
@ -20,13 +20,13 @@ React Redux provides a small API with two key features: `Provider` and `connect`
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor now shows all your Redux and React code from the past several challenges. It includes the Redux store, actions, and the `DisplayMessages` component. The only new piece is the `AppWrapper` component at the bottom. Use this top level component to render the `Provider` from `ReactRedux`, and pass the Redux store as a prop. Then render the `DisplayMessages` component as a child. Once you are finished, you should see your React component rendered to the page.
|
此时,编辑器上显示的是过去几个挑战中所有代码, 包括 Redux store、actions、`DisplayMessages` 组件。 新出现的代码是底部的`AppWrapper`组件, 这个顶级组件可用于渲染 `ReactRedux` 的 `Provider`,并把 Redux 的 store 作为 props 传入。 接着,渲染 `DisplayMessages` 为子组件。 完成这些任务后,会看到 React 组件渲染到页面上。
|
||||||
|
|
||||||
**Note:** React Redux is available as a global variable here, so you can access the Provider with dot notation. The code in the editor takes advantage of this and sets it to a constant `Provider` for you to use in the `AppWrapper` render method.
|
**注意:** React Redux 在此可作全局变量,因此可通过点号表示法访问 Provider。 利用这一点,编辑器上的代码把 `Provider` 设置为常量,便于你在 `AppWrapper` 渲染方法中使用。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `AppWrapper` should render.
|
`AppWrapper` 应渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -37,7 +37,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Provider` wrapper component should have a prop of `store` passed to it, equal to the Redux store.
|
`Provider` 组件应传入相当于 Redux store 的 `store` 参数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
@ -51,7 +51,7 @@ The `Provider` wrapper component should have a prop of `store` passed to it, equ
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`DisplayMessages` should render as a child of `AppWrapper`.
|
`DisplayMessages` 应渲染为 `AppWrapper` 的子组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -64,7 +64,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `DisplayMessages` component should render an h2, input, button, and `ul` element.
|
`DisplayMessages` 组件应渲染 `h2`、`input`、`button`、`ul` 四个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616e
|
id: 5a24c314108439a4d403616e
|
||||||
title: Access Props Using this.props
|
title: 使用 this.props 访问 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301375
|
forumTopicId: 301375
|
||||||
dashedName: access-props-using-this-props
|
dashedName: access-props-using-this-props
|
||||||
@ -8,17 +8,17 @@ dashedName: access-props-using-this-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last several challenges covered the basic ways to pass props to child components. But what if the child component that you're passing a prop to is an ES6 class component, rather than a stateless functional component? The ES6 class component uses a slightly different convention to access props.
|
前几项挑战涵盖了将 props 传递给子组件的基本方法。 但是,倘若接收 prop 的子组件不是无状态函数组件,而是一个 ES6 类组件又当如何呢? ES6 类组件访问 props 的方法略有不同。
|
||||||
|
|
||||||
Anytime you refer to a class component within itself, you use the `this` keyword. To access props within a class component, you preface the code that you use to access it with `this`. For example, if an ES6 class component has a prop called `data`, you write `{this.props.data}` in JSX.
|
任何时候,如果要引用类组件本身,可以使用 `this` 关键字。 要访问类组件中的 props,需要在在访问它的代码前面添加 `this`。 例如,如果 ES6 类组件有一个名为 `data` 的 prop,可以在 JSX 中这样写:`{this.props.data}`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Render an instance of the `ReturnTempPassword` component in the parent component `ResetPassword`. Here, give `ReturnTempPassword` a prop of `tempPassword` and assign it a value of a string that is at least 8 characters long. Within the child, `ReturnTempPassword`, access the `tempPassword` prop within the `strong` tags to make sure the user sees the temporary password.
|
在父组件 `ResetPassword` 中渲染 `ReturnTempPassword` 组件的一个实例。 在这里,为 `ReturnTempPassword` 提供一个 `tempPassword` prop,并赋值一个长度至少为 8 个字符的字符串。 在子组件 `ReturnTempPassword` 中,访问 `strong` 标签中的 `tempPassword` prop,以确保用户看到临时密码。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `ResetPassword` component should return a single `div` element.
|
`ResetPassword` 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The fourth child of `ResetPassword` should be the `ReturnTempPassword` component.
|
`ResetPassword` 的第四个子组件应该是 `ReturnTempPassword` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -42,7 +42,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ReturnTempPassword` component should have a prop called `tempPassword`.
|
`ReturnTempPassword` 组件应该有一个名为 `tempPassword` 的属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -53,7 +53,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `tempPassword` prop of `ReturnTempPassword` should be equal to a string of at least `8` characters.
|
`ReturnTempPassword` 组件的 `tempPassword` prop 值应该是一个字符串,至少为 8 个字符。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -66,7 +66,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ReturnTempPassword` component should display the password you create as the `tempPassword` prop within `strong` tags.
|
`ReturnTempPassword` 组件应该显示作为 `tempPassword` prop 创建的密码,并且密码被包裹在 `strong` 标签中。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24bbe0dba28a8d3cbd4c5e
|
id: 5a24bbe0dba28a8d3cbd4c5e
|
||||||
title: Add Comments in JSX
|
title: 在 JSX 中添加注释
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301376
|
forumTopicId: 301376
|
||||||
dashedName: add-comments-in-jsx
|
dashedName: add-comments-in-jsx
|
||||||
@ -8,35 +8,35 @@ dashedName: add-comments-in-jsx
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
JSX is a syntax that gets compiled into valid JavaScript. Sometimes, for readability, you might need to add comments to your code. Like most programming languages, JSX has its own way to do this.
|
JSX 是一种可以编译成 JavaScript 的语法。 有时,为了便于阅读,可能需要在代码中添加注释。 像大多数编程语言一样,JSX 也有自己的方法来实现这一点。
|
||||||
|
|
||||||
To put comments inside JSX, you use the syntax `{/* */}` to wrap around the comment text.
|
要将注释放在 JSX 中,可以使用 `{/* */}` 语法来包裹注释文本。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a JSX element similar to what you created in the last challenge. Add a comment somewhere within the provided `div` element, without modifying the existing `h1` or `p` elements.
|
代码编辑器中的 JSX 元素与在上一个挑战中创建的元素类似。 在提供的 `div` 元素里添加注释,不修改现有的 `h1` 或 `p` 元素。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return a `div` element.
|
常量 `JSX` 应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.type === 'div');
|
assert(JSX.type === 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain an `h1` tag as the first element.
|
`div` 应该包含一个 `h1` 标签作为第一个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[0].type === 'h1');
|
assert(JSX.props.children[0].type === 'h1');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain a `p` tag as the second element.
|
`div` 应该包含一个 `p` 标签作为第二个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[1].type === 'p');
|
assert(JSX.props.children[1].type === 'p');
|
||||||
```
|
```
|
||||||
|
|
||||||
The existing `h1` and `p` elements should not be modified.
|
当前的 `h1` 和 `p` 元素不能被修改。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -45,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `JSX` should use valid comment syntax.
|
`JSX` 应该包含一个注释。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(/<div>[\s\S]*{\s*\/\*[\s\S]*\*\/\s*}[\s\S]*<\/div>/.test(code));
|
assert(/<div>[\s\S]*{\s*\/\*[\s\S]*\*\/\s*}[\s\S]*<\/div>/.test(code));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403617e
|
id: 5a24c314108439a4d403617e
|
||||||
title: Add Event Listeners
|
title: 添加事件侦听器
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301377
|
forumTopicId: 301377
|
||||||
dashedName: add-event-listeners
|
dashedName: add-event-listeners
|
||||||
@ -8,19 +8,19 @@ dashedName: add-event-listeners
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The `componentDidMount()` method is also the best place to attach any event listeners you need to add for specific functionality. React provides a synthetic event system which wraps the native event system present in browsers. This means that the synthetic event system behaves exactly the same regardless of the user's browser - even if the native events may behave differently between different browsers.
|
`componentDidMount()` 方法也是添加特定功能所需的任何事件监听器的最佳位置。 React 提供了一个合成事件系统,它封装了浏览器中的事件系统。 这意味着,不管用户用的是什么浏览器,合成事件系统的行为都完全相同 -- 即使不同浏览器之间的本地事件的行为可能不同。
|
||||||
|
|
||||||
You've already been using some of these synthetic event handlers such as `onClick()`. React's synthetic event system is great to use for most interactions you'll manage on DOM elements. However, if you want to attach an event handler to the document or window objects, you have to do this directly.
|
之前已经接触了一些合成事件处理程序,如`onClick()`。 React 的合成事件系统非常适合用于在 DOM 元素上管理的大多数交互。 但是,如果要将事件处理程序附加到 document 或 window 对象,则必须直接执行此操作。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Attach an event listener in the `componentDidMount()` method for `keydown` events and have these events trigger the callback `handleKeyPress()`. You can use `document.addEventListener()` which takes the event (in quotes) as the first argument and the callback as the second argument.
|
在 `componentDidMount()` 方法中为 `keydown` 事件添加事件监听器,并让这些事件触发回调 `handleKeyPress()`。 可以使用 `document.addEventListener()`,它将事件(用引号括起来)作为第一个参数,将回调作为第二个参数。
|
||||||
|
|
||||||
Then, in `componentWillUnmount()`, remove this same event listener. You can pass the same arguments to `document.removeEventListener()`. It's good practice to use this lifecycle method to do any clean up on React components before they are unmounted and destroyed. Removing event listeners is an example of one such clean up action.
|
然后,在 `componentWillUnmount()` 中移除相同的事件监听器。 可以把相同的参数传递给 `document.removeEventListener()`。 在卸载和销毁 React 组件之前,最好在这个生命周期方法中对它们进行清理。 移除事件监听器就是这样一个清理操作的例子。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should render a `div` element which wraps an `h1` tag.
|
`MyComponent` 应该渲染一个包含 `h1` 标签的 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,7 +31,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
A keydown listener should be attached to the document in `componentDidMount`.
|
应该在 `componentDidMount` 中将 `keydown` 事件监听添加到到 document 上。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -47,7 +47,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The keydown listener should be removed from the document in `componentWillUnmount`.
|
应该在 `componentWillUnmount` 中将 document 上的 `keydown` 事件监听移除。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -63,7 +63,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Once the component has mounted, pressing `enter` should update its state and the rendered `h1` tag.
|
当组件装载完毕,按 `enter` 键应该会更新其 state ,并渲染到 `h1` 标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036182
|
id: 5a24c314108439a4d4036182
|
||||||
title: Add Inline Styles in React
|
title: 在 React 中添加内联样式
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301378
|
forumTopicId: 301378
|
||||||
dashedName: add-inline-styles-in-react
|
dashedName: add-inline-styles-in-react
|
||||||
@ -8,41 +8,41 @@ dashedName: add-inline-styles-in-react
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You may have noticed in the last challenge that there were several other syntax differences from HTML inline styles in addition to the `style` attribute set to a JavaScript object. First, the names of certain CSS style properties use camel case. For example, the last challenge set the size of the font with `fontSize` instead of `font-size`. Hyphenated words like `font-size` are invalid syntax for JavaScript object properties, so React uses camel case. As a rule, any hyphenated style properties are written using camel case in JSX.
|
在上一次挑战中,你可能已经注意到,除了设置为 JavaScript 对象的 `style` 属性之外,与 HTML 内联样式相比,React 的内联样式还有其他几个语法差异。 首先,某些 CSS 样式属性的名称使用驼峰式命名。 例如,最后一个挑战用 `fontSize` 而不是 `font-size` 来设置字体的大小。 对于 JavaScript 对象属性来说,像 `font-size` 这样的连字符命名是无效的语法,所以 React 使用驼峰式命名。 通常,任何连字符的 style 属性在 JSX 中都是使用驼峰式命名的。
|
||||||
|
|
||||||
All property value length units (like `height`, `width`, and `fontSize`) are assumed to be in `px` unless otherwise specified. If you want to use `em`, for example, you wrap the value and the units in quotes, like `{fontSize: "4em"}`. Other than the length values that default to `px`, all other property values should be wrapped in quotes.
|
除非另有规定,否则所有属性值的 length(如`height`、`width` 和 `fontSize`)其单位都假定为 `px`。 例如,如果要使用 `em`,可以用引号将值和单位括起来,例如 `{fontSize: "4em"}`。 除了默认为 `px` 的 length 值之外,所有其他属性值都应该用引号括起来。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
If you have a large set of styles, you can assign a style `object` to a constant to keep your code organized. Initialize a `styles` constant and assign an `object` with three style properties and their values to it. Give the `div` a color of `"purple"`, a font-size of `40`, and a border of `"2px solid purple"`. Then set the `style` attribute equal to the `styles` constant.
|
如果你有大量样式,你可以将样式 `object`(对象)分配给一个常量,以保持代码的组织有序。 定义一个 `styles` 常量,并将其声明为具有三个样式属性及对应值的 `object`(对象)。 使 `div` 的文字颜色为 `purple`、字号为 `40`、边框为 `2px solid purple`。 然后设置 `style` 属性,使其等于 `styles` 常量。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `styles` variable should be an `object` with three properties.
|
`styles` 变量应该是具有三个属性的 `object`(对象)。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Object.keys(styles).length === 3);
|
assert(Object.keys(styles).length === 3);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `styles` variable should have a `color` property set to a value of `purple`.
|
`styles` 变量的 `color` 属性应该设置为 `purple`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(styles.color === 'purple');
|
assert(styles.color === 'purple');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `styles` variable should have a `fontSize` property set to a value of `40`.
|
`styles` 变量应该将 `fontSize` 属性设置为 `40`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(styles.fontSize === 40);
|
assert(styles.fontSize === 40);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `styles` variable should have a `border` property set to a value of `2px solid purple`.
|
`styles` 变量的 `border` 属性应该设置为 `2px solid purple`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(styles.border === '2px solid purple');
|
assert(styles.border === '2px solid purple');
|
||||||
```
|
```
|
||||||
|
|
||||||
The component should render a `div` element.
|
组件应该渲染一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -53,7 +53,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` element should have its styles defined by the `styles` object.
|
`div` 元素的样式应该由 `styles` 对象定义。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036174
|
id: 5a24c314108439a4d4036174
|
||||||
title: Bind 'this' to a Class Method
|
title: 将 this 绑定到 Class 方法上
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301379
|
forumTopicId: 301379
|
||||||
dashedName: bind-this-to-a-class-method
|
dashedName: bind-this-to-a-class-method
|
||||||
@ -8,23 +8,23 @@ dashedName: bind-this-to-a-class-method
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
In addition to setting and updating `state`, you can also define methods for your component class. A class method typically needs to use the `this` keyword so it can access properties on the class (such as `state` and `props`) inside the scope of the method. There are a few ways to allow your class methods to access `this`.
|
除了设置和更新 `state` 之外,还可以为组件类定义方法。 类方法通常需要使用 `this` 关键字,以便它可以访问方法中类的属性(例如 `state` 和 `props`)。 有几种方法可以让类方法访问 `this`。
|
||||||
|
|
||||||
One common way is to explicitly bind `this` in the constructor so `this` becomes bound to the class methods when the component is initialized. You may have noticed the last challenge used `this.handleClick = this.handleClick.bind(this)` for its `handleClick` method in the constructor. Then, when you call a function like `this.setState()` within your class method, `this` refers to the class and will not be `undefined`.
|
一种常见的方法是在构造函数中显式地绑定 `this`,这样当组件初始化时,`this` 就会绑定到类方法。 你可能已经注意到上一个挑战在构造函数中的 `handleClick` 方法使用了 `this.handleClick = this.handleClick.bind(this)`。 然后,当在类方法中调用像 `this.setState()` 这样的函数时,`this` 指的是这个类,而不是 `undefined`。
|
||||||
|
|
||||||
**Note:** The `this` keyword is one of the most confusing aspects of JavaScript but it plays an important role in React. Although its behavior here is totally normal, these lessons aren't the place for an in-depth review of `this` so please refer to other lessons if the above is confusing!
|
**注意:** `this`关键字是 JavaScript 中最令人困惑的方面之一,但它在 React 中扮演着重要的角色。 虽然它的行为在这里是完全正常的,但是这些课程并不深入研究`this`,所以如果以上内容令你感到困惑,请参考其他课程!
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a component with a `state` that keeps track of the text. It also has a method which allows you to set the text to `"You clicked!"`. However, the method doesn't work because it's using the `this` keyword that is undefined. Fix it by explicitly binding `this` to the `handleClick()` method in the component's constructor.
|
代码编辑器有一个带有 `state` 的组件,用于跟踪项目计数。 它还有一个方法,允许设置文本为 `You clicked!`。 但是,该方法不起作用,因为它使用了未定义的 `this` 关键字。 可以通过将 `this` 显式绑定到组件构造函数中的 `handleClick()`方法来修复它。
|
||||||
|
|
||||||
Next, add a click handler to the `button` element in the render method. It should trigger the `handleClick()` method when the button receives a click event. Remember that the method you pass to the `onClick` handler needs curly braces because it should be interpreted directly as JavaScript.
|
接下来,向 render 方法中的 `button` 元素添加一个单击处理程序。 当按钮接收到单击事件时,它应该触发 `handleClick()` 方法。 记住,传递给 `onClick` 处理程序的方法需要使用花括号,因为它应该直接被解释为 JavaScript。
|
||||||
|
|
||||||
Once you complete the above steps you should be able to click the button and see `You clicked!`.
|
完成上述步骤后,可以单击按钮并看到 `You clicked!`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should return a `div` element which wraps two elements, a button and an `h1` element, in that order.
|
`MyComponent` 应返回 `div` 元素,该元素按顺序包含两个元素,一个按钮和一个 `h1` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `MyComponent` should initialize with the key value pair `{ text: "Hello" }`.
|
`MyComponent` 的 state 应该使用键值对 `{ text: "Hello" }`,进行初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -48,7 +48,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the `button` element should run the `handleClick` method and set the state `text` to `"You clicked!"`.
|
单击 `button` 元素应该运行 `handleClick` 方法,并使 state `text` 为 `You clicked!`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036189
|
id: 5a24c314108439a4d4036189
|
||||||
title: Change Inline CSS Conditionally Based on Component State
|
title: 根据组件状态有条件地更改内联 CSS
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301380
|
forumTopicId: 301380
|
||||||
dashedName: change-inline-css-conditionally-based-on-component-state
|
dashedName: change-inline-css-conditionally-based-on-component-state
|
||||||
@ -8,17 +8,17 @@ dashedName: change-inline-css-conditionally-based-on-component-state
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
At this point, you've seen several applications of conditional rendering and the use of inline styles. Here's one more example that combines both of these topics. You can also render CSS conditionally based on the state of a React component. To do this, you check for a condition, and if that condition is met, you modify the styles object that's assigned to the JSX elements in the render method.
|
此时,已经看到了一些条件渲染的应用程序和内联样式的使用。 这里还有一个将这两个主题结合在一起的例子。 你也可以根据 React 组件的 state 有条件地渲染 CSS。 要执行此操作,请检查条件,如果满足该条件,则修改在 render 方法中分配给 JSX 元素的样式对象。
|
||||||
|
|
||||||
This paradigm is important to understand because it is a dramatic shift from the more traditional approach of applying styles by modifying DOM elements directly (which is very common with jQuery, for example). In that approach, you must keep track of when elements change and also handle the actual manipulation directly. It can become difficult to keep track of changes, potentially making your UI unpredictable. When you set a style object based on a condition, you describe how the UI should look as a function of the application's state. There is a clear flow of information that only moves in one direction. This is the preferred method when writing applications with React.
|
理解这个模式很重要,因为相比传统的方式(这在 jQuery 中非常常见),直接修改 DOM 元素来应用样式的方法是一个戏剧性的转变。 在该方法中,必须跟踪元素何时更改并直接处理实际操作。 跟踪更改可能变得很困难,可能会使 UI无法预测。 当根据一个条件设置一个样式对象时,描述了 UI 作为应用程序的状态函数应当如何展现。 如此便有一个清晰的单向流动的信息流。 这是使用 React 编写应用程序时的首选方法。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a simple controlled input component with a styled border. You want to style this border red if the user types more than 15 characters of text in the input box. Add a condition to check for this and, if the condition is valid, set the input border style to `3px solid red`. You can try it out by entering text in the input.
|
代码编辑器有一个简单的带有边框样式的受控 input 组件。 如果用户在输入框中键入超过 15 个字符的文本,希望将此边框变成红色。 添加一个条件来检查这一点,如果条件有效,则将 input 的边框样式设置为`3px solid red`。 可以通过在 input 中输入文本来检测它。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `GateKeeper` component should render a `div` element.
|
`GateKeeper` 组件应该渲染一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `GateKeeper` component should be initialized with a state key `input` set to an empty string.
|
`GateKeeper` 组件应使用初始为空字符串的 `input` 进行初始化 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `GateKeeper` component should render an `h3` tag and an `input` tag.
|
`GateKeeper` 组件应该渲染一个 `h3` 标签和一个 `input` 标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -54,7 +54,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `input` tag should initially have a style of `1px solid black` for the `border` property.
|
`input` 标签 `border` 属性的样式应该初始化为 `1px solid black`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -67,7 +67,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `input` tag should be styled with a border of `3px solid red` if the input value in state is longer than 15 characters.
|
如果 state 中 input 的值超过 15 个字符,则 `input` 标签的 border 样式应为 `3px solid red`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036166
|
id: 5a24c314108439a4d4036166
|
||||||
title: Compose React Components
|
title: 组合 React 组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301381
|
forumTopicId: 301381
|
||||||
dashedName: compose-react-components
|
dashedName: compose-react-components
|
||||||
@ -8,17 +8,17 @@ dashedName: compose-react-components
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
As the challenges continue to use more complex compositions with React components and JSX, there is one important point to note. Rendering ES6 style class components within other components is no different than rendering the simple components you used in the last few challenges. You can render JSX elements, stateless functional components, and ES6 class components within other components.
|
随着挑战继续,将组合使用更复杂的 React 组件和 JSX,有一点需要注意。 在其它组件中渲染 ES6 风格的类组件和渲染在过去几个挑战中使用的简单组件没有什么不同。 可以在其它组件中渲染 JSX 元素、无状态功能组件和 ES6 类组件。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the code editor, the `TypesOfFood` component is already rendering a component called `Vegetables`. Also, there is the `Fruits` component from the last challenge.
|
在代码编辑器中,`TypesOfFood` 组件已经渲染了一个名为 `Vegetables` 的组件。 此外,还有上次挑战中的 `Fruits` 组件。
|
||||||
|
|
||||||
Nest two components inside of `Fruits` — first `NonCitrus`, and then `Citrus`. Both of these components are provided for you behind the scenes. Next, nest the `Fruits` class component into the `TypesOfFood` component, below the `h1` header and above `Vegetables`. The result should be a series of nested components, which uses two different component types.
|
在 `Fruits` 中嵌套两个组件,首先 `NonCitrus`,然后是 `Citrus`, 这两个组件都已经引入。 接下来,将 `Fruits` 类组件嵌到 `TypesOfFood` 组件中,位于 `h1` 标题下方和 `Vegetables` 上方。 结果应该是一系列嵌套的组件,它们使用两种不同的组件类型。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `TypesOfFood` component should return a single `div` element.
|
`TypesOfFood` 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should return the `Fruits` component.
|
`TypesOfFood` 组件应该返回 `Fruits` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Fruits` component should return the `NonCitrus` component and the `Citrus` component.
|
`Fruits` 组件应该返回 `NonCitrus` 组件和 `Citrus` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -55,7 +55,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should return the `Vegetables` component below the `Fruits` component.
|
`TypesOfFood` 组件应该返回 `Vegetables` 组件,且其位于 `Fruits` 组件之下。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24bbe0dba28a8d3cbd4c5d
|
id: 5a24bbe0dba28a8d3cbd4c5d
|
||||||
title: Create a Complex JSX Element
|
title: 创建一个复杂的 JSX 元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301382
|
forumTopicId: 301382
|
||||||
dashedName: create-a-complex-jsx-element
|
dashedName: create-a-complex-jsx-element
|
||||||
@ -8,17 +8,17 @@ dashedName: create-a-complex-jsx-element
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last challenge was a simple example of JSX, but JSX can represent more complex HTML as well.
|
上一个挑战是 JSX 的一个简单示例,但 JSX 也可以表示更复杂的 HTML。
|
||||||
|
|
||||||
One important thing to know about nested JSX is that it must return a single element.
|
关于嵌套的 JSX,需要知道的一件重要的事情,那就是它必须返回单个元素。
|
||||||
|
|
||||||
This one parent element would wrap all of the other levels of nested elements.
|
这个父元素将包裹所有其他级别的嵌套元素。
|
||||||
|
|
||||||
For instance, several JSX elements written as siblings with no parent wrapper element will not transpile.
|
例如,几个作为兄弟元素编写的 JSX 元素而没有父元素包裹将不会被转换。
|
||||||
|
|
||||||
Here's an example:
|
这里是一个示例:
|
||||||
|
|
||||||
**Valid JSX:**
|
**有效的 JSX:**
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<div>
|
<div>
|
||||||
@ -28,7 +28,7 @@ Here's an example:
|
|||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Invalid JSX:**
|
**无效的 JSX:**
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<p>Paragraph One</p>
|
<p>Paragraph One</p>
|
||||||
@ -38,39 +38,39 @@ Here's an example:
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Define a new constant `JSX` that renders a `div` which contains the following elements in order:
|
定义一个新的常量 `JSX`,渲染一个 `div`,其中依次包含以下元素:
|
||||||
|
|
||||||
An `h1`, a `p`, and an unordered list that contains three `li` items. You can include any text you want within each element.
|
一个 `h1`,一个 `p`,一个包含三个 `li` 项的无序列表。 可以在每个元素中包含任意文本。
|
||||||
|
|
||||||
**Note:** When rendering multiple elements like this, you can wrap them all in parentheses, but it's not strictly required. Also notice this challenge uses a `div` tag to wrap all the child elements within a single parent element. If you remove the `div`, the JSX will no longer transpile. Keep this in mind, since it will also apply when you return JSX elements in React components.
|
**注意:** 当像这样渲染多个元素时,可以把它们都用圆括号括起来,但是这并不是必须的。 另外,此挑战使用 `div` 标签把所有子元素包裹在里面。 如果删除 `div`,JSX 将不会编译这些元素。 请记住这一点,因为在 React 组件中返回 JSX 元素时也适用。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return a `div` element.
|
常量 `JSX` 应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.type === 'div');
|
assert(JSX.type === 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain an `h1` tag as the first element.
|
`div` 应该包含一个 `h1` 标签作为第一个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[0].type === 'h1');
|
assert(JSX.props.children[0].type === 'h1');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain a `p` tag as the second element.
|
`div`应该包含一个`p`标签作为第二个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[1].type === 'p');
|
assert(JSX.props.children[1].type === 'p');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain a `ul` tag as the third element.
|
`div` 应该包含一个 `ul` 标签作为第三个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[2].type === 'ul');
|
assert(JSX.props.children[2].type === 'ul');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ul` should contain three `li` elements.
|
`ul` 应该包含三个 `li` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -89,7 +89,9 @@ ReactDOM.render(JSX, document.getElementById('root'))
|
|||||||
```
|
```
|
||||||
|
|
||||||
## --seed-contents--
|
## --seed-contents--
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036164
|
id: 5a24c314108439a4d4036164
|
||||||
title: Create a Component with Composition
|
title: 用组合的方式创建一个 React 组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301383
|
forumTopicId: 301383
|
||||||
dashedName: create-a-component-with-composition
|
dashedName: create-a-component-with-composition
|
||||||
@ -8,9 +8,9 @@ dashedName: create-a-component-with-composition
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now we will look at how we can compose multiple React components together. Imagine you are building an App and have created three components, a `Navbar`, `Dashboard`, and `Footer`.
|
现在来看看如何组合多个 React 组件。 想象一下,现在正在构建一个应用程序,并创建了三个组件:`Navbar`、`Dashboard` 和 `Footer`。
|
||||||
|
|
||||||
To compose these components together, you could create an `App` *parent* component which renders each of these three components as *children*. To render a component as a child in a React component, you include the component name written as a custom HTML tag in the JSX. For example, in the `render` method you could write:
|
要将这些组件组合在一起,可以创建一个 `App` *父组件*,将这三个组件分别渲染成为*子组件*。 要在 React 组件中渲染一个子组件,需要在 JSX 中包含作为自定义 HTML 标签编写的组件名称。 例如,在 `render` 方法中,可以这样编写:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
return (
|
return (
|
||||||
@ -22,17 +22,17 @@ return (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
When React encounters a custom HTML tag that references another component (a component name wrapped in `< />` like in this example), it renders the markup for that component in the location of the tag. This should illustrate the parent/child relationship between the `App` component and the `Navbar`, `Dashboard`, and `Footer`.
|
当 React 遇到一个自定义 HTML 标签引用另一个组件的时(如本例所示,组件名称包含在 `< />` 中),它在自定义标签的位置渲染该组件的标签。 这可以说明 `App` 组件和 `Navbar`、`Dashboard` 以及 `Footer` 之间的父子关系。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the code editor, there is a simple functional component called `ChildComponent` and a class component called `ParentComponent`. Compose the two together by rendering the `ChildComponent` within the `ParentComponent`. Make sure to close the `ChildComponent` tag with a forward slash.
|
在代码编辑器中,有一个名为 `ChildComponent` 的简单功能组件和一个名为 `ParentComponent` 的 React 组件。 通过在 `ParentComponent` 中渲染 `ChildComponent` 来将两者组合在一起。 确保使用正斜杠关闭 `ChildComponent` 标签。
|
||||||
|
|
||||||
**Note:** `ChildComponent` is defined with an ES6 arrow function because this is a very common practice when using React. However, know that this is just a function. If you aren't familiar with the arrow function syntax, please refer to the JavaScript section.
|
**注意:** `ChildComponent` 是使用 ES6 的箭头函数定义的,这是使用 React 时非常常见的做法。 但是,要知道这只是一个函数。 如果你不熟悉箭头函数语法,请参阅 JavaScript 部分。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The React component should return a single `div` element.
|
React 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -43,7 +43,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The component should return two nested elements.
|
组件应该返回两个嵌套的元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -54,7 +54,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The component should return the ChildComponent as its second child.
|
组件的第二个子元素应该是 `ChildComponent`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036179
|
id: 5a24c314108439a4d4036179
|
||||||
title: Create a Controlled Form
|
title: 创建一个可以控制的表单
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301384
|
forumTopicId: 301384
|
||||||
dashedName: create-a-controlled-form
|
dashedName: create-a-controlled-form
|
||||||
@ -8,21 +8,21 @@ dashedName: create-a-controlled-form
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last challenge showed that React can control the internal state for certain elements like `input` and `textarea`, which makes them controlled components. This applies to other form elements as well, including the regular HTML `form` element.
|
上一个挑战展示了 React 能控制某些元素的内部 state,比如 `input` 和 `textarea`,这使得这些元素成为受控组件。 这也适用于其他表单元素,包括常规的 HTML 表单 `form` 元素。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `MyForm` component is set up with an empty `form` with a submit handler. The submit handler will be called when the form is submitted.
|
`MyForm` 组件中是一个带有提交处理程序的空 `form` 元素, 提交处理程序将在提交表单时被调用。
|
||||||
|
|
||||||
We've added a button which submits the form. You can see it has the `type` set to `submit` indicating it is the button controlling the form. Add the `input` element in the `form` and set its `value` and `onChange()` attributes like the last challenge. You should then complete the `handleSubmit` method so that it sets the component state property `submit` to the current input value in the local `state`.
|
我们增加了一个提交表单的按钮。 可以看到它的 `type` 被设置为 `submit`,表明它是控制表单提交的按钮。 在 `form` 中添加 `input` 元素,并像上个挑战一样设置其 `value` 和 `onChange()` 属性。 然后,应该完成 `handleSubmit` 方法,以便将组件 state 属性 `submit` 设置为本地 `state` 下的当前输入值。
|
||||||
|
|
||||||
**Note:** You also must call `event.preventDefault()` in the submit handler, to prevent the default form submit behavior which will refresh the web page.
|
**注意:** 还必须在提交处理程序中调用 `event.preventDefault()`,以防止默认的表单提交行为刷新网页。
|
||||||
|
|
||||||
Finally, create an `h1` tag after the `form` which renders the `submit` value from the component's `state`. You can then type in the form and click the button (or press enter), and you should see your input rendered to the page.
|
最后,在 `form` 元素之后创建一个 `h1` 标签,该标签从组件的 `state` 渲染 `submit` 的值。 然后,可以在表单中键入任何内容,然后单击按钮(或按 enter 键),输入会渲染到页面上。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyForm` should return a `div` element which contains a `form` and an `h1` tag. The form should include an `input` and a `button`.
|
`MyForm` 应该返回一个包含 `form` 和 `h1` 标签的 `div` 元素, 其中,表单中应该包括一个 `input` 和一个 `button`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -38,7 +38,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `MyForm` should initialize with `input` and `submit` properties, both set to empty strings.
|
`MyForm` 的 state 应该用 `input` 和 `submit` 属性初始化,且两者都为空字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -47,7 +47,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Typing in the `input` element should update the `input` property of the component's state.
|
`input` 元素中的输入应该会更新组件中 state 的 `input` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -75,7 +75,7 @@ Typing in the `input` element should update the `input` property of the componen
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
Submitting the form should run `handleSubmit` which should set the `submit` property in state equal to the current input.
|
提交表单应该运行 `handleSubmit`,它应该将 state 中的 `submit` 属性设置为当前输入。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -98,7 +98,7 @@ Submitting the form should run `handleSubmit` which should set the `submit` prop
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
The `h1` header should render the value of the `submit` field from the component's state.
|
`h1` 标题应该从组件的 state 渲染 `submit` 字段的值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036178
|
id: 5a24c314108439a4d4036178
|
||||||
title: Create a Controlled Input
|
title: 创建一个可以控制的输入框
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301385
|
forumTopicId: 301385
|
||||||
dashedName: create-a-controlled-input
|
dashedName: create-a-controlled-input
|
||||||
@ -8,23 +8,23 @@ dashedName: create-a-controlled-input
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Your application may have more complex interactions between `state` and the rendered UI. For example, form control elements for text input, such as `input` and `textarea`, maintain their own state in the DOM as the user types. With React, you can move this mutable state into a React component's `state`. The user's input becomes part of the application `state`, so React controls the value of that input field. Typically, if you have React components with input fields the user can type into, it will be a controlled input form.
|
应用程序可能在 `state` 和渲染的 UI 之间有更复杂的交互。 例如,用于文本输入的表单控件元素(如 `input` 和 `textarea`)在用户键入时在 DOM 中维护自己的 state。 通过 React,可以将这种可变 state 转移到 React 组件的 `state` 中。 用户的输入变成了应用程序 `state` 的一部分,因此 React 控制该输入字段的值。 通常,如果 React 组件具有用户可以键入的输入字段,那么它将是一个受控的输入表单。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has the skeleton of a component called `ControlledInput` to create a controlled `input` element. The component's `state` is already initialized with an `input` property that holds an empty string. This value represents the text a user types into the `input` field.
|
代码编辑器具有一个名为 `ControlledInput` 的组件框架,用于创建受控的 `input` 元素。 组件的 `state` 已经被包含空字符串的 `input` 属性初始化。 此值表示用户在 `input` 字段中键入的文本。
|
||||||
|
|
||||||
First, create a method called `handleChange()` that has a parameter called `event`. When the method is called, it receives an `event` object that contains a string of text from the `input` element. You can access this string with `event.target.value` inside the method. Update the `input` property of the component's `state` with this new string.
|
首先,创建一个名为 `handleChange()` 的方法,该方法具有一个名为 `event` 的参数。 方法被调用时,它接收一个 `event` 对象,该对象包含一个来自 `input` 元素的字符串文本。 可以使用方法内的 `event.target.value` 来访问这个字符串。 用这个新字符串更新组件的`state`的`input`属性。
|
||||||
|
|
||||||
In the render method, create the `input` element above the `h4` tag. Add a `value` attribute which is equal to the `input` property of the component's `state`. Then add an `onChange()` event handler set to the `handleChange()` method.
|
在 `render` 方法中的 `h4` 标签之上创建 `input` 元素。 添加一个 `value` 属性,使其等于组件 `state` 的 `input` 属性。 然后将 `onChange()` 事件处理程序设置到 `handleChange()` 方法中。
|
||||||
|
|
||||||
When you type in the input box, that text is processed by the `handleChange()` method, set as the `input` property in the local `state`, and rendered as the value in the `input` box on the page. The component `state` is the single source of truth regarding the input data.
|
在输入框中键入时,文本由 `handleChange()` 方法处理,文本被设置为本地 `state` 中的 `input` 属性,并渲染在页面上的 `input` 框中。 组件 `state` 是输入数据的唯一真实来源。
|
||||||
|
|
||||||
Last but not least, don't forget to add the necessary bindings in the constructor.
|
最后,不要忘记在构造函数中添加必要的绑定。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`ControlledInput` should return a `div` element which contains an `input` and a `p` tag.
|
`ControlledInput` 应该返回包含一个 `input` 标签和 `p` 标签的 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -39,7 +39,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `ControlledInput` should initialize with an `input` property set to an empty string.
|
`ControlledInput` 的 state 应该使用设置为空字符串的 `input` 属性初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -48,7 +48,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Typing in the input element should update the state and the value of the input, and the `p` element should render this state as you type.
|
Input 元素中的键入值应该更新 input 的 state 和值,并且 `p` 元素应该在输入时呈现 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036163
|
id: 5a24c314108439a4d4036163
|
||||||
title: Create a React Component
|
title: 创建一个 React 组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301386
|
forumTopicId: 301386
|
||||||
dashedName: create-a-react-component
|
dashedName: create-a-react-component
|
||||||
@ -8,7 +8,7 @@ dashedName: create-a-react-component
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The other way to define a React component is with the ES6 `class` syntax. In the following example, `Kitten` extends `React.Component`:
|
定义 React 组件的另一种方法是使用 ES6 的 `class`语法。 在以下示例中,`Kitten` 扩展了`React.Component`:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
class Kitten extends React.Component {
|
class Kitten extends React.Component {
|
||||||
@ -24,21 +24,21 @@ class Kitten extends React.Component {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This creates an ES6 class `Kitten` which extends the `React.Component` class. So the `Kitten` class now has access to many useful React features, such as local state and lifecycle hooks. Don't worry if you aren't familiar with these terms yet, they will be covered in greater detail in later challenges. Also notice the `Kitten` class has a `constructor` defined within it that calls `super()`. It uses `super()` to call the constructor of the parent class, in this case `React.Component`. The constructor is a special method used during the initialization of objects that are created with the `class` keyword. It is best practice to call a component's `constructor` with `super`, and pass `props` to both. This makes sure the component is initialized properly. For now, know that it is standard for this code to be included. Soon you will see other uses for the constructor as well as `props`.
|
这将创建一个 ES6 类 `Kitten`,它扩展了 `React.Component` 类。 因此,`Kitten` 类现在可以访问许多有用的 React 功能,例如本地状态和生命周期钩子。 如果还不熟悉这些术语,请不要担心,在以后的挑战中我们将更详细地介绍它们。 另请注意,`Kitten` 类中定义了一个调用 `super()` 方法的 `constructor`。 它使用 `super()` 调用父类的构造函数,即本例中的 `React.Component`。 构造函数是使用 `class` 关键字创建的特殊方法,它在实例初始化之前调用。 最佳做法是在组件的 `constructor` 里调用 `super`,并将 `props` 传递给它们, 这样可以保证组件能够正确地初始化。 目前为止 ,需要知道这些代码是必要的。 很快会了解到到构造函数的其他用途以及 `props`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
`MyComponent` is defined in the code editor using class syntax. Finish writing the `render` method so it returns a `div` element that contains an `h1` with the text `Hello React!`.
|
`MyComponent` 是使用类语法在代码编辑器中定义的。 完成 `render` 方法的编写,使其返回 `div` 元素,其中包含文本内容为 `Hello React!` 的 `h1` 元素。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The React component should return a `div` element.
|
该 React 组件应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.shallow(React.createElement(MyComponent)).type() === 'div');
|
assert(Enzyme.shallow(React.createElement(MyComponent)).type() === 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The returned `div` should render an `h1` header within it.
|
返回的 `div` 中应该渲染一个 `h1` 标题。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -48,7 +48,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `h1` header should contain the string `Hello React!`.
|
`h1` 标题中应该包含字符串 `Hello React!`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 587d7dbc367417b2b2512bb1
|
id: 587d7dbc367417b2b2512bb1
|
||||||
title: Create a Simple JSX Element
|
title: 创建一个简单的 JSX 元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301390
|
forumTopicId: 301390
|
||||||
dashedName: create-a-simple-jsx-element
|
dashedName: create-a-simple-jsx-element
|
||||||
@ -8,29 +8,29 @@ dashedName: create-a-simple-jsx-element
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
**Intro:** React is an Open Source view library created and maintained by Facebook. It's a great tool to render the User Interface (UI) of modern web applications.
|
简介:React 是由 Facebook 创建和维护的开源视图库。 它是渲染现代 Web 应用程序用户界面(UI)的好工具。
|
||||||
|
|
||||||
React uses a syntax extension of JavaScript called JSX that allows you to write HTML directly within JavaScript. This has several benefits. It lets you use the full programmatic power of JavaScript within HTML, and helps to keep your code readable. For the most part, JSX is similar to the HTML that you have already learned, however there are a few key differences that will be covered throughout these challenges.
|
React 使用名为 JSX 的 JavaScript 语法扩展,可以直接在 JavaScript 中编写 HTML。 这有几个好处。 可以在 HTML 中使用 JavaScript 的完整程序功能,并有助于保持代码的可读性。 在大多数情况下,JSX 类似于已经学过的 HTML,但是在这些挑战中将会涉及一些关键差异。
|
||||||
|
|
||||||
For instance, because JSX is a syntactic extension of JavaScript, you can actually write JavaScript directly within JSX. To do this, you simply include the code you want to be treated as JavaScript within curly braces: `{ 'this is treated as JavaScript code' }`. Keep this in mind, since it's used in several future challenges.
|
例如,因为 JSX 是 JavaScript 的语法扩展,所以实际上可以直接在 JSX 中编写 JavaScript。 要做到这一点,只需在花括号中包含希望被视为 JavaScript 的代码:`{ 'this is treated as JavaScript code' }`(这被视为 JavaScript 代码)。 请牢记这个写法,将会在接下来的挑战中使用。
|
||||||
|
|
||||||
However, because JSX is not valid JavaScript, JSX code must be compiled into JavaScript. The transpiler Babel is a popular tool for this process. For your convenience, it's already added behind the scenes for these challenges. If you happen to write syntactically invalid JSX, you will see the first test in these challenges fail.
|
但是,由于浏览器不能解析 JSX,因此必须将 JSX 代码编译为 JavaScript。 在这个过程中,转换器 Babel 是一个很受欢迎的工具。 后续挑战已经在后台引入了 Babel,可以直接写 JSX 代码。 如果代码不符合 JSX 语法,那么挑战中的第一个测试就不会通过。
|
||||||
|
|
||||||
It's worth noting that under the hood the challenges are calling `ReactDOM.render(JSX, document.getElementById('root'))`. This function call is what places your JSX into React's own lightweight representation of the DOM. React then uses snapshots of its own DOM to optimize updating only specific parts of the actual DOM.
|
值得注意的是,这些挑战在底层调用 `ReactDOM.render(JSX, document.getElementById('root'))`。 这个函数调用将 JSX 置于 React 自己的轻量级 DOM 中。 然后,React 使用自己的 DOM 快照来实现增量更新。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
**Instructions:** The current code uses JSX to assign a `div` element to the constant `JSX`. Replace the `div` with an `h1` element and add the text `Hello JSX!` inside it.
|
当前代码使用 JSX 将 `div` 元素赋值给常量 `JSX`。 将 `div` 替换为 `h1` 元素,并在其中添加文本 `Hello JSX!`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return an `h1` element.
|
常量 `JSX` 应该返回一个 `h1` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.type === 'h1');
|
assert(JSX.type === 'h1');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `h1` tag should include the text `Hello JSX!`
|
`h1` 标签应该包含文本 `Hello JSX!`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.shallow(JSX).contains('Hello JSX!'));
|
assert(Enzyme.shallow(JSX).contains('Hello JSX!'));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036170
|
id: 5a24c314108439a4d4036170
|
||||||
title: Create a Stateful Component
|
title: 创建一个有状态的组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301391
|
forumTopicId: 301391
|
||||||
dashedName: create-a-stateful-component
|
dashedName: create-a-stateful-component
|
||||||
@ -8,25 +8,25 @@ dashedName: create-a-stateful-component
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
One of the most important topics in React is `state`. State consists of any data your application needs to know about, that can change over time. You want your apps to respond to state changes and present an updated UI when necessary. React offers a nice solution for the state management of modern web applications.
|
React 中最重要的主题之一是 `state`。 state 包含应用程序需要了解的任何数据,这些数据可能会随时间而变化。 应用程序能够响应 state 的变更,并在必要时显示更新后的 UI。 React 为现代 Web 应用程序的状态管理提供了一个很好的解决方案。
|
||||||
|
|
||||||
You create state in a React component by declaring a `state` property on the component class in its `constructor`. This initializes the component with `state` when it is created. The `state` property must be set to a JavaScript `object`. Declaring it looks like this:
|
可以在类组件的 `constructor` 上声明 `state` 属性来在 React 组件中创建 state, 它在创建时使用 `state` 初始化组件。 `state` 属性必须设置为 JavaScript `object`(对象)。 声明如下:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
this.state = {
|
this.state = {
|
||||||
// describe your state here
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You have access to the `state` object throughout the life of your component. You can update it, render it in your UI, and pass it as props to child components. The `state` object can be as complex or as simple as you need it to be. Note that you must create a class component by extending `React.Component` in order to create `state` like this.
|
可以在组件的整个生命周期内访问 `state` 对象, 可以更新它、在 UI 中渲染它,也可以将其作为 props 传递给子组件。 `state` 对象的使用可以很简单,亦可以很复杂,就看你怎么用了。 请注意,必须通过扩展 `React.Component` 来创建类组件,以便像这样创建 `state`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There is a component in the code editor that is trying to render a `name` property from its `state`. However, there is no `state` defined. Initialize the component with `state` in the `constructor` and assign your name to a property of `name`.
|
代码编辑器中有一个组件试图从其 `state` 中渲染一个 `name` 属性, 但是 `state` 还没有定义。 在 `constructor` 中使用 `state` 初始化组件,并将你的名字赋给 `name` 属性。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`StatefulComponent` should exist and render.
|
`StatefulComponent` 应该存在并被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -39,7 +39,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`StatefulComponent` should render a `div` and an `h1` element.
|
`StatefulComponent` 应该渲染一个 `div` 元素和一个 `h1` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -55,7 +55,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `StatefulComponent` should be initialized with a property `name` set to a string.
|
应使用被设置为字符串的 `name` 属性来初始化 `StatefulComponent` 的 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -71,7 +71,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The property `name` in the state of `StatefulComponent` should render in the `h1` element.
|
`StatefulComponent` 中 state 的 `name` 属性应该渲染在 `h1` 元素里。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036162
|
id: 5a24c314108439a4d4036162
|
||||||
title: Create a Stateless Functional Component
|
title: 创建一个无状态的函数组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301392
|
forumTopicId: 301392
|
||||||
dashedName: create-a-stateless-functional-component
|
dashedName: create-a-stateless-functional-component
|
||||||
@ -8,14 +8,13 @@ dashedName: create-a-stateless-functional-component
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Components are the core of React. Everything in React is a component and here you will learn how to create one.
|
组件是 React 的核心。 React 中的所有内容都是一个组件,在这里将学习如何创建一个组件。
|
||||||
|
|
||||||
There are two ways to create a React component. The first way is to use a JavaScript function. Defining a component in this way creates a *stateless functional component*. The concept of state in an application will be covered in later challenges. For now, think of a stateless component as one that can receive data and render it, but does not manage or track changes to that data. (We'll cover the second way to create a React component in the next challenge.)
|
有两种方法可以创建 React 组件。 第一种方法是使用 JavaScript 函数。 以这种方式定义组件会创建*无状态功能组件*。 应用程序中的状态概念将在以后的挑战中介绍。 目前为止,可以将无状态组件视为能接收数据并对其进行渲染,但不管理或跟踪该数据的更改的组件。 (我们将下一个挑战使用中第二种方式创建 React 组件。)
|
||||||
|
|
||||||
To create a component with a function, you simply write a JavaScript function that returns either JSX or `null`. One important thing to note is that React requires your function name to begin with a capital letter. Here's an example of a stateless functional component that assigns an HTML class in JSX:
|
要用函数创建组件,只需编写一个返回 JSX 或 `null` 的 JavaScript 函数。 需要注意的一点是,React 要求你的函数名以大写字母开头。 下面是一个无状态功能组件的示例,该组件在 JSX 中分配一个 HTML 的 class:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
// After being transpiled, the <div> will have a CSS class of 'customClass'
|
|
||||||
const DemoComponent = function() {
|
const DemoComponent = function() {
|
||||||
return (
|
return (
|
||||||
<div className='customClass' />
|
<div className='customClass' />
|
||||||
@ -23,17 +22,19 @@ const DemoComponent = function() {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Because a JSX component represents HTML, you could put several components together to create a more complex HTML page. This is one of the key advantages of the component architecture React provides. It allows you to compose your UI from many separate, isolated components. This makes it easier to build and maintain complex user interfaces.
|
翻译完成后, `<div>` 将有一个 `customClass` 的 CSS class。
|
||||||
|
|
||||||
|
因为 JSX 组件代表 HTML,所以你可以将几个组件放在一起以创建更复杂的 HTML 页面。 这是 React 提供的组件架构的关键优势之一。 它允许用许多独立的组件组合成 UI。 这使得构建和维护复杂的用户界面变得更加容易。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a function called `MyComponent`. Complete this function so it returns a single `div` element which contains some string of text.
|
代码编辑器中有一个名为 `MyComponent` 的函数。 完成此函数,使其返回包含一些文本字符串的单个`div`元素。
|
||||||
|
|
||||||
**Note:** The text is considered a child of the `div` element, so you will not be able to use a self-closing tag.
|
**注意:** 文本被视为是 `div` 的子元素,因此不能使用自闭合标签。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should return JSX.
|
`MyComponent` 应该返回 JSX。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -44,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should return a `div` element.
|
`MyComponent` 应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -55,7 +56,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` element should contain a string of text.
|
`div` 元素应该包含一个文本字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036160
|
id: 5a24c314108439a4d4036160
|
||||||
title: Define an HTML Class in JSX
|
title: 在 JSX 中定义一个 HTML Class
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301393
|
forumTopicId: 301393
|
||||||
dashedName: define-an-html-class-in-jsx
|
dashedName: define-an-html-class-in-jsx
|
||||||
@ -8,27 +8,27 @@ dashedName: define-an-html-class-in-jsx
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now that you're getting comfortable writing JSX, you may be wondering how it differs from HTML.
|
现在已经习惯了编写 JSX,可能想知道它与 HTML 有什么不同。
|
||||||
|
|
||||||
So far, it may seem that HTML and JSX are exactly the same.
|
到目前为止,HTML 和 JSX 似乎完全相同。
|
||||||
|
|
||||||
One key difference in JSX is that you can no longer use the word `class` to define HTML classes. This is because `class` is a reserved word in JavaScript. Instead, JSX uses `className`.
|
JSX 的一个关键区别是你不能再使用 `class` 这个单词来做为 HTML 的 class 名。 这是因为 `class` 是 JavaScript 中的关键字。 而 JSX 使用 `className` 来代替。
|
||||||
|
|
||||||
In fact, the naming convention for all HTML attributes and event references in JSX become camelCase. For example, a click event in JSX is `onClick`, instead of `onclick`. Likewise, `onchange` becomes `onChange`. While this is a subtle difference, it is an important one to keep in mind moving forward.
|
事实上,JSX 中所有 HTML 属性和事件引用的命名约定都变成了驼峰式。 例如,JSX 中的单击事件是 `onClick`,而不是 `onclick`。 同样,`onchange` 变成了`onChange`。 虽然这是一个微小的差异,但请你一定要记住。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Apply a class of `myDiv` to the `div` provided in the JSX code.
|
将 class `myDiv` 应用于 JSX 提供的 `div`上。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return a `div` element.
|
常量`JSX`应该返回一个`div`元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(JSX.type, 'div');
|
assert.strictEqual(JSX.type, 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should have a class of `myDiv`.
|
`div` 应该有一个 `myDiv` class。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(JSX.props.className, 'myDiv');
|
assert.strictEqual(JSX.props.className, 'myDiv');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403618b
|
id: 5a24c314108439a4d403618b
|
||||||
title: Give Sibling Elements a Unique Key Attribute
|
title: 给同级元素一个唯一的键属性
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301394
|
forumTopicId: 301394
|
||||||
dashedName: give-sibling-elements-a-unique-key-attribute
|
dashedName: give-sibling-elements-a-unique-key-attribute
|
||||||
@ -8,19 +8,19 @@ dashedName: give-sibling-elements-a-unique-key-attribute
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last challenge showed how the `map` method is used to dynamically render a number of elements based on user input. However, there was an important piece missing from that example. When you create an array of elements, each one needs a `key` attribute set to a unique value. React uses these keys to keep track of which items are added, changed, or removed. This helps make the re-rendering process more efficient when the list is modified in any way.
|
上一个挑战展示了如何使用 `map` 方法根据用户输入动态渲染多个元素。 然而,这个例子中缺少一个重要的部分。 创建元素数组时,每个元素都需要一个设置为唯一值的 `key` 属性。 React 使用这些键来跟踪哪些项目被添加、更改或删除。 这有助于在以任何方式修改列表时提高重新渲染过程的效率。
|
||||||
|
|
||||||
**Note:** Keys only need to be unique between sibling elements, they don't need to be globally unique in your application.
|
**注意:** 键只需要在兄弟元素之间是唯一的,它们不需要在应用程序中是全局唯一的。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has an array with some front end frameworks and a stateless functional component named `Frameworks()`. `Frameworks()` needs to map the array to an unordered list, much like in the last challenge. Finish writing the `map` callback to return an `li` element for each framework in the `frontEndFrameworks` array. This time, make sure to give each `li` a `key` attribute, set to a unique value. The `li` elements should also contain text from `frontEndFrameworks`.
|
代码编辑器有一个数组,它包含一些前端框架和一个名为 `Frameworks()` 的无状态函数组件。 `Frameworks()` 需要将数组映射到无序列表,就像上一个挑战一样。 完成 `map` 回调,为 `frontEndFrameworks` 数组中的每个框架返回一个 `li` 元素。 这次,确保给每个 `li` 的 `key` 属性设置一个唯一的值。 `li` 元素还应该包含来自 `frontEndFrameworks` 的文本。
|
||||||
|
|
||||||
Normally, you want to make the key something that uniquely identifies the element being rendered. As a last resort the array index may be used, but typically you should try to use a unique identification.
|
通常,希望使 key 能唯一标识要渲染的元素。 数组索引可以是最后的选择,但通常你应该尝试使用唯一标识。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `Frameworks` component should exist and render to the page.
|
`Frameworks` 组件应该存在并渲染到页面。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -28,19 +28,19 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`Frameworks` should render an `h1` element.
|
`Frameworks` 应该渲染一个 `h1` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.mount(React.createElement(Frameworks)).find('h1').length === 1);
|
assert(Enzyme.mount(React.createElement(Frameworks)).find('h1').length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
`Frameworks` should render a `ul` element.
|
`Frameworks` 应该渲染一个 `ul` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.mount(React.createElement(Frameworks)).find('ul').length === 1);
|
assert(Enzyme.mount(React.createElement(Frameworks)).find('ul').length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ul` tag should render 6 child `li` elements.
|
`ul` 标签应该渲染 6 个子 `li` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -54,7 +54,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Each list item element should have a unique `key` attribute.
|
每个列表项元素应该具有唯一的 `key` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -73,7 +73,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Each list item element should contain text from `frontEndFrameworks`.
|
每个列表项元素应该包含来自 `frontEndFrameworks` 的文本。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036181
|
id: 5a24c314108439a4d4036181
|
||||||
title: Introducing Inline Styles
|
title: 介绍内联样式
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301395
|
forumTopicId: 301395
|
||||||
dashedName: introducing-inline-styles
|
dashedName: introducing-inline-styles
|
||||||
@ -8,29 +8,29 @@ dashedName: introducing-inline-styles
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
There are other complex concepts that add powerful capabilities to your React code. But you may be wondering about the more simple problem of how to style those JSX elements you create in React. You likely know that it won't be exactly the same as working with HTML because of [the way you apply classes to JSX elements](/learn/front-end-libraries/react/define-an-html-class-in-jsx).
|
还有其他复杂的概念可以为 React 代码增加强大的功能。 但是,你可能会想知道更简单的问题,比如:如何对在 React 中创建的 JSX 元素添加样式。 你可能知道,由于[将 class 应用于 JSX 元素的方式](/learn/front-end-libraries/react/define-an-html-class-in-jsx)与 HTML 中的使用并不完全相同。
|
||||||
|
|
||||||
If you import styles from a stylesheet, it isn't much different at all. You apply a class to your JSX element using the `className` attribute, and apply styles to the class in your stylesheet. Another option is to apply inline styles, which are very common in ReactJS development.
|
如果从样式表导入样式,它就没有太大的不同。 使用 `className` 属性将 class 应用于 JSX 元素,并将样式应用于样式表中的 class。 另一种选择是使用内联样式,这在 ReactJS 开发中非常常见。
|
||||||
|
|
||||||
You apply inline styles to JSX elements similar to how you do it in HTML, but with a few JSX differences. Here's an example of an inline style in HTML:
|
将内联样式应用于 JSX 元素,类似于在 HTML 中的操作方式,但有一些 JSX 差异。 以下是 HTML 中内联样式的示例:
|
||||||
|
|
||||||
`<div style="color: yellow; font-size: 16px">Mellow Yellow</div>`
|
`<div style="color: yellow; font-size: 16px">Mellow Yellow</div>`
|
||||||
|
|
||||||
JSX elements use the `style` attribute, but because of the way JSX is transpiled, you can't set the value to a `string`. Instead, you set it equal to a JavaScript `object`. Here's an example:
|
JSX 元素使用 `style` 属性,但是由于 JSX 的编译方式,不能将值设置为 `string`(字符串)。 相反,你应将其设置为 JavaScript `object`(对象)。 这里有一个例子:
|
||||||
|
|
||||||
`<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div>`
|
`<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div>`
|
||||||
|
|
||||||
Notice how we camelCase the "fontSize" property? This is because React will not accept kebab-case keys in the style object. React will apply the correct property name for us in the HTML.
|
请注意如何驼峰拼写 `fontSize` 属性? 这是因为 React 不接受下划线分隔的样式对象。 React 将在 HTML 中编译为正确的属性名称。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Add a `style` attribute to the `div` in the code editor to give the text a color of red and font size of 72px.
|
在代码编辑器的 `div` 中添加一个 `style` 属性,使文本颜色为红色,字体大小为 `72px`。
|
||||||
|
|
||||||
Note that you can optionally set the font size to be a number, omitting the units "px", or write it as "72px".
|
请注意,可以选择将字体大小设置为数字,省略单位 `px`,或者将其写为 `72px`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The component should render a `div` element.
|
组件应该渲染一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -41,7 +41,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` element should have a color of `red`.
|
`div` 元素的颜色应该是 `red`(红色)。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -52,7 +52,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` element should have a font size of `72px`.
|
`div` 元素的字体大小应为 `72px`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036161
|
id: 5a24c314108439a4d4036161
|
||||||
title: Learn About Self-Closing JSX Tags
|
title: 了解 JSX 的自动闭合
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301396
|
forumTopicId: 301396
|
||||||
dashedName: learn-about-self-closing-jsx-tags
|
dashedName: learn-about-self-closing-jsx-tags
|
||||||
@ -8,35 +8,35 @@ dashedName: learn-about-self-closing-jsx-tags
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
So far, you’ve seen how JSX differs from HTML in a key way with the use of `className` vs. `class` for defining HTML classes.
|
到目前为止,已经看到 JSX 与 HTML 的关键不同在于使用 `className` 还是 `class` 来定义 HTML 的 class。
|
||||||
|
|
||||||
Another important way in which JSX differs from HTML is in the idea of the self-closing tag.
|
JSX 不同于 HTML 的另一个重要方面是自闭合标签。
|
||||||
|
|
||||||
In HTML, almost all tags have both an opening and closing tag: `<div></div>`; the closing tag always has a forward slash before the tag name that you are closing. However, there are special instances in HTML called “self-closing tags”, or tags that don’t require both an opening and closing tag before another tag can start.
|
在HTML中,几乎所有的标签都有一个开始和结束标签:`<div></div>`,结束标签在你要关闭的标签名之前始终具有正斜杠。 但是,HTML 中有一些称为 “自闭合标签” 的特殊实例,它们在另一个标签开始之前,不需要开始和结束标签都存在。
|
||||||
|
|
||||||
For example the line-break tag can be written as `<br>` or as `<br />`, but should never be written as `<br></br>`, since it doesn't contain any content.
|
例如,换行标签可以写成 `<br>` 或者 `<br />`,但是不应该写成 `<br></br>`,因为它不包含任何内容。
|
||||||
|
|
||||||
In JSX, the rules are a little different. Any JSX element can be written with a self-closing tag, and every element must be closed. The line-break tag, for example, must always be written as `<br />` in order to be valid JSX that can be transpiled. A `<div>`, on the other hand, can be written as `<div />` or `<div></div>`. The difference is that in the first syntax version there is no way to include anything in the `<div />`. You will see in later challenges that this syntax is useful when rendering React components.
|
在 JSX 中,规则略有不同。 任何 JSX 元素都可以使用自闭合标签编写,并且每个元素都必须关闭。 例如,为了通过编译换行标签必须始终编写为 `<br />`。 另一方面 `<div>` 可以写成 `<div />` 或者 `<div></div>`。 不同之处在于,在第一个语法版本中,无法在 `<div />` 中包含任何内容。 在后面的挑战中你会发现,这种语法在渲染 React 组件时非常有用。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Fix the errors in the code editor so that it is valid JSX and successfully transpiles. Make sure you don't change any of the content - you only need to close tags where they are needed.
|
修复代码编辑器中的错误,使其成为有效的 JSX 并成功编译。 确保不更改任何内容 -- 只需要在需要的地方关闭标签。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return a `div` element.
|
常量 `JSX` 应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(JSX.type, 'div');
|
assert.strictEqual(JSX.type, 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain a `br` tag.
|
`div` 应该包含一个 `br` 标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.shallow(JSX).find('br').length === 1);
|
assert(Enzyme.shallow(JSX).find('br').length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain an `hr` tag.
|
`div` 应该包含一个 `hr` 标签。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.shallow(JSX).find('hr').length === 1);
|
assert(Enzyme.shallow(JSX).find('hr').length === 1);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036180
|
id: 5a24c314108439a4d4036180
|
||||||
title: Optimize Re-Renders with shouldComponentUpdate
|
title: 使用 shouldComponentUpdate 优化重新渲染
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301398
|
forumTopicId: 301398
|
||||||
dashedName: optimize-re-renders-with-shouldcomponentupdate
|
dashedName: optimize-re-renders-with-shouldcomponentupdate
|
||||||
@ -8,17 +8,17 @@ dashedName: optimize-re-renders-with-shouldcomponentupdate
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
So far, if any component receives new `state` or new `props`, it re-renders itself and all its children. This is usually okay. But React provides a lifecycle method you can call when child components receive new `state` or `props`, and declare specifically if the components should update or not. The method is `shouldComponentUpdate()`, and it takes `nextProps` and `nextState` as parameters.
|
到目前为止,如果任何组件接收到新的 `state` 或新的 `props`,它会重新渲染自己及其所有子组件。 这通常是好的。 但是 React 提供了一种生命周期方法,当子组件接收到新的 `state` 或 `props` 时,可以调用该方法,并特别声明组件是否应该更新。 这个方法就是 `shouldComponentUpdate()`,它将 `nextProps` 和 `nextState` 作为参数。
|
||||||
|
|
||||||
This method is a useful way to optimize performance. For example, the default behavior is that your component re-renders when it receives new `props`, even if the `props` haven't changed. You can use `shouldComponentUpdate()` to prevent this by comparing the `props`. The method must return a `boolean` value that tells React whether or not to update the component. You can compare the current props (`this.props`) to the next props (`nextProps`) to determine if you need to update or not, and return `true` or `false` accordingly.
|
这种方法是优化性能的有效方法。 例如,默认行为是,当组件接收到新的 `props` 时,即使 `props` 没有改变,它也会重新渲染。 可以通过使用 `shouldComponentUpdate()` 比较 `props` 来防止这种情况发生。 该方法必须返回一个 `boolean`(布尔值),该值告诉 React 是否更新组件。 可以比较当前的 props(`this.props`)和下一个 props(`nextProps`),以确定你是否需要更新,并相应地返回 `true` 或 `false`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `shouldComponentUpdate()` method is added in a component called `OnlyEvens`. Currently, this method returns `true` so `OnlyEvens` re-renders every time it receives new `props`. Modify the method so `OnlyEvens` updates only if the `value` of its new props is even. Click the `Add` button and watch the order of events in your browser's console as the lifecycle hooks are triggered.
|
将 `shouldComponentUpdate()` 方法添加到名为 `OnlyEvens` 的组件中。 目前,该方法返回 `true`,因此每次收到新的 `props` 时,`OnlyEvens` 都会重新渲染。 修改该方法,以便 `OnlyEvens` 仅在其新 props 的 `value` 为偶数时更新。 单击 `Add` 按钮,在触发其他生命周期钩子时,在浏览器控制台中查看事件的顺序。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `Controller` component should render the `OnlyEvens` component as a child.
|
`Controller` 组件应该将 `OnlyEvens` 组件渲染为子组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -32,7 +32,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `shouldComponentUpdate` method should be defined on the `OnlyEvens` component.
|
应该在 `OnlyEvens` 组件上定义 `shouldComponentUpdate` 方法。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -45,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `OnlyEvens` component should return an `h1` tag which renders the value of `this.props.value`.
|
`OnlyEvens` 组件应该返回一个 `h1` 标签,该标签渲染 `this.props.value` 的值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -64,7 +64,7 @@ The `OnlyEvens` component should return an `h1` tag which renders the value of `
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
`OnlyEvens` should re-render only when `nextProps.value` is even.
|
只有在 `nextProps.value` 为偶数时,`OnlyEvens` 才会重新渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616c
|
id: 5a24c314108439a4d403616c
|
||||||
title: Override Default Props
|
title: 覆盖默认的 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301399
|
forumTopicId: 301399
|
||||||
dashedName: override-default-props
|
dashedName: override-default-props
|
||||||
@ -8,17 +8,17 @@ dashedName: override-default-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The ability to set default props is a useful feature in React. The way to override the default props is to explicitly set the prop values for a component.
|
在 React 中,设置默认的 props 是一个很有用的特性, 显式设置组件的 prop 值即可覆盖默认 props。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `ShoppingCart` component now renders a child component `Items`. This `Items` component has a default prop `quantity` set to the integer `0`. Override the default prop by passing in a value of `10` for `quantity`.
|
`ShoppingCart` 组件现在渲染了一个子组件 `Items`。 该 `Items` 组件有一个默认 `quantity` prop,其值被设置为整数 `0`。 通过传入数值 `10` 来覆盖 `quantity` 的默认 prop。
|
||||||
|
|
||||||
**Note:** Remember that the syntax to add a prop to a component looks similar to how you add HTML attributes. However, since the value for `quantity` is an integer, it won't go in quotes but it should be wrapped in curly braces. For example, `{100}`. This syntax tells JSX to interpret the value within the braces directly as JavaScript.
|
**注意:** 请记住,向组件添加 prop 的语法与添加 HTML 属性类似。 但是,由于 `quantity` 的值是整数,所以它不会加引号,但应该用花括号括起来, 例如`{100}`。 这个语法告诉 JSX 直接将花括号中的值解释为 JavaScript。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The component `ShoppingCart` should render.
|
应该渲染 `ShoppingCart` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The component `Items` should render.
|
应该渲染 `Items` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Items` component should have a prop of `{ quantity: 10 }` passed from the `ShoppingCart` component.
|
`Items` 组件应该有一个 `{ quantity: 10 }` 的 prop,该 prop 是从 `ShoppingCart` 组件传递过去的。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403617b
|
id: 5a24c314108439a4d403617b
|
||||||
title: Pass a Callback as Props
|
title: 传递回调作为 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301400
|
forumTopicId: 301400
|
||||||
dashedName: pass-a-callback-as-props
|
dashedName: pass-a-callback-as-props
|
||||||
@ -8,17 +8,17 @@ dashedName: pass-a-callback-as-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You can pass `state` as props to child components, but you're not limited to passing data. You can also pass handler functions or any method that's defined on a React component to a child component. This is how you allow child components to interact with their parent components. You pass methods to a child just like a regular prop. It's assigned a name and you have access to that method name under `this.props` in the child component.
|
可以将 `state` 作为 props 传递给子组件,但不仅限于传递数据。 也可以将函数或在 React 组件中定义的任何方法传递给子组件。 这就是子组件与父组件交互的方式。 可以把方法像普通 prop 一样传递给子组件, 它会被分配一个名字,可以在子组件中的 `this.props` 下访问该方法的名字。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There are three components outlined in the code editor. The `MyApp` component is the parent that will render the `GetInput` and `RenderInput` child components. Add the `GetInput` component to the render method in `MyApp`, then pass it a prop called `input` assigned to `inputValue` from `MyApp`'s `state`. Also create a prop called `handleChange` and pass the input handler `handleChange` to it.
|
代码编辑器中列出了三个组件。 `MyApp` 是父组件,`GetInput` 和`RenderInput` 是它将要渲染的子组件。 将 `GetInput` 组件添加到 `MyApp` 的 render 方法,然后将 `MyApp` 的 `state` 中的 `inputValue` 传入名为 `input` 的 prop。 还要创建一个名为 `handleChange` 的 prop,并将输入处理程序 `handleChange` 传递给它。
|
||||||
|
|
||||||
Next, add `RenderInput` to the render method in `MyApp`, then create a prop called `input` and pass the `inputValue` from `state` to it. Once you are finished you will be able to type in the `input` field in the `GetInput` component, which then calls the handler method in its parent via props. This updates the input in the `state` of the parent, which is passed as props to both children. Observe how the data flows between the components and how the single source of truth remains the `state` of the parent component. Admittedly, this example is a bit contrived, but should serve to illustrate how data and callbacks can be passed between React components.
|
接下来,将 `RenderInput` 添加到 `MyApp` 中的 render 方法中,然后创建一个名为 `input` 的 prop,并将 `state` 中的 `inputValue` 传递给它。 完成后,可以在 `GetInput` 组件中的 `input` 字段中键入内容,然后该组件通过 props 调用其父组件中的处理函数方法。 这将更新处于父组件 `state` 中的 input,该 input 将作为 props 传递给两个子组件。 观察数据如何在组件之间流动,以及单一数据源如何保持父组件`state`。 诚然,这个示例有点做作,但是应该能用来说明数据和回调是如何在 React 组件之间传递的。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `MyApp` component should render.
|
应该渲染 `MyApp` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `GetInput` component should render.
|
应该渲染 `GetInput` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,7 +40,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `RenderInput` component should render.
|
应该渲染 `RenderInput` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -51,7 +51,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `GetInput` component should receive the `MyApp` state property `inputValue` as props and contain an `input` element which modifies `MyApp` state.
|
`GetInput` 组件应该接收 `MyApp` 的 state 属性 `inputValue` 作为 props,并包含一个修改 `MyApp` state 的 `input` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -74,7 +74,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The `RenderInput` component should receive the `MyApp` state property `inputValue` as props.
|
`RenderInput` 组件应该接收 `MyApp` state 属性 `inputValue` 作为 props。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616a
|
id: 5a24c314108439a4d403616a
|
||||||
title: Pass an Array as Props
|
title: 传递一个数组作为 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301401
|
forumTopicId: 301401
|
||||||
dashedName: pass-an-array-as-props
|
dashedName: pass-an-array-as-props
|
||||||
@ -8,7 +8,7 @@ dashedName: pass-an-array-as-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last challenge demonstrated how to pass information from a parent component to a child component as `props` or properties. This challenge looks at how arrays can be passed as `props`. To pass an array to a JSX element, it must be treated as JavaScript and wrapped in curly braces.
|
上一个挑战演示了如何将来自父组件的信息作为 `props` 传递给子组件。 这个挑战着眼于如何将数组作为 `props` 传递。 要将数组传递给 JSX 元素,必须将其视为 JavaScript 并用花括号括起来。
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<ParentComponent>
|
<ParentComponent>
|
||||||
@ -16,15 +16,15 @@ The last challenge demonstrated how to pass information from a parent component
|
|||||||
</ParentComponent>
|
</ParentComponent>
|
||||||
```
|
```
|
||||||
|
|
||||||
The child component then has access to the array property `colors`. Array methods such as `join()` can be used when accessing the property. `const ChildComponent = (props) => <p>{props.colors.join(', ')}</p>` This will join all `colors` array items into a comma separated string and produce: `<p>green, blue, red</p>` Later, we will learn about other common methods to render arrays of data in React.
|
这样,子组件就可以访问数组属性 `colors`。 访问属性时可以使用 `join()` 等数组方法。 `const ChildComponent = (props) => <p>{props.colors.join(', ')}</p>` 这将把所有 `colors` 数组项连接成一个逗号分隔的字符串并生成: `<p>green, blue, red</p>` 稍后,我们将了解在 React 中渲染数组数据的其他常用方法。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There are `List` and `ToDo` components in the code editor. When rendering each `List` from the `ToDo` component, pass in a `tasks` property assigned to an array of to-do tasks, for example `["walk dog", "workout"]`. Then access this `tasks` array in the `List` component, showing its value within the `p` element. Use `join(", ")` to display the `props.tasks`array in the `p` element as a comma separated list. Today's list should have at least 2 tasks and tomorrow's should have at least 3 tasks.
|
代码编辑器中有 `List` 和 `ToDo` 组件。 在 `ToDo` 组件中渲染每个 `List` 时,传入 `tasks` 属性并将其分配给待办任务数组,例如 `["walk dog", "workout"]`。 然后访问 `List` 组件中的 `tasks` 数组,在`p`元素中显示其值。 使用 `join(", ")` 把 `props.tasks` 数组作为逗号分隔列表显示在 `p` 元素中。 今天的列表应该至少有 2 个任务,明天的列表应该至少有 3 个任务。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `ToDo` component should return a single outer `div`.
|
`ToDo` 组件应该返回单个外部 `div`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -35,7 +35,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The third child of the `ToDo` component should be an instance of the `List` component.
|
`ToDo` 组件的第三个子元素应该是 `List` 组件的一个实例。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -46,7 +46,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The fifth child of the `ToDo` component should be an instance of the `List` component.
|
`ToDo` 组件的第五个子元素应该是 `List` 组件的一个实例。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -57,7 +57,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Both instances of the `List` component should have a property called `tasks` and `tasks` should be of type array.
|
`List` 组件的两个实例都应该具有一个名为 `tasks` 的属性,并且 `tasks` 的类型应该是数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -71,7 +71,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The first `List` component representing the tasks for today should have 2 or more items.
|
表示今天任务的第一个 `List` 组件应该有 2 个或更多项。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -82,7 +82,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The second `List` component representing the tasks for tomorrow should have 3 or more items.
|
表示明天任务的第二个 `List` 组件应该有 3 个或更多项。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -93,7 +93,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `List` component should render the value from the `tasks` prop in the `p` tag.
|
`List` 组件应在 `p` 标签中渲染 `tasks` 属性的值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036169
|
id: 5a24c314108439a4d4036169
|
||||||
title: Pass Props to a Stateless Functional Component
|
title: 将 Props 传递给无状态函数组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301402
|
forumTopicId: 301402
|
||||||
dashedName: pass-props-to-a-stateless-functional-component
|
dashedName: pass-props-to-a-stateless-functional-component
|
||||||
@ -8,7 +8,7 @@ dashedName: pass-props-to-a-stateless-functional-component
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The previous challenges covered a lot about creating and composing JSX elements, functional components, and ES6 style class components in React. With this foundation, it's time to look at another feature very common in React: **props**. In React, you can pass props, or properties, to child components. Say you have an `App` component which renders a child component called `Welcome` which is a stateless functional component. You can pass `Welcome` a `user` property by writing:
|
之前的挑战涵盖了关于在 React 中创建和组合 JSX 元素、函数组件和 ES6 风格的类组件的很多内容。 有了这个基础,现在是时候看看 React 中的另一个常见特性 **props** 了。 在 React 中,可以将属性传递给子组件。 假设有一个 `App` 组件,该组件渲染了一个名为 `Welcome` 的子组件,它是一个无状态函数组件。 可以通过以下方式给 `Welcome` 传递一个 `user` 属性:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<App>
|
<App>
|
||||||
@ -16,21 +16,21 @@ The previous challenges covered a lot about creating and composing JSX elements,
|
|||||||
</App>
|
</App>
|
||||||
```
|
```
|
||||||
|
|
||||||
You use **custom HTML attributes** created by you and supported by React to be passed to the component. In this case, the created property `user` is passed to the component `Welcome`. Since `Welcome` is a stateless functional component, it has access to this value like so:
|
可以把创建的 React 支持的**自定义 HTML 属性**传递给组件, 在上面的例子里,将创建的属性 `user` 传递给组件 `Welcome`。 由于 `Welcome` 是一个无状态函数组件,它可以像这样访问该值:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const Welcome = (props) => <h1>Hello, {props.user}!</h1>
|
const Welcome = (props) => <h1>Hello, {props.user}!</h1>
|
||||||
```
|
```
|
||||||
|
|
||||||
It is standard to call this value `props` and when dealing with stateless functional components, you basically consider it as an argument to a function which returns JSX. You can access the value of the argument in the function body. With class components, you will see this is a little different.
|
调用 `props` 这个值是常见做法,当处理无状态函数组件时,基本上可以将其视为返回 JSX 的函数的参数。 这样,你就可以在函数体中访问该值。 但对于类组件,访问方式会略有不同。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There are `Calendar` and `CurrentDate` components in the code editor. When rendering `CurrentDate` from the `Calendar` component, pass in a property of `date` assigned to the current date from JavaScript's `Date` object. Then access this `prop` in the `CurrentDate` component, showing its value within the `p` tags. Note that for `prop` values to be evaluated as JavaScript, they must be enclosed in curly brackets, for instance `date={Date()}`.
|
代码编辑器中有 `Calendar` 和 `CurrentDate` 组件。 从 `Calendar` 组件渲染 `CurrentDate` 时,从 JavaScript 的 `Date` 对象分配当前日期,并将其作为 `date` 属性传入。 然后访问 `CurrentDate` 组件的 `prop`,并在 `p` 标签中显示其值。 请注意,要将 `prop` 的值视为 JavaScript,必须将它们括在花括号中,例如`date={Date()}`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `Calendar` component should return a single `div` element.
|
`Calendar` 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -41,7 +41,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The second child of the `Calendar` component should be the `CurrentDate` component.
|
`Calendar` 组件的第二个子元素应该是 `CurrentDate` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -52,7 +52,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `CurrentDate` component should have a prop called `date`.
|
`CurrentDate` 组件应该有一个名为 `date` 的属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -63,7 +63,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `date` prop of the `CurrentDate` should contain a string of text.
|
`CurrentDate` 的 `date` 属性应该包含一段文本字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -75,13 +75,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `date` prop should be generated by calling `Date()`
|
`date` prop 应由调用 `Date()` 生成。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(/<CurrentDatedate={Date\(\)}\/>/.test(__helpers.removeWhiteSpace(code)));
|
assert(/<CurrentDatedate={Date\(\)}\/>/.test(__helpers.removeWhiteSpace(code)));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `CurrentDate` component should render the value from the `date` prop in the `p` tag.
|
`CurrentDate` 组件应该把 `date` 属性渲染在 `p` 标签内。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let date = 'dummy date';
|
let date = 'dummy date';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403617a
|
id: 5a24c314108439a4d403617a
|
||||||
title: Pass State as Props to Child Components
|
title: 将 State 作为 Props 传递给子组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301403
|
forumTopicId: 301403
|
||||||
dashedName: pass-state-as-props-to-child-components
|
dashedName: pass-state-as-props-to-child-components
|
||||||
@ -8,19 +8,19 @@ dashedName: pass-state-as-props-to-child-components
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You saw a lot of examples that passed props to child JSX elements and child React components in previous challenges. You may be wondering where those props come from. A common pattern is to have a stateful component containing the `state` important to your app, that then renders child components. You want these components to have access to some pieces of that `state`, which are passed in as props.
|
在之前的挑战中,看到了很多将 props 传递给子 JSX 元素和子 React 组件的例子。 你可能想知道那些 props 是从哪里来的。 一个常见的模式是:有状态组件中包含对应用程序很重要的 `state`,然后用它渲染子组件。 如果想让这些组件能够访问该 `state` 的某些部分,就把这些部分作为 props 传入。
|
||||||
|
|
||||||
For example, maybe you have an `App` component that renders a `Navbar`, among other components. In your `App`, you have `state` that contains a lot of user information, but the `Navbar` only needs access to the user's username so it can display it. You pass that piece of `state` to the `Navbar` component as a prop.
|
例如,有一个 `App` 组件可以渲染 `Navbar` 以及其他组件。 `App` 里的 `state` 包含大量用户信息,但 `Navbar` 只需要访问用户的用户名,以便显示它。 将该 `state` 作为 prop 传递给`Navbar`组件。
|
||||||
|
|
||||||
This pattern illustrates some important paradigms in React. The first is *unidirectional data flow*. State flows in one direction down the tree of your application's components, from the stateful parent component to child components. The child components only receive the state data they need. The second is that complex stateful apps can be broken down into just a few, or maybe a single, stateful component. The rest of your components simply receive state from the parent as props, and render a UI from that state. It begins to create a separation where state management is handled in one part of code and UI rendering in another. This principle of separating state logic from UI logic is one of React's key principles. When it's used correctly, it makes the design of complex, stateful applications much easier to manage.
|
这个模式说明了 React 中的一些重要范例。 第一个是*单向数据流*, state 沿着应用程序组件树的一个方向流动,从有状态父组件到子组件, 子组件只接收它们需要的 state 数据。 第二,复杂的有状态应用程序可以分解成几个,或者可能是一个单一的有状态组件。 其余组件只是从父组件简单的接收 state 作为 props,并从该 state 渲染 UI。 它开始创建一种分离,在这种分离中,state 管理在代码的一部分中处理,而 UI 渲染在另一部分中处理。 将 state 逻辑与 UI 逻辑分离是 React 的关键原则之一。 当它被正确使用时,它使得复杂的、有状态的应用程序的设计变得更容易管理。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `MyApp` component is stateful and renders a `Navbar` component as a child. Pass the `name` property in its `state` down to the child component, then show the `name` in the `h1` tag that's part of the `Navbar` render method. `name` should appear after the text `Hello, my name is:`.
|
`MyApp` 组件是有状态的,并将 `Navbar` 组件渲染为子组件。 将 `state` 的 `name` 属性向下传递给子组件,然后在 `h1` 中显示该 `name` ,h1 是 `Navbar` render方法的一部分。 `name` 应该显示在文本 `Hello, my name is:` 后面。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `MyApp` component should render with a `Navbar` component inside.
|
`MyApp` 组件应该在内部渲染一个 `Navbar` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -34,7 +34,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Navbar` component should receive the `MyApp` state property `name` as props.
|
`Navbar` 组件应该接收 `MyApp` 的 state 中的 `name` 属性作为 props。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -50,7 +50,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The `h1` element in `Navbar` should render the `name` prop.
|
`Navbar` 中的 `h1`元素应该渲染 prop `name`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036167
|
id: 5a24c314108439a4d4036167
|
||||||
title: Render a Class Component to the DOM
|
title: 将 class 组件渲染到 DOM 树
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301404
|
forumTopicId: 301404
|
||||||
dashedName: render-a-class-component-to-the-dom
|
dashedName: render-a-class-component-to-the-dom
|
||||||
@ -8,19 +8,19 @@ dashedName: render-a-class-component-to-the-dom
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You may remember using the ReactDOM API in an earlier challenge to render JSX elements to the DOM. The process for rendering React components will look very similar. The past few challenges focused on components and composition, so the rendering was done for you behind the scenes. However, none of the React code you write will render to the DOM without making a call to the ReactDOM API.
|
还记不记得在之前的挑战中使用 ReactDOM API 将 JSX 元素渲染到 DOM, 这与渲染 React 组件的过程十分相似。 过去的几个挑战主要针对组件和组合,因此渲染是在幕后完成的。 但是,如果不调用 ReactDOM API,编写的任何 React 代码都不会渲染到 DOM。
|
||||||
|
|
||||||
Here's a refresher on the syntax: `ReactDOM.render(componentToRender, targetNode)`. The first argument is the React component that you want to render. The second argument is the DOM node that you want to render that component within.
|
复习一下语法: `ReactDOM.render(componentToRender, targetNode)`。 第一个参数是要渲染的 React 组件。 第二个参数是要在其中渲染该组件的 DOM 节点。
|
||||||
|
|
||||||
React components are passed into `ReactDOM.render()` a little differently than JSX elements. For JSX elements, you pass in the name of the element that you want to render. However, for React components, you need to use the same syntax as if you were rendering a nested component, for example `ReactDOM.render(<ComponentToRender />, targetNode)`. You use this syntax for both ES6 class components and functional components.
|
传递到`ReactDOM.render()` 的React 组件与 JSX 元素略有不同。 对于 JSX 元素,传入的是要渲染的元素的名称。 但是,对于 React 组件,需要使用与渲染嵌套组件相同的语法,例如`ReactDOM.render(<ComponentToRender />, targetNode)`。 此语法用于 ES6 class 组件和函数组件都可以。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Both the `Fruits` and `Vegetables` components are defined for you behind the scenes. Render both components as children of the `TypesOfFood` component, then render `TypesOfFood` to the DOM. There is a `div` with `id='challenge-node'` available for you to use.
|
在后台引入了 `Fruits` 和 `Vegetables` 组件。 将两个组件渲染为 `TypesOfFood` 组件的子组件,然后将 `TypesOfFood` 渲染到 DOM 节点, 在这个挑战中,请渲染到 `id='challenge-node'`的 `div` 中。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `TypesOfFood` component should return a single `div` element.
|
`TypesOfFood` 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,7 +31,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should render the `Fruits` component after the `h1` element.
|
`TypesOfFood` 组件应该在 `h1` 元素之后渲染 `Fruits` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -42,7 +42,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should render the `Vegetables` component after `Fruits`.
|
`TypesOfFood` 组件应该在 `Fruits` 组件之后渲染 `Vegetables` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -53,7 +53,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should render to the DOM within the `div` with the id `challenge-node`.
|
`TypesOfFood` 组件应该渲染到 id 为 `challenge-node` 的 `div`中。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036188
|
id: 5a24c314108439a4d4036188
|
||||||
title: Render Conditionally from Props
|
title: 根据 Props 有条件地渲染
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301405
|
forumTopicId: 301405
|
||||||
dashedName: render-conditionally-from-props
|
dashedName: render-conditionally-from-props
|
||||||
@ -8,21 +8,21 @@ dashedName: render-conditionally-from-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
So far, you've seen how to use `if/else`, `&&,` `null` and the ternary operator (`condition ? expressionIfTrue : expressionIfFalse`) to make conditional decisions about what to render and when. However, there's one important topic left to discuss that lets you combine any or all of these concepts with another powerful React feature: props. Using props to conditionally render code is very common with React developers — that is, they use the value of a given prop to automatically make decisions about what to render.
|
到目前为止,已经看到了如何使用 `if/else`、`&&`和三元运算符(`condition ? expressionIfTrue : expressionIfFalse`)对渲染什么和何时渲染做出有条件的判定。 然而,还有一个重要的话题需要讨论,将这些概念中的任何一个或所有概念与另一个强大的 React 功能结合起来:props。 使用 props 有条件地渲染代码在 React 开发人员中很常见 -- 也就是说:他们使用给定 prop 的值来自动决定渲染什么。
|
||||||
|
|
||||||
In this challenge, you'll set up a child component to make rendering decisions based on props. You'll also use the ternary operator, but you can see how several of the other concepts that were covered in the last few challenges might be just as useful in this context.
|
在这个挑战中,将设置一个子组件来根据 props 做出渲染决定。 可以使用三元运算符,但是可以看到过去几个挑战中涵盖的其他几个概念在这种情况下可能同样有用。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has two components that are partially defined for you: a parent called `GameOfChance`, and a child called `Results`. They are used to create a simple game where the user presses a button to see if they win or lose.
|
代码编辑器有两个部分为你定义的组件:一个名为 `GameOfChance` 的父组件和一个名为 `Results` 的子组件。 它们被用来创建一个简单的游戏,用户按下按钮来看它们是赢还是输。
|
||||||
|
|
||||||
First, you'll need a simple expression that randomly returns a different value every time it is run. You can use `Math.random()`. This method returns a value between `0` (inclusive) and `1` (exclusive) each time it is called. So for 50/50 odds, use `Math.random() >= .5` in your expression. Statistically speaking, this expression will return `true` 50% of the time, and `false` the other 50%. In the render method, replace `null` with the above expression to complete the variable declaration.
|
首先,需要一个简单的表达式,每次运行时都会随机返回一个不同的值。 可以使用 `Math.random()`。 每次调用此方法时,此方法返回 `0`(包括)和 `1`(不包括)之间的值。 因此,对于50/50的几率,请在表达式中使用 `Math.random() >= .5`。 从统计学上讲,这个表达式有 50% 的几率返回 `true`,另外 50% 返回 `false`。 在第 render 方法里,用此表达式替换 `null` 以完成变量声明。
|
||||||
|
|
||||||
Now you have an expression that you can use to make a randomized decision in the code. Next you need to implement this. Render the `Results` component as a child of `GameOfChance`, and pass in `expression` as a prop called `fiftyFifty`. In the `Results` component, write a ternary expression to render the `h1` element with the text `"You Win!"` or `"You Lose!"` based on the `fiftyFifty` prop that's being passed in from `GameOfChance`. Finally, make sure the `handleClick()` method is correctly counting each turn so the user knows how many times they've played. This also serves to let the user know the component has actually updated in case they win or lose twice in a row.
|
现在了一个表达式,可以使用该表达式在代码中做出随机决策。 接下来,需要实现此功能。 将 `Results` 组件渲染为 `GameOfChance` 的子 组件,并将 `expression` 作为名为 `fiftyFifty` 的 prop 传入 。 在 `Results` 组件中,编写一个三元表达式来渲染 `h1` 元素的文本。`GameOfChance` 传来的 prop `fiftyFifty` 来决定渲染文本 `You Win!` 还是 `You Lose!`。 最后,确保 `handleClick()` 方法正确计算每个回合,以便用户知道他们玩过多少次。 这也可以让用户知道组件实际上已经更新,以防他们连续赢两次或输两次时自己不知道。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `GameOfChance` component should exist and render to the page.
|
`GameOfChance` 组件应该存在并渲染到页面。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -31,7 +31,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`GameOfChance` should return a single `button` element.
|
`GameOfChance` 应该返回单个 `button` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -40,7 +40,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`GameOfChance` should return a single instance of the `Results` component, which has a prop called `fiftyFifty`.
|
`GameOfChance` 应该返回 `Results` 组件的一个实例,它有一个名为 `fiftyFifty` 的 prop。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -53,7 +53,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`GameOfChance` state should be initialized with a property of `counter` set to a value of `1`.
|
`GameOfChance` 的 state 应该使用值为 `1` 的 `counter` 属性来初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -62,7 +62,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When the `GameOfChance` component is first rendered to the DOM, a `p` element should be returned with the inner text of `Turn: 1`.
|
当 `GameOfChance` 组件第一次渲染到 DOM 时,应该返回一个 `p` 元素,其内部文本为 `Turn: 1`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -71,7 +71,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Each time the button is clicked, the counter state should be incremented by a value of 1, and a single `p` element should be rendered to the DOM that contains the text "Turn: N", where N is the value of the counter state.
|
每次点击按钮,counter 应该增加 1,并且一个包含文本 `Turn: N` 的 `p` 元素应该渲染到 DOM,其中 `N` 是 counter 的值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -123,7 +123,7 @@ Each time the button is clicked, the counter state should be incremented by a va
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
When the `GameOfChance` component is first mounted to the DOM and each time the button is clicked thereafter, a single `h1` element should be returned that randomly renders either `You Win!` or `You Lose!`.
|
当 `GameOfChance` 组件第一次挂载到 DOM 上时,每次按钮被点击,都应该返回一个 `h1` 元素,元素中随机渲染 `You Win!` 或者 `You Lose!`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24bbe0dba28a8d3cbd4c5f
|
id: 5a24bbe0dba28a8d3cbd4c5f
|
||||||
title: Render HTML Elements to the DOM
|
title: 渲染 HTML 元素为 DOM 树
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301406
|
forumTopicId: 301406
|
||||||
dashedName: render-html-elements-to-the-dom
|
dashedName: render-html-elements-to-the-dom
|
||||||
@ -8,37 +8,37 @@ dashedName: render-html-elements-to-the-dom
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
So far, you've learned that JSX is a convenient tool to write readable HTML within JavaScript. With React, we can render this JSX directly to the HTML DOM using React's rendering API known as ReactDOM.
|
到目前为止,已经了解到 JSX 是一种在 JavaScript 中编写可读 HTML 的便捷工具。 在 React 中,可以使用它的的渲染 API(ReactDOM)将此 JSX 直接渲染到 HTML DOM。
|
||||||
|
|
||||||
ReactDOM offers a simple method to render React elements to the DOM which looks like this: `ReactDOM.render(componentToRender, targetNode)`, where the first argument is the React element or component that you want to render, and the second argument is the DOM node that you want to render the component to.
|
ReactDOM 提供了一个简单的方法来将 React 元素呈现给 DOM,如下所示:`ReactDOM.render(componentToRender, targetNode)`,其中第一个参数是要渲染的 React 元素或组件,第二个参数是组件将要渲染到的 DOM 节点。
|
||||||
|
|
||||||
As you would expect, `ReactDOM.render()` must be called after the JSX element declarations, just like how you must declare variables before using them.
|
如你所料,必须在 JSX 元素声明之后调用 `ReactDOM.render()`,就像在使用变量之前必须声明它一样。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a simple JSX component. Use the `ReactDOM.render()` method to render this component to the page. You can pass defined JSX elements directly in as the first argument and use `document.getElementById()` to select the DOM node to render them to. There is a `div` with `id='challenge-node'` available for you to use. Make sure you don't change the `JSX` constant.
|
代码编辑器有一个简单的 JSX 组件。 使用 `ReactDOM.render()` 方法将该组件渲染到页面。 可以将定义好的 JSX 元素直接作为第一个参数传入,然后使用 `document.getElementById()` 来选择要渲染到的 DOM 节点, 在这个挑战中,请渲染到 `id='challenge-node'` 的 `div` 中。 确保没有修改 `JSX` 常量。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The constant `JSX` should return a `div` element.
|
常量 `JSX` 应该返回一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.type === 'div');
|
assert(JSX.type === 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain an `h1` tag as the first element.
|
`div` 应该包含一个 `h1` 标签作为第一个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[0].type === 'h1');
|
assert(JSX.props.children[0].type === 'h1');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `div` should contain a `p` tag as the second element.
|
`div` 应该包含一个 `p` 标签作为第二个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(JSX.props.children[1].type === 'p');
|
assert(JSX.props.children[1].type === 'p');
|
||||||
```
|
```
|
||||||
|
|
||||||
The provided JSX element should render to the DOM node with id `challenge-node`.
|
提供的 JSX 元素应该渲染到 id 为 `challenge-node` 的 DOM 节点。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403618d
|
id: 5a24c314108439a4d403618d
|
||||||
title: Render React on the Server with renderToString
|
title: 用 renderToString 在服务器上渲染 React
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301407
|
forumTopicId: 301407
|
||||||
dashedName: render-react-on-the-server-with-rendertostring
|
dashedName: render-react-on-the-server-with-rendertostring
|
||||||
@ -8,17 +8,17 @@ dashedName: render-react-on-the-server-with-rendertostring
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
So far, you have been rendering React components on the client. Normally, this is what you will always do. However, there are some use cases where it makes sense to render a React component on the server. Since React is a JavaScript view library and you can run JavaScript on the server with Node, this is possible. In fact, React provides a `renderToString()` method you can use for this purpose.
|
到目前为止,已经能够在客户端上渲染 React 组件, 一般来说我们都是这么做的。 然而,在一些用例中,需要在服务器上渲染一个 React 组件。 由于 React 是一个 JavaScript 视图库,所以通常使用 Node 让 JavaScript 运行在服务器上。 事实上,React 提供了一个可用于此目的的 `renderToString()` 方法。
|
||||||
|
|
||||||
There are two key reasons why rendering on the server may be used in a real world app. First, without doing this, your React apps would consist of a relatively empty HTML file and a large bundle of JavaScript when it's initially loaded to the browser. This may not be ideal for search engines that are trying to index the content of your pages so people can find you. If you render the initial HTML markup on the server and send this to the client, the initial page load contains all of the page's markup which can be crawled by search engines. Second, this creates a faster initial page load experience because the rendered HTML is smaller than the JavaScript code of the entire app. React will still be able to recognize your app and manage it after the initial load.
|
有两个关键原因可以解释为什么服务器上的渲染可能会在真实世界的应用程序中使用。 首先,如果不这样做,当 React 应用程序最初加载到浏览器时,它将包含一个代码量很少的 HTML 文件和一大堆 JavaScript。 这对于搜索引擎来说可能不太理想,因为它们试图为网页内容生成索引,以便人们可以找到这个应用。 如果在服务器上渲染初始 HTML 标记并将其发送到客户端,则初始页面加载的内容包含搜索引擎可以抓取的所有页面标记。 其次,这创造了更快的初始页面加载体验,因为渲染的 HTML 代码量要比整个应用程序的 JavaScript 代码小。 React 仍然能够识别你的应用并在初始加载后进行管理。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `renderToString()` method is provided on `ReactDOMServer`, which is available here as a global object. The method takes one argument which is a React element. Use this to render `App` to a string.
|
`renderToString()` 方法由 `ReactDOMServer` 提供,在这里已为你定义成全局变量。 这个方法接收一个 React 元素作为参数。 用它来把 `App` 渲染成字符串。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `App` component should render to a string using `ReactDOMServer.renderToString`.
|
`App` 组件应该使用 `ReactDOMServer.renderToString` 渲染一个字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036172
|
id: 5a24c314108439a4d4036172
|
||||||
title: Render State in the User Interface Another Way
|
title: 以另一种方式在用户界面中渲染状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301408
|
forumTopicId: 301408
|
||||||
dashedName: render-state-in-the-user-interface-another-way
|
dashedName: render-state-in-the-user-interface-another-way
|
||||||
@ -8,17 +8,17 @@ dashedName: render-state-in-the-user-interface-another-way
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
There is another way to access `state` in a component. In the `render()` method, before the `return` statement, you can write JavaScript directly. For example, you could declare functions, access data from `state` or `props`, perform computations on this data, and so on. Then, you can assign any data to variables, which you have access to in the `return` statement.
|
还有另一种方法可以访问组件中的 `state`。 在 `render()` 方法中,在 `return` 语句之前,可以直接编写 JavaScript。 例如,可以声明函数、从 `state` 或 `props` 中访问数据、对此数据执行计算等。 然后,可以将任何数据赋值给 `return` 语句中可以访问的变量。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the `MyComponent` render method, define a `const` called `name` and set it equal to the name value in the component's `state`. Because you can write JavaScript directly in this part of the code, you don't have to enclose this reference in curly braces.
|
在 `MyComponent` 的 render 方法中,定义一个名为 `name` 的 `const`(常量),并将其设置为组件 `state` 中的 name 值。 因为可以直接在代码部分编写 JavaScript,所以不需要用大括号括起来。
|
||||||
|
|
||||||
Next, in the return statement, render this value in an `h1` tag using the variable `name`. Remember, you need to use the JSX syntax (curly braces for JavaScript) in the return statement.
|
接下来,在 return 语句中,在 `h1` 标签中渲染变量 `name` 的值。 记住,在 return 语句中需要使用 JSX 语法(用到 JavaScript 的花括号)。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should have a key `name` with value `freeCodeCamp` stored in its state.
|
`MyComponent` 应该有一个键 `name`,其值 `freeCodeCamp` 存储在其 state 中。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -27,7 +27,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should render an `h1` header enclosed in a single `div`.
|
`MyComponent` 应该在 `div` 中渲染一个 `h1` 标题。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -37,14 +37,14 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The rendered `h1` tag should include a reference to `{name}`.
|
渲染的 `h1` 标签应该包含 `{name}` 的引用。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
assert(/<h1>\n*\s*\{\s*name\s*\}\s*\n*<\/h1>/.test(getUserInput('index')));
|
assert(/<h1>\n*\s*\{\s*name\s*\}\s*\n*<\/h1>/.test(getUserInput('index')));
|
||||||
```
|
```
|
||||||
|
|
||||||
The rendered `h1` header should contain text rendered from the component's state.
|
渲染的 `h1` 标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036171
|
id: 5a24c314108439a4d4036171
|
||||||
title: Render State in the User Interface
|
title: 在用户界面中渲染状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301409
|
forumTopicId: 301409
|
||||||
dashedName: render-state-in-the-user-interface
|
dashedName: render-state-in-the-user-interface
|
||||||
@ -8,23 +8,23 @@ dashedName: render-state-in-the-user-interface
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Once you define a component's initial state, you can display any part of it in the UI that is rendered. If a component is stateful, it will always have access to the data in `state` in its `render()` method. You can access the data with `this.state`.
|
定义了组件的初始 state 之后,就可以在要渲染的 UI 中显示它。 如果组件是有状态的,它将始终可以访问 `render()` 方法中 `state` 的数据。 就可以使用 `this.state` 访问数据。
|
||||||
|
|
||||||
If you want to access a state value within the `return` of the render method, you have to enclose the value in curly braces.
|
如果想在 render 方法的 `return` 中访问 state 值,必须把这个值用花括号括起来。
|
||||||
|
|
||||||
`State` is one of the most powerful features of components in React. It allows you to track important data in your app and render a UI in response to changes in this data. If your data changes, your UI will change. React uses what is called a virtual DOM, to keep track of changes behind the scenes. When state data updates, it triggers a re-render of the components using that data - including child components that received the data as a prop. React updates the actual DOM, but only where necessary. This means you don't have to worry about changing the DOM. You simply declare what the UI should look like.
|
`state` 是 React 组件中最强大的特性之一, 它可以跟踪应用程序中的重要数据,并根据数据的变化渲染 UI。 如果数据发生变化,UI 也会随之改变。 React 使用所谓的虚拟 DOM 来跟踪幕后的变化。 当 state 数据更新时,它会使用该数据触发组件的重新渲染 -- 包括接收 prop 数据的子组件。 React 只在必要的时候更新实际的 DOM, 这意味着你不必担心 DOM 的变更, 只需声明 UI 的外观即可。
|
||||||
|
|
||||||
Note that if you make a component stateful, no other components are aware of its `state`. Its `state` is completely encapsulated, or local to that component, unless you pass state data to a child component as `props`. This notion of encapsulated `state` is very important because it allows you to write certain logic, then have that logic contained and isolated in one place in your code.
|
注意,如果组件是有状态的,其它组件并不知道它的 `state`。 它的 `state` 是完全封装的,或者是局限于组件本身的,除非你将 state 数据作为 `props` 传递给子组件。 封装 `state` 的概念非常重要,因为它允许编写特定的逻辑,然后将该逻辑包含并隔离在代码中的某个位置。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the code editor, `MyComponent` is already stateful. Define an `h1` tag in the component's render method which renders the value of `name` from the component's state.
|
在代码编辑器中,`MyComponent` 是一个有状态组件, 在组件的 render 方法中定义一个`h1`标签,该方法从组件的 state 渲染 `name` 的值。
|
||||||
|
|
||||||
**Note:** The `h1` should only render the value from `state` and nothing else. In JSX, any code you write with curly braces `{ }` will be treated as JavaScript. So to access the value from `state` just enclose the reference in curly braces.
|
**注意:** `h1` 应该只渲染来自 `state` 的值。 在 JSX 中,使用花括号 `{ }` 编写的任何代码都将被视为 JavaScript。 因此,要访问 `state` 中的值,只需将引用括在花括号中即可。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should have a key `name` with value `freeCodeCamp` stored in its state.
|
`MyComponent` 应该有一个键 `name`,其值 `freeCodeCamp` 存储在其 state 中。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,7 +33,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should render an `h1` header enclosed in a single `div`.
|
`MyComponent` 应该在 `div` 中渲染一个 `h1` 标题。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -43,7 +43,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The rendered `h1` header should contain text rendered from the component's state.
|
渲染的 `h1` 标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036184
|
id: 5a24c314108439a4d4036184
|
||||||
title: Render with an If-Else Condition
|
title: 使用 If-Else 条件进行渲染
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301410
|
forumTopicId: 301410
|
||||||
dashedName: render-with-an-if-else-condition
|
dashedName: render-with-an-if-else-condition
|
||||||
@ -8,17 +8,17 @@ dashedName: render-with-an-if-else-condition
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Another application of using JavaScript to control your rendered view is to tie the elements that are rendered to a condition. When the condition is true, one view renders. When it's false, it's a different view. You can do this with a standard `if/else` statement in the `render()` method of a React component.
|
使用 JavaScript 控制渲染视图的另一个应用是按条件渲染元素。 当条件为真时,将呈现一个视图, 反之,则呈现另一种视图。 可以在 React 组件的 `render()` 方法中使用的标准 `if/else` 语句来实现这一点。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
MyComponent contains a `boolean` in its state which tracks whether you want to display some element in the UI or not. The `button` toggles the state of this value. Currently, it renders the same UI every time. Rewrite the `render()` method with an `if/else` statement so that if `display` is `true`, you return the current markup. Otherwise, return the markup without the `h1` element.
|
MyComponent 的 state 中包含一个 `boolean`(布尔值),用于跟踪是否要在 UI 中显示某个元素。 `button` 切换此值的状态。 目前,它每次都呈现相同的 UI。 用 `if/else` 语句重写 `render()` 方法,如果 `display` 为 `true` 则返回当前标记。 否则,返回不带 `h1` 元素的标记。
|
||||||
|
|
||||||
**Note:** You must write an `if/else` to pass the tests. Use of the ternary operator will not pass here.
|
**注意:** 写 `if/else` 语句才能通过测试, 使用三元运算符是不会通过的。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should exist and render.
|
`MyComponent` 应该存在并被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When `display` is set to `true`, a `div`, `button`, and `h1` should render.
|
当 `display` 被设置为 `true` 时,`div`、`button` 和 `h1` 标签应该被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -50,7 +50,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
When `display` is set to `false`, only a `div` and `button` should render.
|
当 `display` 被设置为 `false` 时,只有 `div` 和 `button` 应该被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -71,7 +71,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The render method should use an `if/else` statement to check the condition of `this.state.display`.
|
Render 方法中应该使用 `if/else` 语句来检查 `this.state.display` 的条件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616f
|
id: 5a24c314108439a4d403616f
|
||||||
title: Review Using Props with Stateless Functional Components
|
title: 复习使用无状态函数组件的 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301411
|
forumTopicId: 301411
|
||||||
dashedName: review-using-props-with-stateless-functional-components
|
dashedName: review-using-props-with-stateless-functional-components
|
||||||
@ -8,19 +8,19 @@ dashedName: review-using-props-with-stateless-functional-components
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Except for the last challenge, you've been passing props to stateless functional components. These components act like pure functions. They accept props as input and return the same view every time they are passed the same props. You may be wondering what state is, and the next challenge will cover it in more detail. Before that, here's a review of the terminology for components.
|
除了上一个挑战,一直在将 props 传递给无状态的函数组件。 这些组件就像纯函数, 它们接收 props 作为输入,并在每次传递相同 props 时返回相同的视图。 你可能好奇什么是状态,下一个挑战将会更详细地讲述它。 在此之前,我们先来回顾一下组件的术语。
|
||||||
|
|
||||||
A *stateless functional component* is any function you write which accepts props and returns JSX. A *stateless component*, on the other hand, is a class that extends `React.Component`, but does not use internal state (covered in the next challenge). Finally, a *stateful component* is a class component that does maintain its own internal state. You may see stateful components referred to simply as components or React components.
|
*无状态函数组件*是一个函数,它接收 props 作为输入并返回 JSX。 另一方面,*无状态组件*是一个类,它扩展了`React.Component`,但是不使用内部状态(下一个挑战中讨论)。 最后,*状态组件*是指维护其自身内部状态的组件, 它简称组件或 React 组件。
|
||||||
|
|
||||||
A common pattern is to try to minimize statefulness and to create stateless functional components wherever possible. This helps contain your state management to a specific area of your application. In turn, this improves development and maintenance of your app by making it easier to follow how changes to state affect its behavior.
|
一种常见的应用模式是尽可能减少状态组件并创建无状态的函数组件。 这有助于将状态管理包含到应用程序的特定区域。 反过来,通过更容易地跟踪状态变化如何影响其行为,可以改善应用程序的开发和维护。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has a `CampSite` component that renders a `Camper` component as a child. Define the `Camper` component and assign it default props of `{ name: 'CamperBot' }`. Inside the `Camper` component, render any code that you want, but make sure to have one `p` element that includes only the `name` value that is passed in as a `prop`. Finally, define `propTypes` on the `Camper` component to require `name` to be provided as a prop and verify that it is of type `string`.
|
在代码编辑器中有一个 `CampSite` 组件,它把 `Camper` 组件渲染为自己的子组件。 定义 `Camper` 组件,并为其分配默认 props `{ name: 'CamperBot' }`。 可以在 `Camper` 组件内部渲染任何你想要的代码,但是要确保有一个 `p` 元素,它只包含作为 `prop` 传递的 `name` 值。 最后,在 `Camper` 组件上定义 `propTypes`,要求提供 `name` 作为 prop,并验证它是 `string` 类型。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `CampSite` component should render.
|
应该渲染 `CampSite` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,7 +31,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Camper` component should render.
|
应该渲染 `Camper` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -42,7 +42,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Camper` component should include default props which assign the string `CamperBot` to the key `name`.
|
`Camper` 组件应该包含默认 props,它将字符串 `CamperBot` 赋值给关键字 `name`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -52,7 +52,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Camper` component should include prop types which require the `name` prop to be of type `string`.
|
`Camper` 组件应该包含 `string` 类型的 `name` prop。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -62,7 +62,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Camper` component should contain a `p` element with only the text from the `name` prop.
|
`Camper` 组件应该包含 `p` 元素,元素的文本是 prop 的 `name`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036173
|
id: 5a24c314108439a4d4036173
|
||||||
title: Set State with this.setState
|
title: 用 this.setState 设置状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301412
|
forumTopicId: 301412
|
||||||
dashedName: set-state-with-this-setstate
|
dashedName: set-state-with-this-setstate
|
||||||
@ -8,7 +8,7 @@ dashedName: set-state-with-this-setstate
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The previous challenges covered component `state` and how to initialize state in the `constructor`. There is also a way to change the component's `state`. React provides a method for updating component `state` called `setState`. You call the `setState` method within your component class like so: `this.setState()`, passing in an object with key-value pairs. The keys are your state properties and the values are the updated state data. For instance, if we were storing a `username` in state and wanted to update it, it would look like this:
|
前面的挑战涵盖了组件的 `state` 以及如何在 `constructor` 中初始化 state。 还有一种方法可以更改组件的 `state`, React 提供了 `setState` 方法来更新组件的 `state`。 在组件类中调用 `setState` 方法如下所示:`this.setState()`,传入键值对的对象, 其中键是 state 属性,值是更新后的 state 数据。 例如,如果我们在 state 中存储 `username`,并想要更新它,代码如下所示:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -16,17 +16,17 @@ this.setState({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
React expects you to never modify `state` directly, instead always use `this.setState()` when state changes occur. Also, you should note that React may batch multiple state updates in order to improve performance. What this means is that state updates through the `setState` method can be asynchronous. There is an alternative syntax for the `setState` method which provides a way around this problem. This is rarely needed but it's good to keep it in mind! Please consult the [React documentation](https://facebook.github.io/react/docs/state-and-lifecycle.html) for further details.
|
React 要求永远不要直接修改 `state`,而是在 state 发生改变时始终使用 `this.setState()`。 此外,应该注意,React 可以批量处理多个 state 更新以提高性能。 这意味着通过 `setState` 方法进行的 state 更新可以是异步的。 `setState` 方法有一种替代语法可以解决异步问题, 虽然这很少用到,但是最好还是记住它! 有关详细信息,请参阅[React 文档](https://facebook.github.io/react/docs/state-and-lifecycle.html)。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There is a `button` element in the code editor which has an `onClick()` handler. This handler is triggered when the `button` receives a click event in the browser, and runs the `handleClick` method defined on `MyComponent`. Within the `handleClick` method, update the component `state` using `this.setState()`. Set the `name` property in `state` to equal the string `React Rocks!`.
|
代码编辑器中有一个 `button` 元素,它有一个 `onClick()` 处理程序。 当 `button` 在浏览器中接收到单击事件时触发此处理程序,并运行 `MyComponent` 中定义的 `handleClick` 方法。 在 `handleClick` 方法中,使用 `this.setState()` 更新组件的 `state`。 设置 `state` 中的 `name` 属性为字符串 `React Rocks!`。
|
||||||
|
|
||||||
Click the button and watch the rendered state update. Don't worry if you don't fully understand how the click handler code works at this point. It's covered in upcoming challenges.
|
单击按钮查看渲染的 state 的更新。 如果不完全理解单击处理程序代码在此时的工作方式,请不要担心。 在接下来的挑战中会有讲述。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The state of `MyComponent` should initialize with the key value pair `{ name: Initial State }`.
|
`MyComponent` 的 state 应该使用键值对 `{ name: Initial State }` 来初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -35,13 +35,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should render an `h1` header.
|
`MyComponent` 应该渲染一个 `h1` 标题。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.mount(React.createElement(MyComponent)).find('h1').length === 1);
|
assert(Enzyme.mount(React.createElement(MyComponent)).find('h1').length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
The rendered `h1` header should contain text rendered from the component's state.
|
渲染的 `h1` 标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -57,7 +57,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Calling the `handleClick` method on `MyComponent` should set the name property in state to equal `React Rocks!`.
|
调用 `MyComponent` 的 `handleClick` 方法应该将 state 的 name 属性设置为 `React Rocks!`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -8,19 +8,19 @@ dashedName: use--for-a-more-concise-conditional
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The if/else statements worked in the last challenge, but there's a more concise way to achieve the same result. Imagine that you are tracking several conditions in a component and you want different elements to render depending on each of these conditions. If you write a lot of `else if` statements to return slightly different UIs, you may repeat code which leaves room for error. Instead, you can use the `&&` logical operator to perform conditional logic in a more concise way. This is possible because you want to check if a condition is `true`, and if it is, return some markup. Here's an example:
|
`if/else` 语句在上一次挑战中是有效的,但是有一种更简洁的方法可以达到同样的结果。 假设正在跟踪组件中的几个条件,并且希望根据这些条件中的每一个来渲染不同的元素。 如果你写了很多 `else if` 语句来返回稍微不同的 UI,你可能会写很多重复代码,这就留下了出错的空间。 相反,你可以使用 `&&` 逻辑运算符以更简洁的方式执行条件逻辑。 这是完全可行的,因为你希望检查条件是否为 `true`。如果是,则返回一些标记。 这里有一个例子:
|
||||||
|
|
||||||
`{condition && <p>markup</p>}`
|
`{condition && <p>markup</p>}`
|
||||||
|
|
||||||
If the `condition` is `true`, the markup will be returned. If the condition is `false`, the operation will immediately return `false` after evaluating the `condition` and return nothing. You can include these statements directly in your JSX and string multiple conditions together by writing `&&` after each one. This allows you to handle more complex conditional logic in your `render()` method without repeating a lot of code.
|
如果 `condition` 为 `true`,则返回标记。 如果 condition 为 `false`,操作将在判断 `condition` 后立即返回 `false`,并且不返回任何内容。 可以将这些语句直接包含在 JSX 中,并通过在每个条件后面写 `&&` 来将多个条件串在一起。 这允许在 `render()` 方法中处理更复杂的条件逻辑,而无需重复大量代码。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Solve the previous example again, so the `h1` only renders if `display` is `true`, but use the `&&` logical operator instead of an `if/else` statement.
|
再来看看前面的示例,`h1` 还是在 `display` 为 `true` 时被渲染,但使用 `&&` 逻辑运算符代替 `if/else` 语句。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should exist and render.
|
`MyComponent` 应该存在并被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -31,7 +31,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When `display` is set to `true`, a `div`, `button`, and `h1` should render.
|
当 `display` 被设置为 `true` 时,`div`、`button` 和 `h1` 标签应该被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -52,7 +52,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
When `display` is set to `false`, only a `div` and `button` should render.
|
当 `display` 被设置为 `false` 时,只有 `div` 和 `button` 应该被渲染。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
async () => {
|
async () => {
|
||||||
@ -73,7 +73,7 @@ async () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The render method should use the && logical operator to check the condition of this.state.display.
|
render 方法应该使用 `&&` 逻辑运算符来检查 `this.state.display` 的条件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) => assert(getUserInput('index').includes('&&'));
|
(getUserInput) => assert(getUserInput('index').includes('&&'));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036187
|
id: 5a24c314108439a4d4036187
|
||||||
title: Use a Ternary Expression for Conditional Rendering
|
title: 使用三元表达式进行条件渲染
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301414
|
forumTopicId: 301414
|
||||||
dashedName: use-a-ternary-expression-for-conditional-rendering
|
dashedName: use-a-ternary-expression-for-conditional-rendering
|
||||||
@ -8,7 +8,7 @@ dashedName: use-a-ternary-expression-for-conditional-rendering
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Before moving on to dynamic rendering techniques, there's one last way to use built-in JavaScript conditionals to render what you want: the <dfn>ternary operator</dfn>. The ternary operator is often utilized as a shortcut for `if/else` statements in JavaScript. They're not quite as robust as traditional `if/else` statements, but they are very popular among React developers. One reason for this is because of how JSX is compiled, `if/else` statements can't be inserted directly into JSX code. You might have noticed this a couple challenges ago — when an `if/else` statement was required, it was always *outside* the `return` statement. Ternary expressions can be an excellent alternative if you want to implement conditional logic within your JSX. Recall that a ternary operator has three parts, but you can combine several ternary expressions together. Here's the basic syntax:
|
在继续使用动态渲染技术之前,还有最后一种方法可以渲染想要的东西,它使用内置的 JavaScript 条件:<dfn>三元运算符</dfn>。 三元运算符经常被用作 JavaScript 中 `if/else` 语句的缩写。 它们不像传统的 `if/else` 语句那样强大,但是在 React 开发人员中非常流行, 原因之一就是 JSX 的编译原理,`if/else` 语句不能直接插入到 JSX 代码中。 可能你在前几个挑战就注意到了这一点——当需要 `if/else` 语句时,它总是在 `return` 语句的*外面*。 如果想在 JSX 中实现条件逻辑,三元表达式是一个很好的选择。 回想一下,三元运算符有三个部分,但是可以将多个三元表达式组合在一起。 以下是基本语法:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
condition ? expressionIfTrue : expressionIfFalse;
|
condition ? expressionIfTrue : expressionIfFalse;
|
||||||
@ -16,13 +16,13 @@ condition ? expressionIfTrue : expressionIfFalse;
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has three constants defined within the `CheckUserAge` component's `render()` method. They are called `buttonOne`, `buttonTwo`, and `buttonThree`. Each of these is assigned a simple JSX expression representing a button element. First, initialize the state of `CheckUserAge` with `input` and `userAge` both set to values of an empty string.
|
代码编辑器在 `CheckUserAge` 组件的 `render()` 方法中定义了三个常量, 它们分别是 `buttonOne`、`buttonTwo` 和 `buttonThree`。 每个都分配了一个表示按钮元素的简单 JSX 表达式。 首先,使用 `input` 和 `userAge` 初始化 `CheckUserAge` 的 state,并将其值设置为空字符串。
|
||||||
|
|
||||||
Once the component is rendering information to the page, users should have a way to interact with it. Within the component's `return` statement, set up a ternary expression that implements the following logic: when the page first loads, render the submit button, `buttonOne`, to the page. Then, when a user enters their age and clicks the button, render a different button based on the age. If a user enters a number less than `18`, render `buttonThree`. If a user enters a number greater than or equal to `18`, render `buttonTwo`.
|
一旦组件将信息渲染给页面,用户应该有一种方法与之交互。 在组件的 `return` 语句中,设置一个实现以下逻辑的三元表达式:当页面首次加载时,将提交按钮 `buttonOne` 渲染到页面。 然后,当用户输入年龄并点击该按钮时,根据年龄渲染不同的按钮。 如果用户输入的数字小于`18`,则渲染`buttonThree`。 如果用户输入的数字大于或等于`18`,则渲染`buttonTwo`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `CheckUserAge` component should render with a single `input` element and a single `button` element.
|
`CheckUserAge` 组件应该渲染出单个 `input` 元素和单个 `button` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,7 +33,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `CheckUserAge` component's state should be initialized with a property of `userAge` and a property of `input`, both set to a value of an empty string.
|
`CheckUserAge` 组件的 state 应该用 `userAge` 属性和 `input` 属性初始化,并且这两个属性的值都被设置为空字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -42,7 +42,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When the `CheckUserAge` component is first rendered to the DOM, the `button`'s inner text should be Submit.
|
当 `CheckUserAge` 组件首次渲染到 DOM 时,`button` 内部的文本应为 Submit。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -51,7 +51,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When a number of less than 18 is entered into the `input` element and the `button` is clicked, the `button`'s inner text should read `You Shall Not Pass`.
|
当小于 18 的数字输入到 `input` 元素中,并点击该`button` 时,该 `button` 的内部文本应该是 `You Shall Not Pass`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -83,7 +83,7 @@ When a number of less than 18 is entered into the `input` element and the `butto
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
When a number greater than or equal to 18 is entered into the `input` element and the `button` is clicked, the `button`'s inner text should read `You May Enter`.
|
当大于或等于 18 的数字输入到 `input` 元素中,并点击该 `button` 时,该 `button` 的内部文本应该是 `You May Enter`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -115,7 +115,7 @@ When a number greater than or equal to 18 is entered into the `input` element an
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
Once a number has been submitted, and the value of the `input` is once again changed, the `button` should return to reading `Submit`.
|
提交了一个数字之后,并再次更改了 `input` 的值,该 `button` 内部文本应该变回 `Submit`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -156,7 +156,7 @@ Once a number has been submitted, and the value of the `input` is once again cha
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
Your code should not contain any `if/else` statements.
|
你的代码不应该包含任何 `if/else` 语句。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036183
|
id: 5a24c314108439a4d4036183
|
||||||
title: Use Advanced JavaScript in React Render Method
|
title: 在 React Render 方法中使用 JavaScript
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301415
|
forumTopicId: 301415
|
||||||
dashedName: use-advanced-javascript-in-react-render-method
|
dashedName: use-advanced-javascript-in-react-render-method
|
||||||
@ -8,17 +8,17 @@ dashedName: use-advanced-javascript-in-react-render-method
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
In previous challenges, you learned how to inject JavaScript code into JSX code using curly braces, `{ }`, for tasks like accessing props, passing props, accessing state, inserting comments into your code, and most recently, styling your components. These are all common use cases to put JavaScript in JSX, but they aren't the only way that you can utilize JavaScript code in your React components.
|
在之前的挑战中,学习了如何使用大括号 `{ }` 将 JavaScript 代码插入到 JSX 代码中,用于访问 props、传递 props、访问 state、在代码中插入注释以及最近学习的定制组件样式等任务。 这些都是将 JavaScript 放在 JSX 中的常见用例,但是在 React 组件中使用 JavaScript 代码还有其他方式。
|
||||||
|
|
||||||
You can also write JavaScript directly in your `render` methods, before the `return` statement, ***without*** inserting it inside of curly braces. This is because it is not yet within the JSX code. When you want to use a variable later in the JSX code *inside* the `return` statement, you place the variable name inside curly braces.
|
在 `render` 方法中编写 JavaScript,可以把 JavaScript 直接放在 `return` 语句之前,而***不必***将其插入大括号中。 这是因为它还不在 JSX 代码中。 如果之后想在 `return` 语句中的 JSX 代码*里面*使用变量时,可以将变量名放在大括号中。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the code provided, the `render` method has an array that contains 20 phrases to represent the answers found in the classic 1980's Magic Eight Ball toy. The button click event is bound to the `ask` method, so each time the button is clicked a random number will be generated and stored as the `randomIndex` in state. On line 52, delete the string `"change me!"` and reassign the `answer` const so your code randomly accesses a different index of the `possibleAnswers` array each time the component updates. Finally, insert the `answer` const inside the `p` tags.
|
在提供的代码中,`render` 方法中有一个包含 20 个短语的数组,用于表示 20 世纪 80 年代经典魔术八球玩具中的答案。 绑定 `ask` 方法到按钮的单击事件,每次单击该按钮时,将生成随机数并将其存储为 state 中的 `randomIndex`。 在第 52 行,删除字符串 `change me!` 并重新分配 `answer` 常量,以便每次组件更新时,代码随机访问 `possibleAnswers` 数组的不同值。 最后,在 `p` 标签内插入 `answer` 常量。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `MagicEightBall` component should exist and should render to the page.
|
`MagicEightBall` 组件应该存在并被渲染到页面。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -28,7 +28,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MagicEightBall`'s first child should be an `input` element.
|
`MagicEightBall` 的第一个子元素应该是 `input` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -40,7 +40,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MagicEightBall`'s third child should be a `button` element.
|
`MagicEightBall` 的第三个子元素应该是 `button` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -52,7 +52,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MagicEightBall`'s state should be initialized with a property of `userInput` and a property of `randomIndex` both set to a value of an empty string.
|
`MagicEightBall` 的 state 应该用 `userInput` 属性和 `randomIndex` 属性初始化,并且这两个属性的值都应该是空字符串。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -62,7 +62,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When `MagicEightBall` is first mounted to the DOM, it should return an empty `p` element.
|
当 `MagicEightBall` 第一次加载到 DOM 中时,它应该返回一个空的 `p` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -71,7 +71,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When text is entered into the `input` element and the button is clicked, the `MagicEightBall` component should return a `p` element that contains a random element from the `possibleAnswers` array.
|
当文本被输入到 `input` 元素中并点击按钮时, `MagicEightBall` 组件应该返回一个 `p` 元素,该元素包含数组 `possibleAnswers` 中的随机一个元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403618c
|
id: 5a24c314108439a4d403618c
|
||||||
title: Use Array.filter() to Dynamically Filter an Array
|
title: 使用 Array.Filter() 动态过滤数组
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301416
|
forumTopicId: 301416
|
||||||
dashedName: use-array-filter-to-dynamically-filter-an-array
|
dashedName: use-array-filter-to-dynamically-filter-an-array
|
||||||
@ -8,17 +8,17 @@ dashedName: use-array-filter-to-dynamically-filter-an-array
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The `map` array method is a powerful tool that you will use often when working with React. Another method related to `map` is `filter`, which filters the contents of an array based on a condition, then returns a new array. For example, if you have an array of users that all have a property `online` which can be set to `true` or `false`, you can filter only those users that are online by writing:
|
`map` 数组方法是一个强大的工具,在使用 React 时经常使用。 与 `map` 相关的另一种方法是 `filter`,它根据条件过滤数组的内容,然后返回一个新数组。 例如,如果有一个 users 数组,每个数组元素都有一个可以设置为 `true` 或 `false` 的 `online` 属性,可以这样只过滤那些在线的用户:
|
||||||
|
|
||||||
`let onlineUsers = users.filter(user => user.online);`
|
`let onlineUsers = users.filter(user => user.online);`
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
In the code editor, `MyComponent`'s `state` is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use `filter` to return a new array containing only the users whose `online` property is `true`. Then, in the `renderOnline` variable, map over the filtered array, and return a `li` element for each user that contains the text of their `username`. Be sure to include a unique `key` as well, like in the last challenges.
|
在代码编辑器中,`MyComponent` 的 `state` 由一个 users 数组初始化。 有些用户在线,有些则不在线。 过滤数组,只看到在线用户。 为此,首先使用 `filter` 返回一个新数组,该数组只包含 `online` 属性为 `true` 的用户。 然后,在 `renderOnline` 变量中,映射经过过滤的数组,并为每个用户返回一个包含它们 `username` 文本的 `li` 元素。 确保像上一个挑战一样包含一个独特的 `key`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should exist and render to the page.
|
`MyComponent` 应该存在并被渲染到页面。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -27,7 +27,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent`'s state should be initialized to an array of six users.")
|
`MyComponent` 的 state 应该初始化为包含 6 个用户的数组。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -38,7 +38,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should return a `div`, an `h1`, and then an unordered list containing `li` elements for every user whose online status is set to `true`.
|
`MyComponent` 应该返回一个 `div`、一个 `h1` 和一个包含 `li` 元素的无序列表,该列表用于展示在线状态为 `true` 的每个用户。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -81,7 +81,7 @@ assert(
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should render `li` elements that contain the username of each online user.
|
`MyComponent` 应该渲染包含每个在线用户的 `username` 的 `li` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -107,7 +107,7 @@ assert(
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
Each list item element should have a unique `key` attribute.
|
每个列表项元素都应该有一个唯一的 `key` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403618a
|
id: 5a24c314108439a4d403618a
|
||||||
title: Use Array.map() to Dynamically Render Elements
|
title: 使用 Array.map() 动态渲染元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301417
|
forumTopicId: 301417
|
||||||
dashedName: use-array-map-to-dynamically-render-elements
|
dashedName: use-array-map-to-dynamically-render-elements
|
||||||
@ -8,21 +8,21 @@ dashedName: use-array-map-to-dynamically-render-elements
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Conditional rendering is useful, but you may need your components to render an unknown number of elements. Often in reactive programming, a programmer has no way to know what the state of an application is until runtime, because so much depends on a user's interaction with that program. Programmers need to write their code to correctly handle that unknown state ahead of time. Using `Array.map()` in React illustrates this concept.
|
条件渲染很有用,但是可能需要组件来渲染未知数量的元素。 通常在响应式编程中,程序员在应用程序运行时之前无法知道其 state,因为这在很大程度上取决于用户与该程序的交互。 程序员需要提前编写代码来正确处理未知状态。 在 React 中使用 `Array.map()` 阐明了这个概念。
|
||||||
|
|
||||||
For example, you create a simple "To Do List" app. As the programmer, you have no way of knowing how many items a user might have on their list. You need to set up your component to dynamically render the correct number of list elements long before someone using the program decides that today is laundry day.
|
例如,创建一个简单的“To Do List”应用程序。 作为程序员,你无法知道用户可能在其列表中有多少项。 需要设置组件,以便在使用该程序的人决定今天今日待办事项之前动态渲染正确数量的列表元素。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has most of the `MyToDoList` component set up. Some of this code should look familiar if you completed the controlled form challenge. You'll notice a `textarea` and a `button`, along with a couple of methods that track their states, but nothing is rendered to the page yet.
|
代码编辑器完成了 `MyToDoList` 组件的大部分设置。 如果完成了受控表单挑战,这些代码中的一些应该看起来很熟悉。 你会注意到一个 `textarea` 和一个 `button`,以及一些跟踪它们状态的方法,但是页面当前还没有任何东西被渲染。
|
||||||
|
|
||||||
Inside the `constructor`, create a `this.state` object and define two states: `userInput` should be initialized as an empty string, and `toDoList` should be initialized as an empty array. Next, delete the comment in the `render()` method next to the `items` variable. In its place, map over the `toDoList` array stored in the component's internal state and dynamically render a `li` for each item. Try entering the string `eat, code, sleep, repeat` into the `textarea`, then click the button and see what happens.
|
在 `constructor` 中,创建一个 `this.state` 对象并定义两个 state:`userInput` 应该初始化为空字符串,`toDoList` 应该初始化为空数组。 接下来,删除 `items` 变量旁边 `render()` 方法中的注释。 取而代之的是,将存储在组件内部 state 中的 `toDoList` 数组一一遍历并相应的动态呈现 `li` 元素中。 尝试在 `textarea` 中输入 `eat, code, sleep, repeat`,然后点击按钮,看看会发生什么。
|
||||||
|
|
||||||
**Note:** You may know that all sibling child elements created by a mapping operation like this do need to be supplied with a unique `key` attribute. Don't worry, this is the topic of the next challenge.
|
**注意:** 像这样的映射操作创建的所有兄弟子元素都需要提供唯一的 `key` 属性。 别担心,这是下一个挑战的主题。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The MyToDoList component should exist and render to the page.
|
MyToDoList 组件应该存在,并渲染到页面。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,7 +33,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The first child of `MyToDoList` should be a `textarea` element.
|
`MyToDoList` 组件的第一个子元素应该是 `textarea` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -47,7 +47,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The second child of `MyToDoList` should be a `br` element.
|
`MyToDoList` 组件的第二个子元素应该是 `br` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -60,7 +60,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The third child of `MyToDoList` should be a `button` element.
|
`MyToDoList` 组件的第三个子元素应该是 `button` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -74,7 +74,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `MyToDoList` should be initialized with `toDoList` as an empty array.
|
`MyToDoList` 的 state 应该使用被设置为空数组的 `toDoList` 进行初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -89,7 +89,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `MyToDoList` should be initialized with `userInput` as an empty string.
|
`MyToDoList` 的 state 应该使用被设置为空字符串的 `userInput` 进行初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -104,7 +104,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
When the `Create List` button is clicked, the `MyToDoList` component should dynamically return an unordered list that contains a list item element for every item of a comma-separated list entered into the `textarea` element.
|
单击 `Create List` 按钮时,`MyToDoList` 组件应该动态返回一个无序列表,该列表包含输入到 `textarea` 元素中的逗号分隔列表的每个项目的列表项目元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616b
|
id: 5a24c314108439a4d403616b
|
||||||
title: Use Default Props
|
title: 使用默认的 Props
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301418
|
forumTopicId: 301418
|
||||||
dashedName: use-default-props
|
dashedName: use-default-props
|
||||||
@ -8,15 +8,15 @@ dashedName: use-default-props
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
React also has an option to set default props. You can assign default props to a component as a property on the component itself and React assigns the default prop if necessary. This allows you to specify what a prop value should be if no value is explicitly provided. For example, if you declare `MyComponent.defaultProps = { location: 'San Francisco' }`, you have defined a location prop that's set to the string `San Francisco`, unless you specify otherwise. React assigns default props if props are undefined, but if you pass `null` as the value for a prop, it will remain `null`.
|
React 还有一个设置默认 props 的选项。 可以将默认 props 作为组件本身的属性分配给组件,React 会在必要时分配默认 prop。 如果没有显式的提供任何值,这允许指定 prop 值应该是什么。 例如,如果声明 `MyComponent.defaultProps = { location: 'San Francisco' }`,即定义一个 location 属性,并且其值在没有另行制定的情况下被设置为字符串 `San Francisco`。 如果 props 未定义,则 React 会分配默认 props,但如果你将 `null` 作为 prop 的值,它将保持 `null`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor shows a `ShoppingCart` component. Define default props on this component which specify a prop `items` with a value of `0`.
|
代码编辑器中有一个 `ShoppingCart` 组件。 在这个组件上定义默认 props,它指定一个 `items` prop,其值为 `0`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `ShoppingCart` component should render.
|
应该渲染 `ShoppingCart` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -27,7 +27,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ShoppingCart` component should have a default prop of `{ items: 0 }`.
|
`ShoppingCart` 组件应该有一个 `{ items: 0 }` 的默认 prop。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403616d
|
id: 5a24c314108439a4d403616d
|
||||||
title: Use PropTypes to Define the Props You Expect
|
title: 使用 PropTypes 来定义 Props 的类型
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301419
|
forumTopicId: 301419
|
||||||
dashedName: use-proptypes-to-define-the-props-you-expect
|
dashedName: use-proptypes-to-define-the-props-you-expect
|
||||||
@ -8,23 +8,23 @@ dashedName: use-proptypes-to-define-the-props-you-expect
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
React provides useful type-checking features to verify that components receive props of the correct type. For example, your application makes an API call to retrieve data that you expect to be in an array, which is then passed to a component as a prop. You can set `propTypes` on your component to require the data to be of type `array`. This will throw a useful warning when the data is of any other type.
|
React 提供了有用的类型检查特性,以验证组件是否接收了正确类型的 props。 例如,应用程序调用 API 来检索数据是否是数组,然后将数据作为 prop 传递给组件。 可以在组件上设置 `propTypes`,以要求数据的类型为 `array`。 当数据是任何其它类型时,都会抛出警告。
|
||||||
|
|
||||||
It's considered a best practice to set `propTypes` when you know the type of a prop ahead of time. You can define a `propTypes` property for a component in the same way you defined `defaultProps`. Doing this will check that props of a given key are present with a given type. Here's an example to require the type `function` for a prop called `handleClick`:
|
当提前知道 prop 的类型时,最佳实践是设置其 `propTypes`。 可以为组件定义 `propTypes` 属性,方法与定义 `defaultProps` 相同。 这样做将检查给定键的 prop 是否是给定类型。 这里有一个示例,表示名为 `handleClick` 的 prop 应为 `function` 类型:
|
||||||
|
|
||||||
`MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }`
|
`MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }`
|
||||||
|
|
||||||
In the example above, the `PropTypes.func` part checks that `handleClick` is a function. Adding `isRequired` tells React that `handleClick` is a required property for that component. You will see a warning if that prop isn't provided. Also notice that `func` represents `function`. Among the seven JavaScript primitive types, `function` and `boolean` (written as `bool`) are the only two that use unusual spelling. In addition to the primitive types, there are other types available. For example, you can check that a prop is a React element. Please refer to the [documentation](https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type) for all of the options.
|
在上面的示例中,`PropTypes.func` 部分检查 `handleClick` 是否为函数。 添加 `isRequired` 是为了告诉 React `handleClick` 是该组件的必需属性。 如果未提供该 prop,将看到警告信息。 另请注意,`func` 表示 `function`。 在 7 种 JavaScript 基本类型中,`function` 和 `boolean`(写为 `bool`)是仅有的使用异常拼写的两种类型。 除了基本类型,还有其它类型可用。 例如,可以检查 prop 是否为 React 组件, 请参阅[文档](https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type)以获取所有选项。
|
||||||
|
|
||||||
**Note:** As of React v15.5.0, `PropTypes` is imported independently from React, like this: `import PropTypes from 'prop-types';`
|
**注意:** 在 React v15.5.0 版本中, `PropTypes` 可以从 React 中单独引入,例如: `import PropTypes from 'prop-types';`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Define `propTypes` for the `Items` component to require `quantity` as a prop and verify that it is of type `number`.
|
为 `Items` 组件定义 `propTypes`,要求 `quantity` 作为 prop,并验证它是 `number` 类型。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `ShoppingCart` component should render.
|
应该渲染 `ShoppingCart` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -35,7 +35,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Items` component should render.
|
应该渲染 `Items` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -46,7 +46,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Items` component should include a `propTypes` check to require a value for `quantity` and ensure that its value is a number.
|
`Items` 组件应该包含一个 `propTypes`,要求 `quantity` 有一个 number 类型的值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036165
|
id: 5a24c314108439a4d4036165
|
||||||
title: Use React to Render Nested Components
|
title: 使用 React 渲染嵌套组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301420
|
forumTopicId: 301420
|
||||||
dashedName: use-react-to-render-nested-components
|
dashedName: use-react-to-render-nested-components
|
||||||
@ -8,23 +8,23 @@ dashedName: use-react-to-render-nested-components
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last challenge showed a simple way to compose two components, but there are many different ways you can compose components with React.
|
上一个挑战显示了组合两个组件的简单方法,但是有许多不同的方法可以把 React 组件组合在一起。
|
||||||
|
|
||||||
Component composition is one of React's powerful features. When you work with React, it is important to start thinking about your user interface in terms of components like the App example in the last challenge. You break down your UI into its basic building blocks, and those pieces become the components. This helps to separate the code responsible for the UI from the code responsible for handling your application logic. It can greatly simplify the development and maintenance of complex projects.
|
组件组合是 React 的强大功能之一。 当使用 React 时,应当先用组件的思路考虑清楚用户界面的结构(如上一个挑战中的 App 示例)。 可以将 UI 分解为基本的构建块,这些构建块就是组件。 这样做有助于将负责 UI 的代码与负责处理应用程序逻辑的代码分开, 并可以大大简化复杂项目的开发和维护。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There are two functional components defined in the code editor, called `TypesOfFruit` and `Fruits`. Take the `TypesOfFruit` component and compose it, or *nest* it, within the `Fruits` component. Then take the `Fruits` component and nest it within the `TypesOfFood` component. The result should be a child component, nested within a parent component, which is nested within a parent component of its own!
|
代码编辑器中定义了两个功能组件,分别是 `TypesOfFruit` 和 `Fruits`。 请用组合或者*嵌套*把 `TypesOfFruit` 组件放到 `Fruits` 组件中, 然后把 `Fruits` 组件放到 `TypesOfFood` 组件中。 结果应该是子组件嵌套在父组件中,父组件嵌套在它本身的父组件中!
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `TypesOfFood` component should return a single `div` element.
|
`TypesOfFood` 组件应该返回单个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(Enzyme.shallow(React.createElement(TypesOfFood)).type() === 'div');
|
assert(Enzyme.shallow(React.createElement(TypesOfFood)).type() === 'div');
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFood` component should return the `Fruits` component.
|
`TypesOfFood` 组件应该返回 `Fruits` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,7 +33,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Fruits` component should return the `TypesOfFruit` component.
|
`Fruits` 组件应该返回 `TypesOfFruit` 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -42,7 +42,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TypesOfFruit` component should return the `h2` and `ul` elements.
|
`TypesOfFruit` 组件应该返回 `h2` 和 `ul` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036176
|
id: 5a24c314108439a4d4036176
|
||||||
title: Use State to Toggle an Element
|
title: 使用 State 切换元素
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301421
|
forumTopicId: 301421
|
||||||
dashedName: use-state-to-toggle-an-element
|
dashedName: use-state-to-toggle-an-element
|
||||||
@ -8,7 +8,7 @@ dashedName: use-state-to-toggle-an-element
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Sometimes you might need to know the previous state when updating the state. However, state updates may be asynchronous - this means React may batch multiple `setState()` calls into a single update. This means you can't rely on the previous value of `this.state` or `this.props` when calculating the next value. So, you should not use code like this:
|
有时可能在更新状态的时候想知道上一个状态是什么。 但是状态更新是异步的,这意味着 React 可能会把多个 `setState()` 集中在一起批量更新。 所以计算下一个值时 `this.state` 或者 `this.props` 不能作为当前值。 所以最好不要写如下的代码:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -16,7 +16,7 @@ this.setState({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Instead, you should pass `setState` a function that allows you to access state and props. Using a function with `setState` guarantees you are working with the most current values of state and props. This means that the above should be rewritten as:
|
正确的做法是,给 `setState` 传入一个函数,这个函数可以访问 state 和 props。 给 `setState` 传入函数可以保证 state 和 props 是正确的值。 代码可以重写为这样:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
this.setState((state, props) => ({
|
this.setState((state, props) => ({
|
||||||
@ -24,7 +24,7 @@ this.setState((state, props) => ({
|
|||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use a form without `props` if you need only the `state`:
|
如果只需要 `state`,那么用下面没有 `props` 的格式也是可以的:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
@ -32,21 +32,21 @@ this.setState(state => ({
|
|||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that you have to wrap the object literal in parentheses, otherwise JavaScript thinks it's a block of code.
|
注意一定要把 object 放在括号里,否则 JavaScript 会认为这只是代码片段。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
`MyComponent` has a `visibility` property which is initialized to `false`. The render method returns one view if the value of `visibility` is true, and a different view if it is false.
|
`MyComponent` 有一个初始值为 `false` 的`visibility` 属性。 如果 `visibility` 的值为 true,render 方法返回一个视图,如果为 false,返回另一个视图。
|
||||||
|
|
||||||
Currently, there is no way of updating the `visibility` property in the component's `state`. The value should toggle back and forth between true and false. There is a click handler on the button which triggers a class method called `toggleVisibility()`. Pass a function to `setState` to define this method so that the `state` of `visibility` toggles to the opposite value when the method is called. If `visibility` is `false`, the method sets it to `true`, and vice versa.
|
目前,无法更新组件 `state` 中的 `visibility` 属性, 该值应在 true 和 false 之间来回切换。 按钮上有一个单击处理程序,它触发一个名为 `toggleVisibility()` 的类方法。 给函数传入 `setState` 来定义此方法,以便 `visibility` 的 `state` 在调用方法时切换到相反的值。 如果 `visibility` 是 `false`,则该方法将其设置为`true`,反之亦然。
|
||||||
|
|
||||||
Finally, click the button to see the conditional rendering of the component based on its `state`.
|
最后,单击按钮以查看基于其 `state` 的组件的条件渲染。
|
||||||
|
|
||||||
**Hint:** Don't forget to bind the `this` keyword to the method in the constructor!
|
**提示:** 不要忘记将 `this` 关键字绑定到 `constructor` 中的方法上!
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should return a `div` element which contains a `button`.
|
`MyComponent` 应该返回一个 `div` 元素,其中包含一个 `button` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -56,7 +56,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `MyComponent` should initialize with a `visibility` property set to `false`.
|
`MyComponent` 应该使用设置为 `false` 的 `visibility` 属性来初始化其 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
@ -65,7 +65,7 @@ assert.strictEqual(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the button element should toggle the `visibility` property in state between `true` and `false`.
|
单击按钮元素应在 `true` 和 `false` 之间切换 `visibility` 属性的状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
@ -89,7 +89,7 @@ Clicking the button element should toggle the `visibility` property in state bet
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
An anonymous function should be passed to `setState`.
|
应该给 `setState` 传入一个匿名函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?';
|
const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?';
|
||||||
@ -104,7 +104,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`this` should not be used inside `setState`
|
不要在 `setState` 里面使用 `this`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(!/this\.setState\([^}]*this/.test(code));
|
assert(!/this\.setState\([^}]*this/.test(code));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403617d
|
id: 5a24c314108439a4d403617d
|
||||||
title: Use the Lifecycle Method componentDidMount
|
title: 使用生命周期方法:componentDidMount
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301422
|
forumTopicId: 301422
|
||||||
dashedName: use-the-lifecycle-method-componentdidmount
|
dashedName: use-the-lifecycle-method-componentdidmount
|
||||||
@ -8,17 +8,17 @@ dashedName: use-the-lifecycle-method-componentdidmount
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Most web developers, at some point, need to call an API endpoint to retrieve data. If you're working with React, it's important to know where to perform this action.
|
某些时候,大多数 web 开发人员需要调用 API 接口来获取数据。 如果正在使用 React,知道在哪里执行这个动作是很重要的。
|
||||||
|
|
||||||
The best practice with React is to place API calls or any calls to your server in the lifecycle method `componentDidMount()`. This method is called after a component is mounted to the DOM. Any calls to `setState()` here will trigger a re-rendering of your component. When you call an API in this method, and set your state with the data that the API returns, it will automatically trigger an update once you receive the data.
|
React 的最佳实践是在生命周期方法 `componentDidMount()` 中对服务器进行 API 调用或任何其它调用。 将组件装载到 DOM 后会调用此方法。 此处对 `setState()` 的任何调用都将触发组件的重新渲染。 在此方法中调用 API 并用 API 返回的数据设置 state 时,一旦收到数据,它将自动触发更新。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There is a mock API call in `componentDidMount()`. It sets state after 2.5 seconds to simulate calling a server to retrieve data. This example requests the current total active users for a site. In the render method, render the value of `activeUsers` in the `h1` after the text `Active Users:`. Watch what happens in the preview, and feel free to change the timeout to see the different effects.
|
`componentDidMount()` 中有一个模拟 API 调用。 它在 2.5 秒后设置 state,以模拟调用服务器检索数据。 本示例请求站点的当前活动用户总数。 在 render 方法中,把 `activeUsers` 渲染到文字 `Active Users:` 后的 `h1` 标签中。 观看预览中发生的事情,随意更改超时时间以查看不同的效果。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should render a `div` element which wraps an `h1` tag.
|
`MyComponent` 应该渲染一个包含 `h1` 标签的 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -32,7 +32,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Component state should be updated with a timeout function in `componentDidMount`.
|
组件 state 应该用 `componentDidMount` 中的延时函数来更新。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -45,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `h1` tag should render the `activeUsers` value from `MyComponent`'s state.
|
`h1` 标签应该从 `MyComponent` 的 state 渲染 `activeUsers` 值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403617c
|
id: 5a24c314108439a4d403617c
|
||||||
title: Use the Lifecycle Method componentWillMount
|
title: 使用生命周期方法:componentWillMount
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301423
|
forumTopicId: 301423
|
||||||
dashedName: use-the-lifecycle-method-componentwillmount
|
dashedName: use-the-lifecycle-method-componentwillmount
|
||||||
@ -8,17 +8,17 @@ dashedName: use-the-lifecycle-method-componentwillmount
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
React components have several special methods that provide opportunities to perform actions at specific points in the lifecycle of a component. These are called lifecycle methods, or lifecycle hooks, and allow you to catch components at certain points in time. This can be before they are rendered, before they update, before they receive props, before they unmount, and so on. Here is a list of some of the main lifecycle methods: `componentWillMount()` `componentDidMount()` `shouldComponentUpdate()` `componentDidUpdate()` `componentWillUnmount()` The next several lessons will cover some of the basic use cases for these lifecycle methods.
|
React 组件有几种特殊方法,可以在组件生命周期的特定点执行操作。 这些称为生命周期方法或生命周期钩子,允许在特定时间点捕获组件。 这可以在渲染之前、更新之前、接收 props 之前、卸载之前等等。 以下是一些主要生命周期方法的列表: `componentWillMount()` `componentDidMount()` `shouldComponentUpdate()` `componentDidUpdate()` `componentWillUnmount()` 接下来的几节课将讲述这些生命周期方法的一些基本用例。
|
||||||
|
|
||||||
**Note:** The `componentWillMount` Lifecycle method will be deprecated in a future version of 16.X and removed in version 17. [(Source)](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html)
|
**注意:** `componentWillMount` 生命周期方法会在版本 16.X 废弃在版本 17 移除。 [(来源)](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html)
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `componentWillMount()` method is called before the `render()` method when a component is being mounted to the DOM. Log something to the console within `componentWillMount()` - you may want to have your browser console open to see the output.
|
当组件被挂载到 DOM 时,`componentWillMount()` 方法在 `render()` 方法之前被调用。 在`componentWillMount()`中将一些内容记录到控制台 -- 可能需要打开浏览器控制台以查看输出。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`MyComponent` should render a `div` element.
|
`MyComponent` 应该渲染一个 `div` 元素。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,7 +29,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`console.log` should be called in `componentWillMount`.
|
应该在 `componentWillMount` 中调用 `console.log`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036168
|
id: 5a24c314108439a4d4036168
|
||||||
title: Write a React Component from Scratch
|
title: 从零开始写一个 React 组件
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301424
|
forumTopicId: 301424
|
||||||
dashedName: write-a-react-component-from-scratch
|
dashedName: write-a-react-component-from-scratch
|
||||||
@ -8,17 +8,17 @@ dashedName: write-a-react-component-from-scratch
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Now that you've learned the basics of JSX and React components, it's time to write a component on your own. React components are the core building blocks of React applications so it's important to become very familiar with writing them. Remember, a typical React component is an ES6 `class` which extends `React.Component`. It has a render method that returns HTML (from JSX) or `null`. This is the basic form of a React component. Once you understand this well, you will be prepared to start building more complex React projects.
|
你已经了解了 JSX 和 React 组件的基础知识,是时候自己编写一个组件了。 React 组件是 React 应用程序的核心组成部分,因此熟练编写它们是非常重要的。 记住,典型的 React 组件是 ES6 `class`,它扩展了 `React.Component`。 它有一个返回 HTML(从 JSX 返回)或 `null` 的渲染方法, 这是 React 组件的基本形式。 理解了这一点之后,就可以开始构建更复杂的 React 项目了。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Define a class `MyComponent` that extends `React.Component`. Its render method should return a `div` that contains an `h1` tag with the text: `My First React Component!` in it. Use this text exactly, the case and punctuation matter. Make sure to call the constructor for your component, too.
|
定义一个 `MyComponent` 类,它是 `React.Component` 的扩展。 它的渲染方法应该返回一个 `div`,其中包含一个 `h1` 标签,标签文本为:`My First React Component!`。 准确使用此文本,大小写和标点符号也要考虑。 确保也调用组件的构造器。
|
||||||
|
|
||||||
Render this component to the DOM using `ReactDOM.render()`. There is a `div` with `id='challenge-node'` available for you to use.
|
使用 `ReactDOM.render()` 把该组件渲染到 DOM 中。 有一个 `id='challenge-node'` 的 `div` 可供渲染。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
There should be a React component called `MyComponent`.
|
应该有一个名为 `MyComponent` 的 React 组件。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
@ -29,7 +29,7 @@ There should be a React component called `MyComponent`.
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should contain an `h1` tag with text `My First React Component!` Case and punctuation matter.
|
`MyComponent` 应该包含一个 `h1` 标签,标签的文本为 `My First React Component!`,区分大小写并有标点符号。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -40,13 +40,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should render to the DOM.
|
`MyComponent` 应该渲染到 DOM。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(document.getElementById('challenge-node').childNodes.length === 1);
|
assert(document.getElementById('challenge-node').childNodes.length === 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
`MyComponent` should have a constructor calling `super` with `props`.
|
`MyComponent` 应该有一个构造器,里面调用了传参 `props` 的 `super` 函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036177
|
id: 5a24c314108439a4d4036177
|
||||||
title: Write a Simple Counter
|
title: 写一个简单的计数器
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301425
|
forumTopicId: 301425
|
||||||
dashedName: write-a-simple-counter
|
dashedName: write-a-simple-counter
|
||||||
@ -8,17 +8,17 @@ dashedName: write-a-simple-counter
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
You can design a more complex stateful component by combining the concepts covered so far. These include initializing `state`, writing methods that set `state`, and assigning click handlers to trigger these methods.
|
可以结合目前为止所涵盖的概念来设计更复杂的有状态组件。 这包括初始化 `state`,编写设置 `state` 的方法,以及指定单击处理程序来触发这些方法。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The `Counter` component keeps track of a `count` value in `state`. There are two buttons which call methods `increment()` and `decrement()`. Write these methods so the counter value is incremented or decremented by 1 when the appropriate button is clicked. Also, create a `reset()` method so when the reset button is clicked, the count is set to 0.
|
`Counter` 组件跟踪 `state` 中的 `count` 值。 有两个按钮分别调用 `increment()` 和 `decrement()` 方法。 编写这些方法,使计数器值在单击相应按钮时增加或减少 1。 另外,创建一个 `reset()` 方法,当单击 reset 按钮时,把计数设置为 0。
|
||||||
|
|
||||||
**Note:** Make sure you don't modify the `classNames` of the buttons. Also, remember to add the necessary bindings for the newly-created methods in the constructor.
|
**注意:** 确保没有修改按钮的 `className`。 另外,请记住在构造函数中为新创建的方法添加必要的绑定。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
`Counter` should return a `div` element which contains three buttons with text content in this order `Increment!`, `Decrement!`, `Reset`.
|
`Counter` 应该返回一个 `div` 元素,它包含三个按钮,按钮内容依次是 `Increment!`、`Decrement!`、`Reset`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -33,14 +33,14 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The state of `Counter` should initialize with a `count` property set to `0`.
|
`Counter` 应该使用设置为 `0` 的 `count` 属性初始化 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
||||||
assert(mockedComponent.find('h1').text() === 'Current Count: 0');
|
assert(mockedComponent.find('h1').text() === 'Current Count: 0');
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the increment button should increment the count by `1`.
|
单击 increment 按钮应将计数增加 `1`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
||||||
@ -48,7 +48,7 @@ mockedComponent.find('.inc').simulate('click');
|
|||||||
assert(mockedComponent.find('h1').text() === 'Current Count: 1');
|
assert(mockedComponent.find('h1').text() === 'Current Count: 1');
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the decrement button should decrement the count by `1`.
|
单击 decrement 按钮应将计数减少 `1`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
||||||
@ -56,7 +56,7 @@ mockedComponent.find('.dec').simulate('click');
|
|||||||
assert(mockedComponent.find('h1').text() === 'Current Count: -1');
|
assert(mockedComponent.find('h1').text() === 'Current Count: -1');
|
||||||
```
|
```
|
||||||
|
|
||||||
Clicking the reset button should reset the count to `0`.
|
单击 reset 按钮应将计数重置为 `0`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
const mockedComponent = Enzyme.mount(React.createElement(Counter));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036154
|
id: 5a24c314108439a4d4036154
|
||||||
title: Combine Multiple Reducers
|
title: 组合多个 Reducers
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301436
|
forumTopicId: 301436
|
||||||
dashedName: combine-multiple-reducers
|
dashedName: combine-multiple-reducers
|
||||||
@ -8,11 +8,11 @@ dashedName: combine-multiple-reducers
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
When the state of your app begins to grow more complex, it may be tempting to divide state into multiple pieces. Instead, remember the first principle of Redux: all app state is held in a single state object in the store. Therefore, Redux provides reducer composition as a solution for a complex state model. You define multiple reducers to handle different pieces of your application's state, then compose these reducers together into one root reducer. The root reducer is then passed into the Redux `createStore()` method.
|
当应用程序的状态开始变得越来越复杂时,可能会将 state 分成多个块。 相反,请记住 Redux 的第一个原则:所有应用程序状态都保存在 store 中的一个简单的 state 对象中。 因此,Redux 提供 reducer 组合作为复杂状态模型的解决方案。 定义多个 reducer 来处理应用程序状态的不同部分,然后将这些 reducer 组合成一个 root reducer。 然后将 root reducer 传递给 Redux `createStore()`方法。
|
||||||
|
|
||||||
In order to let us combine multiple reducers together, Redux provides the `combineReducers()` method. This method accepts an object as an argument in which you define properties which associate keys to specific reducer functions. The name you give to the keys will be used by Redux as the name for the associated piece of state.
|
为了将多个 reducer 组合在一起,Redux 提供了`combineReducers()`方法。 该方法接受一个对象作为参数,在该参数中定义一个属性,该属性将键与特定 reducer 函数关联。 Redux 将使用给定的键值作为关联状态的名称。
|
||||||
|
|
||||||
Typically, it is a good practice to create a reducer for each piece of application state when they are distinct or unique in some way. For example, in a note-taking app with user authentication, one reducer could handle authentication while another handles the text and notes that the user is submitting. For such an application, we might write the `combineReducers()` method like this:
|
通常情况下,当它们在某种程度上是独一无二的,为每个应用程序的 state 创建一个 reducer 是一个很好的做法。 例如,在一个带有用户身份验证的记笔记应用程序中,一个 reducer 可以处理身份验证而另一个处理用户提交的文本和注释。 对于这样的应用程序,可能会编写 `combineReducers()` 方法,如下所示:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const rootReducer = Redux.combineReducers({
|
const rootReducer = Redux.combineReducers({
|
||||||
@ -21,15 +21,15 @@ const rootReducer = Redux.combineReducers({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, the key `notes` will contain all of the state associated with our notes and handled by our `notesReducer`. This is how multiple reducers can be composed to manage more complex application state. In this example, the state held in the Redux store would then be a single object containing `auth` and `notes` properties.
|
现在,`notes` 键将包含与注释相关联的所有状态,并由 `notesReducer` 处理。 这就是组合多个 reducer 来管理更复杂的应用程序状态的方式, 在此示例中,Redux store 中保存的状态将是一个包含 `auth` 和 `notes` 属性的简单对象。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There are `counterReducer()` and `authReducer()` functions provided in the code editor, along with a Redux store. Finish writing the `rootReducer()` function using the `Redux.combineReducers()` method. Assign `counterReducer` to a key called `count` and `authReducer` to a key called `auth`.
|
代码编辑器中提供了 `counterReducer()` 和 `authReducer()` 函数以及 Redux store。 使用 `Redux.combineReducers()` 方法编写完成 `rootReducer()` 函数。 将 `counterReducer` 分配给一个叫做 `count` 的键,将 `authReducer` 分配给一个叫做 `auth` 的键。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The `counterReducer` should increment and decrement the `state`.
|
`counterReducer` 应该递增和递减 `state`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -45,7 +45,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `authReducer` should toggle the `state` of `authenticated` between `true` and `false`.
|
`authReducer` 应该可以使 `authenticated` 的 `state` 值在 `true` 和 `false` 之间切换。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -59,7 +59,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The store `state` should have two keys: `count`, which holds a number, and `auth`, which holds an object. The `auth` object should have a property of `authenticated`, which holds a boolean.
|
store `state` 应该有两个 key:一个是 `count`,它包含一个数字。 另一个 `auth`,它包含一个对象。 `auth` 对象应该具有 `authenticated` 的属性,该属性的值应该为布尔值。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -74,7 +74,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `rootReducer` should be a function that combines the `counterReducer` and the `authReducer`.
|
`rootReducer` 应该是一个合并了 `counterReducer` 和 `authReducer` 的函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403615b
|
id: 5a24c314108439a4d403615b
|
||||||
title: Copy an Object with Object.assign
|
title: 使用 Object.assign 拷贝对象
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301437
|
forumTopicId: 301437
|
||||||
dashedName: copy-an-object-with-object-assign
|
dashedName: copy-an-object-with-object-assign
|
||||||
@ -8,19 +8,19 @@ dashedName: copy-an-object-with-object-assign
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The last several challenges worked with arrays, but there are ways to help enforce state immutability when state is an `object`, too. A useful tool for handling objects is the `Object.assign()` utility. `Object.assign()` takes a target object and source objects and maps properties from the source objects to the target object. Any matching properties are overwritten by properties in the source objects. This behavior is commonly used to make shallow copies of objects by passing an empty object as the first argument followed by the object(s) you want to copy. Here's an example:
|
最后几个挑战适用于数组,但是当状态是 `object` 时,有一些方法可以实现状态不变性。 处理对象的一个常用的方法是 `Object.assign()`。 `Object.assign()` 获取目标对象和源对象,并将源对象中的属性映射到目标对象。 任何匹配的属性都会被源对象中的属性覆盖。 通常用于通过传递一个空对象作为第一个参数,然后是要用复制的对象来制作对象的浅表副本。 这是一个例子:
|
||||||
|
|
||||||
`const newObject = Object.assign({}, obj1, obj2);`
|
`const newObject = Object.assign({}, obj1, obj2);`
|
||||||
|
|
||||||
This creates `newObject` as a new `object`, which contains the properties that currently exist in `obj1` and `obj2`.
|
这会创建 `newObject` 作为新的 `object`,其中包含 `obj1` 和 `obj2` 中当前存在的属性。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The Redux state and actions were modified to handle an `object` for the `state`. Edit the code to return a new `state` object for actions with type `ONLINE`, which set the `status` property to the string `online`. Try to use `Object.assign()` to complete the challenge.
|
Redux 状态和 action 被修改为处理 `state` 的 `object`。 编辑代码以返回一个新的 `state` 对象,用于含有 `ONLINE` 类型的 action ,它将 `status` 属性设置为字符串 `online`。 尝试使用 `Object.assign()` 来完成挑战。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The Redux store should exist and initialize with a state that is equivalent to the `defaultState` object declared on line 1.
|
Redux store 应该存在并使用与第 1 行声明的 `defaultState` 对象相同的状态进行初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -37,13 +37,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`wakeUp` and `immutableReducer` both should be functions.
|
`wakeUp` 和 `immutableReducer` 都应该是函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof wakeUp === 'function' && typeof immutableReducer === 'function');
|
assert(typeof wakeUp === 'function' && typeof immutableReducer === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching an action of type `ONLINE` should update the property `status` in state to `online` and should NOT mutate state.
|
dispatch 一个类型为 `ONLINE` 的 action 应该将状态 `status` 更新为 `online`,并且不应该改变状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -63,7 +63,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`Object.assign` should be used to return new state.
|
`Object.assign` 应该被用于返回一个新状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) => assert(getUserInput('index').includes('Object.assign'));
|
(getUserInput) => assert(getUserInput('index').includes('Object.assign'));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614b
|
id: 5a24c314108439a4d403614b
|
||||||
title: Create a Redux Store
|
title: 创建一个 Redux Store
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301439
|
forumTopicId: 301439
|
||||||
dashedName: create-a-redux-store
|
dashedName: create-a-redux-store
|
||||||
@ -8,29 +8,29 @@ dashedName: create-a-redux-store
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Redux is a state management framework that can be used with a number of different web technologies, including React.
|
Redux 是一个状态管理框架,可以与包括 React 在内的许多不同的 Web 技术一起使用。
|
||||||
|
|
||||||
In Redux, there is a single state object that's responsible for the entire state of your application. This means if you had a React app with ten components, and each component had its own local state, the entire state of your app would be defined by a single state object housed in the Redux `store`. This is the first important principle to understand when learning Redux: the Redux store is the single source of truth when it comes to application state.
|
在 Redux 中,有一个状态对象负责应用程序的整个状态, 这意味着如果你有一个包含十个组件且每个组件都有自己的本地状态的 React 项目,那么这个项目的整个状态将通过 Redux `store` 被定义为单个状态对象, 这是学习 Redux 时要理解的第一个重要原则:Redux store 是应用程序状态的唯一真实来源。
|
||||||
|
|
||||||
This also means that any time any piece of your app wants to update state, it **must** do so through the Redux store. The unidirectional data flow makes it easier to track state management in your app.
|
这也意味着,如果应用程序想要更新状态,**只能**通过 Redux store 执行, 单向数据流可以更轻松地对应用程序中的状态进行监测管理。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The Redux `store` is an object which holds and manages application `state`. There is a method called `createStore()` on the Redux object, which you use to create the Redux `store`. This method takes a `reducer` function as a required argument. The `reducer` function is covered in a later challenge, and is already defined for you in the code editor. It simply takes `state` as an argument and returns `state`.
|
Redux `store` 是一个保存和管理应用程序状态的`state`, 可以使用 Redux 对象中的 `createStore()` 来创建一个 redux `store`, 此方法将 `reducer` 函数作为必需参数, `reducer` 函数将在后面的挑战中介绍。该函数已在代码编辑器中为你定义, 它只需将 `state` 作为参数并返回一个 `state` 即可。
|
||||||
|
|
||||||
Declare a `store` variable and assign it to the `createStore()` method, passing in the `reducer` as an argument.
|
声明一个 `store` 变量并把它分配给 `createStore()` 方法,然后把 `reducer` 作为一个参数传入即可。
|
||||||
|
|
||||||
**Note:** The code in the editor uses ES6 default argument syntax to initialize this state to hold a value of `5`. If you're not familiar with default arguments, you can refer to the [ES6 section in the Curriculum](https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/set-default-parameters-for-your-functions) which covers this topic.
|
**注意**: 编辑器中的代码使用 ES6 默认参数语法将 state 的值初始化为 `5`, 如果你不熟悉默认参数,你可以参考[ES6 全部课程](https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/set-default-parameters-for-your-functions),它里面涵盖了这个内容。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The redux store should exist.
|
Redux store 应当存在。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof store.getState === 'function');
|
assert(typeof store.getState === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
The redux store should have a value of 5 for the state.
|
Redux store 的 state 的值应该为 5。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(store.getState() === 5);
|
assert(store.getState() === 5);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614d
|
id: 5a24c314108439a4d403614d
|
||||||
title: Define a Redux Action
|
title: 定义一个 Redux Action
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301440
|
forumTopicId: 301440
|
||||||
dashedName: define-a-redux-action
|
dashedName: define-a-redux-action
|
||||||
@ -8,17 +8,17 @@ dashedName: define-a-redux-action
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Since Redux is a state management framework, updating state is one of its core tasks. In Redux, all state updates are triggered by dispatching actions. An action is simply a JavaScript object that contains information about an action event that has occurred. The Redux store receives these action objects, then updates its state accordingly. Sometimes a Redux action also carries some data. For example, the action carries a username after a user logs in. While the data is optional, actions must carry a `type` property that specifies the 'type' of action that occurred.
|
由于 Redux 是一个状态管理框架,因此更新状态是其核心任务之一。 在 Redux 中,所有状态更新都由 dispatch action 触发, action 只是一个 JavaScript 对象,其中包含有关已发生的 action 事件的信息。 Redux store 接收这些 action 对象,然后更新相应的状态。 有时,Redux action 也会携带一些数据。 例如,在用户登录后携带用户名, 虽然数据是可选的,但 action 必须带有 `type` 属性,该属性表示此 action 的类型。
|
||||||
|
|
||||||
Think of Redux actions as messengers that deliver information about events happening in your app to the Redux store. The store then conducts the business of updating state based on the action that occurred.
|
我们可以将 Redux action 视为信使,将有关应用程序中发生的事件信息提供给 Redux store, 然后 store 根据发生的 action 进行状态的更新。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Writing a Redux action is as simple as declaring an object with a type property. Declare an object `action` and give it a property `type` set to the string `'LOGIN'`.
|
编写 Redux action 就像声明具有 type 属性的对象一样简单, 声明一个对象 `action` 并为它设置一个属性 `type`,并将它的值设置成字符串`'LOGIN'`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
An action object should exist.
|
`action` 对象应该存在。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -28,7 +28,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
The action should have a key property type with value `LOGIN`.
|
`action` 对象应该有一个值为 `LOGIN` 的 `type` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614e
|
id: 5a24c314108439a4d403614e
|
||||||
title: Define an Action Creator
|
title: 定义一个 Action Creator
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301441
|
forumTopicId: 301441
|
||||||
dashedName: define-an-action-creator
|
dashedName: define-an-action-creator
|
||||||
@ -8,27 +8,27 @@ dashedName: define-an-action-creator
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
After creating an action, the next step is sending the action to the Redux store so it can update its state. In Redux, you define action creators to accomplish this. An action creator is simply a JavaScript function that returns an action. In other words, action creators create objects that represent action events.
|
创建 action 后要将 action 发送到 Redux store,以便它可以更新其状态。 在 Redux 中,可以定义动作创建器来完成此任务, action creator 只是一个返回动作的 JavaScript 函数, 换句话说,action creator 创建表示动作事件的对象。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Define a function named `actionCreator()` that returns the `action` object when called.
|
定义名为 `actionCreator()` 的函数,该函数在调用时返回 `action` 对象。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The function `actionCreator` should exist.
|
函数 `actionCreator` 应该存在。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof actionCreator === 'function');
|
assert(typeof actionCreator === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
Running the `actionCreator` function should return the action object.
|
运行 `actionCreator` 函数应返回 `action` 对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof action === 'object');
|
assert(typeof action === 'object');
|
||||||
```
|
```
|
||||||
|
|
||||||
The returned action should have a key property type with value `LOGIN`.
|
返回的 `action` 对象应该有一个值为 `LOGIN` 的 `type` 属性。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(action.type === 'LOGIN');
|
assert(action.type === 'LOGIN');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614f
|
id: 5a24c314108439a4d403614f
|
||||||
title: Dispatch an Action Event
|
title: 分发 Action Event
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301442
|
forumTopicId: 301442
|
||||||
dashedName: dispatch-an-action-event
|
dashedName: dispatch-an-action-event
|
||||||
@ -8,9 +8,9 @@ dashedName: dispatch-an-action-event
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
`dispatch` method is what you use to dispatch actions to the Redux store. Calling `store.dispatch()` and passing the value returned from an action creator sends an action back to the store.
|
`dispatch` 方法用于将 action 分派给 Redux store, 调用 `store.dispatch()` 将从 action creator 返回的值发送回 store。
|
||||||
|
|
||||||
Recall that action creators return an object with a type property that specifies the action that has occurred. Then the method dispatches an action object to the Redux store. Based on the previous challenge's example, the following lines are equivalent, and both dispatch the action of type `LOGIN`:
|
回想一下,动作创建者返回一个具有 type 属性的对象,该属性指定已发生的动作。 然后该方法会将一个 action 对象发送到 Redux store。 基于上一个挑战的示例,下面的行是等效的,两者都会调度类 `LOGIN` 类型的 action:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
store.dispatch(actionCreator());
|
store.dispatch(actionCreator());
|
||||||
@ -19,23 +19,23 @@ store.dispatch({ type: 'LOGIN' });
|
|||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The Redux store in the code editor has an initialized state that's an object containing a `login` property currently set to `false`. There's also an action creator called `loginAction()` which returns an action of type `LOGIN`. Dispatch the `LOGIN` action to the Redux store by calling the `dispatch` method, and pass in the action created by `loginAction()`.
|
代码编辑器中的 Redux store 具有初始化状过的 state,包含 `login` 属性当前设置为 `false`的对象, 还有一个名为 `loginAction()` 的 action creator,它返回类型为 `LOGIN` 的 action, 然后通过调用 `dispatch` 方法将 `LOGIN` 的 action dispatch 给 Redux store,并传入 `loginAction()` 创建的 action。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Calling the function `loginAction` should return an object with `type` property set to the string `LOGIN`.
|
调用函数 `loginAction` 应该返回一个 `type` 属性设置为字符串 `LOGIN` 的对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(loginAction().type === 'LOGIN');
|
assert(loginAction().type === 'LOGIN');
|
||||||
```
|
```
|
||||||
|
|
||||||
The store should be initialized with an object with property `login` set to `false`.
|
store 应该用属性 `login` 设置为 `false` 的对象初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(store.getState().login === false);
|
assert(store.getState().login === false);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `store.dispatch()` method should be used to dispatch an action of type `LOGIN`.
|
`store.dispatch()` 方法应该被用于 dispatch 一个类型为 `LOGIN` 的 action。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d403614c
|
id: 5a24c314108439a4d403614c
|
||||||
title: Get State from the Redux Store
|
title: 从 Redux Store 获取状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301443
|
forumTopicId: 301443
|
||||||
dashedName: get-state-from-the-redux-store
|
dashedName: get-state-from-the-redux-store
|
||||||
@ -8,21 +8,21 @@ dashedName: get-state-from-the-redux-store
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
The Redux store object provides several methods that allow you to interact with it. For example, you can retrieve the current `state` held in the Redux store object with the `getState()` method.
|
Redux store 对象提供了几种与之交互的方法, 比如,可以使用 `getState()` 方法检索 Redux store 对象中保存的当前 `state`。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code from the previous challenge is re-written more concisely in the code editor. Use `store.getState()` to retrieve the `state` from the `store`, and assign this to a new variable `currentState`.
|
在代码编辑器中可以将上一个挑战中的代码更简洁地重写, 在 `store` 中使用 `store.getState()` 检索`state`,并将其分配给新变量 `currentState`。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The redux store should have a value of 5 for the initial state.
|
Redux store 的 state 应该有一个初始值 5。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(store.getState() === 5);
|
assert(store.getState() === 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
A variable `currentState` should exist and should be assigned the current state of the Redux store.
|
应该存在一个变量 `currentState`,并为其分配 Redux store 的当前状态。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) =>
|
(getUserInput) =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036150
|
id: 5a24c314108439a4d4036150
|
||||||
title: Handle an Action in the Store
|
title: 在 Store 里处理 Action
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301444
|
forumTopicId: 301444
|
||||||
dashedName: handle-an-action-in-the-store
|
dashedName: handle-an-action-in-the-store
|
||||||
@ -8,29 +8,29 @@ dashedName: handle-an-action-in-the-store
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
After an action is created and dispatched, the Redux store needs to know how to respond to that action. This is the job of a `reducer` function. Reducers in Redux are responsible for the state modifications that take place in response to actions. A `reducer` takes `state` and `action` as arguments, and it always returns a new `state`. It is important to see that this is the **only** role of the reducer. It has no side effects — it never calls an API endpoint and it never has any hidden surprises. The reducer is simply a pure function that takes state and action, then returns new state.
|
在一个 action 被创建并 dispatch 之后,Redux store 需要知道如何响应该操作。 这就是 `reducer` 函数存在的意义。 Redux 中的 Reducers 负责响应 action 然后进行状态的修改。 `reducer` 将 `state` 和 `action` 作为参数,并且它总是返回一个新的 `state`。 我们要知道这是 reducer 的**唯一**的作用。 它不应有任何其他的作用:比如它不应调用 API 接口,也不应存在任何潜在的副作用。 reducer 只是一个接受状态和动作,然后返回新状态的纯函数。
|
||||||
|
|
||||||
Another key principle in Redux is that `state` is read-only. In other words, the `reducer` function must **always** return a new copy of `state` and never modify state directly. Redux does not enforce state immutability, however, you are responsible for enforcing it in the code of your reducer functions. You'll practice this in later challenges.
|
Redux 的另一个关键原则是 `state` 是只读的。 换句话说,`reducer` 函数必须**始终**返回一个新的 `state`,并且永远不会直接修改状态。 Redux 不强制改变状态,但是需要在 reducer 函数的代码中强制执行它, 以后的挑战会练习这一点。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
The code editor has the previous example as well as the start of a `reducer` function for you. Fill in the body of the `reducer` function so that if it receives an action of type `'LOGIN'` it returns a state object with `login` set to `true`. Otherwise, it returns the current `state`. Note that the current `state` and the dispatched `action` are passed to the reducer, so you can access the action's type directly with `action.type`.
|
代码编辑器中具有前面的示例以及一个 `reducer` 函数。 需要完善 `reducer` 函数的内容,使得它如果收到类型为`'LOGIN'`的action,它将返回一个将 `login` 设置为 `true` 的 state 对象。 否则,它就返回当前的 `state`。 请注意,当前 `state` 和 dispatch 的 `action` 将被传递给 reducer,因此可以使用 `action.type` 直接获取 action 的类型。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Calling the function `loginAction` should return an object with type property set to the string `LOGIN`.
|
调用函数 `loginAction` 应该返回一个 type 属性设置为字符串 `LOGIN` 的对象。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(loginAction().type === 'LOGIN');
|
assert(loginAction().type === 'LOGIN');
|
||||||
```
|
```
|
||||||
|
|
||||||
The store should be initialized with an object with property `login` set to `false`.
|
store 应该用属性 `login` 设置为 `false` 的对象初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(store.getState().login === false);
|
assert(store.getState().login === false);
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching `loginAction` should update the `login` property in the store state to `true`.
|
dispatch `loginAction` 后应将 store 中 state 的 `login` 值更新为 `true`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -43,7 +43,7 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
If the action is not of type `LOGIN`, the store should return the current state.
|
如果 action 的类型不是 `LOGIN`,那么 store 应返回当前的 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036158
|
id: 5a24c314108439a4d4036158
|
||||||
title: Never Mutate State
|
title: 永不改变状态
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301445
|
forumTopicId: 301445
|
||||||
dashedName: never-mutate-state
|
dashedName: never-mutate-state
|
||||||
@ -8,19 +8,19 @@ dashedName: never-mutate-state
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
These final challenges describe several methods of enforcing the key principle of state immutability in Redux. Immutable state means that you never modify state directly, instead, you return a new copy of state.
|
这些最后的挑战描述了在 Redux 中强制执行状态不变性关键原则的几种方法。 不可变状态意味着永远不直接修改状态,而是返回一个新的状态副本。
|
||||||
|
|
||||||
If you took a snapshot of the state of a Redux app over time, you would see something like `state 1`, `state 2`, `state 3`,`state 4`, `...` and so on where each state may be similar to the last, but each is a distinct piece of data. This immutability, in fact, is what provides such features as time-travel debugging that you may have heard about.
|
如果拍摄 Redux 应用程序一段时间状态的快照,会看到类似 `state 1`,`state 2`,`state 3`,`state 4`,`...`等等,每个状态可能与最后一个状态相似,但每个状态都是一个独特的数据。 事实上,这种不变性提供了时间旅行调试等功能。
|
||||||
|
|
||||||
Redux does not actively enforce state immutability in its store or reducers, that responsibility falls on the programmer. Fortunately, JavaScript (especially ES6) provides several useful tools you can use to enforce the immutability of your state, whether it is a `string`, `number`, `array`, or `object`. Note that strings and numbers are primitive values and are immutable by nature. In other words, 3 is always 3. You cannot change the value of the number 3. An `array` or `object`, however, is mutable. In practice, your state will probably consist of an `array` or `object`, as these are useful data structures for representing many types of information.
|
Redux 并没有主动地在其 store 或者 reducer 中强制执行状态不变性,责任落在程序员身上。 幸运的是,JavaScript(尤其是 ES6)提供了一些有用的工具,可以用来强制执行状态的不变性,无论是 `string`,`number`,`array` 或 `object`。 请注意,字符串和数字是原始值,并且本质上是不可变的。 换句话说,3 总是 3, 不能改变数字 3 的值。 然而,`array` 或 `object` 是可变的。 实际上,状态可能会包括 `array` 或 `object`,因为它们经常用来描述一些代表信息的数据结构。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
There is a `store` and `reducer` in the code editor for managing to-do items. Finish writing the `ADD_TO_DO` case in the reducer to append a new to-do to the state. There are a few ways to accomplish this with standard JavaScript or ES6. See if you can find a way to return a new array with the item from `action.todo` appended to the end.
|
代码编辑器中有一个 `store` 和 `reducer`,用于管理待办事项。 完成 reducer 里的 `ADD_TO_DO` 用例,使其可以将一个新的待办事项附加到 state。 使用通过标准 JavaScript 或 ES6 的一些方法实现此目的。 看看是否可以找到一种方法来返回一个新数组,其中来自 `action.todo` 的项目添加到数组的末尾。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
The Redux store should exist and initialize with a state equal to the `todos` array in the code editor.
|
Redux store 应该在代码编辑器中存在并使用名字为 `todos` 的数组进行状态初始化。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -39,13 +39,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`addToDo` and `immutableReducer` both should be functions.
|
`addToDo` 和 `immutableReducer` 都应该是函数。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
|
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
|
||||||
```
|
```
|
||||||
|
|
||||||
Dispatching an action of type `ADD_TO_DO` on the Redux store should add a `todo` item and should NOT mutate state.
|
在 Redux store 上 dispatch 一个类型为 `ADD_TO_DO` 的 aciton,应该添加一个 `todo` 项,并且不应该改变 state。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: 5a24c314108439a4d4036153
|
id: 5a24c314108439a4d4036153
|
||||||
title: Register a Store Listener
|
title: 注册 Store 监听器
|
||||||
challengeType: 6
|
challengeType: 6
|
||||||
forumTopicId: 301446
|
forumTopicId: 301446
|
||||||
dashedName: register-a-store-listener
|
dashedName: register-a-store-listener
|
||||||
@ -8,15 +8,15 @@ dashedName: register-a-store-listener
|
|||||||
|
|
||||||
# --description--
|
# --description--
|
||||||
|
|
||||||
Another method you have access to on the Redux `store` object is `store.subscribe()`. This allows you to subscribe listener functions to the store, which are called whenever an action is dispatched against the store. One simple use for this method is to subscribe a function to your store that simply logs a message every time an action is received and the store is updated.
|
在 Redux `store` 对象上访问数据的另一种方法是 `store.subscribe()`。 这允许将监听器函数订阅到 store,只要 action 被 dispatch 就会调用它们。 这个方法的一个简单用途是为 store 订阅一个函数,它只是在每次收到一个 action 并且更新 store 时记录一条消息。
|
||||||
|
|
||||||
# --instructions--
|
# --instructions--
|
||||||
|
|
||||||
Write a callback function that increments the global variable `count` every time the store receives an action, and pass this function in to the `store.subscribe()` method. You'll see that `store.dispatch()` is called three times in a row, each time directly passing in an action object. Watch the console output between the action dispatches to see the updates take place.
|
编写一个回调函数,每次 store 收到一个 action 时,它会递增全局变量 `count`,并将此函数传递给 `store.subscribe()` 方法。 将会看到 `store.dispatch()` 连续三次被调用,每次都直接传入一个 action 对象。 观察 dispatch action 之间的控制台输出,看看是否发生了更新。
|
||||||
|
|
||||||
# --hints--
|
# --hints--
|
||||||
|
|
||||||
Dispatching the `ADD` action on the store should increment the state by `1`.
|
在 store 上 dispatch `ADD` action 应该使计数器增加 `1`。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(
|
assert(
|
||||||
@ -29,13 +29,13 @@ assert(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
There should be a listener function subscribed to the store using `store.subscribe`.
|
应该有一个监听函数 `store.subscribe` 订阅 store。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(getUserInput) => assert(getUserInput('index').includes('store.subscribe('));
|
(getUserInput) => assert(getUserInput('index').includes('store.subscribe('));
|
||||||
```
|
```
|
||||||
|
|
||||||
The callback to `store.subscribe` should also increment the global `count` variable as the store is updated.
|
在更新 store 时,`store.subscribe` 应该在回调中使全局变量 `count` 增加。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
assert(store.getState() === count);
|
assert(store.getState() === count);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user