在React培训课程的翻译的这一部分中,要求您创建一个模因生成器。

→
第1部分:课程概述,React,ReactDOM和JSX普及的原因→
第2部分:功能组件→
第3部分:组件文件,项目结构→
第4部分:父级和子级组件→
第5部分:TODO应用程序的开始工作,样式设计的基础→
第6部分:关于本课程的一些功能,JSX和JavaScript→
第7部分:内联样式→
第8部分:继续研究TODO应用程序,熟悉组件的属性→
第9部分:组件属性→
第10部分:使用组件特性和样式的研讨会→
第11部分:动态标记生成和映射数组方法→
第12部分:研讨会,TODO应用程序的第三阶段工作→
第13部分:基于类的组件→
第14部分:关于基于类的组件,组件状态的研讨会→
第15部分:组件健康研讨会→
第16部分:TODO应用程序的第四阶段工作,事件处理→
第17部分:TODO应用程序的第五阶段工作,修改组件的状态→
第18部分:TODO应用程序的第六阶段工作→
第19部分:组件生命周期方法第20部分:条件渲染的第一课→
第21部分:关于条件渲染的第二课和研讨会→
第22部分:TODO应用程序的第七阶段工作,从外部资源下载数据→
第23部分:关于使用表格的第一课→
第24部分:第二形式课→
第25部分:使用表单的研讨会→
第26部分:应用程序体系结构,容器/组件模式→
第27部分:课程项目课45.课程项目。 模因发生器
→
原创因此,我们进入了课程项目。 让我们创建一个将产生模因的应用程序。 让我们从使用以下命令创建的标准create-react-app项目开始:
npx create-react-app meme-generator
在这里您可以找到有关其使用功能的信息。
在该项目的工作过程中,将要求您自己实施其中的某些部分,然后阅读有关它们的说明。 标准项目已经具有样板代码,尤其是位于
index.js
和
App.js
。 您可以完全删除此代码并尝试自己编写,以在React-applications的标准机制的实现中进行测试。
在此项目中,邀请您使用以下样式:
* { box-sizing: border-box; } body { margin: 0; background-color: whitesmoke; } header { height: 100px; display: flex; align-items: center; background: #6441A5; background: -webkit-linear-gradient(to right, #2a0845, #6441A5); background: linear-gradient(to right, #2a0845, #6441A5); } header > img { height: 80%; margin-left: 10%; } header > p { font-family: VT323, monospace; color: whitesmoke; font-size: 50px; margin-left: 60px; } .meme { position: relative; width: 90%; margin: auto; } .meme > img { width: 100%; } .meme > h2 { position: absolute; width: 80%; text-align: center; left: 50%; transform: translateX(-50%); margin: 15px 0; padding: 0 5px; font-family: impact, sans-serif; font-size: 2em; text-transform: uppercase; color: white; letter-spacing: 1px; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 0 2px 0 #000, 2px 0 0 #000, 0 -2px 0 #000, -2px 0 0 #000, 2px 2px 5px #000; } .meme > .bottom { bottom: 0; } .meme > .top { top: 0; } .meme-form { width: 90%; margin: 20px auto; display: flex; justify-content: space-between; } .meme-form > input { width: 45%; height: 40px; } .meme-form > button { border: none; font-family: VT323, monospace; font-size: 25px; letter-spacing: 1.5px; color: white; background: #6441A5; } .meme-form > input::-webkit-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input::-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-ms-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen }
这些样式可以包含在项目中已经存在的
index.css
文件中,也可以包含在
index.js
文件中。
因此,基于
index.js
和
App.js
文件现在为空的假设,作为第一个任务,邀请您
index.js
编写
index.js
代码,在
App.js
创建最简单的组件并将其输出到
index.js
。
这是应该出现在
index.js
:
import React from "react" import ReactDOM from "react-dom" import './index.css' import App from "./App" ReactDOM.render(<App />, document.getElementById("root"))
在这里,我们导入
React
和
ReactDOM
,从
index.css
和
App
组件导入样式。 之后,使用
ReactDOM.render()
方法,将
App
组件形成的内容
ReactDOM.render()
到带有
root
标识符(
<div id="root"></div>
)的
index.html
页面的元素中。
这是
App.js
文件的样子:
import React from "react" function App() { return ( <h1>Hello world!</h1> ) } export default App
现在介绍最简单的功能组件。
在这个阶段,该项目看起来如下图所示。
浏览器中的应用现在,在两个名称与组件名称相对应的文件中创建两个新组件:
Header
组件,将用于显示应用程序标题。MemeGenerator
组件,将解决分配给应用程序的主要任务。 即,将在此处执行对API的调用。 应用程序数据将存储在此处。
考虑将什么功能分配给这些组件,请考虑它们应该是什么。
这是
Header.js
文件的内容:
import React from "react" function Header() { return ( <h1>HEADER</h1> ) } export default Header
由于此组件仅用于显示应用程序标头,因此我们将其设计为功能组件。
这是
MemeGenerator.js
文件的代码:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state ={} } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
在这里,考虑到应该通过
MemeGenerator
组件解决的任务,我们将使用基于类的组件。 这里有一个构造函数,其中我们用一个空对象初始化状态。
创建这些文件后,我们将它们导入
App.js
并从
App
的功能组件返回标记,该组件使用这些组件的实例,不要忘记,如果该功能组件返回多个元素,则需要将它们包装在某些东西中。 在我们的例子中,这是
<div>
。 这是更新的
App.js
代码:
import React from "react" import Header from "./Header" import MemeGenerator from "./MemeGenerator" function App() { return ( <div> <Header /> <MemeGenerator /> </div> ) } export default App
检查应用程序的外观。
浏览器中的应用现在让我们研究
Header
组件。 在这里,我们将使用语义元素HTML5
<header>
。 该标签将包含图像和文本。 现在,
Header.js
文件的代码将如下所示:
import React from "react" function Header() { return ( <header> <img src="http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png" alt="Problem?" /> <p>Meme Generator</p> </header> ) } export default Header
这是应用外观的变化方式。
浏览器中的应用应用程序标题是根据
index.js
先前
index.js
的样式设计的。
Header
组件的工作现已完成。
MemeGenerator
继续处理
MemeGenerator
组件。 现在,邀请您通过向其写入以下数据来独立初始化此组件的状态:
这是初始化状态后
MemeGenerator.js
代码的内容:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg" } } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
现在,应用程序的外观将不受影响。
我们将使用对API的调用,该API将返回可以创建模因的对象数组,其中包含指向图像的链接。 在该项目的工作阶段,邀请您在
MemeGenerator
组件中实现以下功能:
在这里,为了更清楚一点,访问此API时返回了JSON数据的一部分:
{ "success":true, "data":{ "memes":[ { "id":"112126428", "name":"Distracted Boyfriend", "url":"https:\/\/i.imgflip.com\/1ur9b0.jpg", "width":1200, "height":800, "box_count":3 }, { "id":"87743020", "name":"Two Buttons", "url":"https:\/\/i.imgflip.com\/1g8my4.jpg", "width":600, "height":908, "box_count":2 }, { "id":"129242436", "name":"Change My Mind", "url":"https:\/\/i.imgflip.com\/24y43o.jpg", "width":482, "height":361, "box_count":2 }, …. ] } }
解决上面提出的问题,有必要考虑以下事实:我们正在谈论组件在应用程序一开始就需要的数据。
因此,要加载它们,我们将诉诸
componentDidMount()
生命周期方法。 在这里,我们将使用标准的
fetch()
方法来调用API。 它返回一个承诺。 加载数据后,响应对象将可供我们使用,我们从中提取
memes
数组并将其放在新的状态属性
allMemeImgs
,并使用一个空数组进行初始化。 由于此数据尚未用于形成屏幕上显示的内容,因此我们将数组的第一个元素打印到控制台,以检查数据加载机制的正确操作。
这是工作阶段的
MemeGenerator
组件的代码:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data console.log(memes[0]) this.setState({ allMemeImgs: memes }) }) } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
这是成功加载数据后进入控制台的内容。
浏览器中的应用程序,输出到控制台中已加载数组的第一个元素请注意,使用许多属性来描述图像。 我们将仅使用
url
属性,该属性允许访问下载图像的链接。
在课程开始时,我们讨论了该应用程序的外观。
模因发生器特别是,其界面有几个用于输入文本的字段,这些字段将显示在图像的上部和下部。 现在,邀请您根据下面显示的
MemeGenerator
组件的更新代码进行
MemeGenerator
,该代码与该组件的上述代码不同,因为在此处添加了空白表单,您可以自己创建几个文本字段
topText
和
bottomText
。 请记住,这些必须是托管组件。 向它们添加必要的属性。
onChange
这些字段创建一个
onChange
事件
onChange
在其中输入文本时,您需要在其中更新相应的状态属性。
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } render() { return ( <div> <form className="meme-form"> { // } <button>Gen</button> </form> </div> ) } } export default MemeGenerator
顺便说一下,请注意以下事实:为了在
render()
方法返回的代码中包含注释,我们将其括在大括号中,以便向系统指示该片段应解释为JavaScript代码。
这是在应用程序的现阶段工作中应获得的:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> </div> ) } } export default MemeGenerator
现在,应用程序页面将如下图所示。
浏览器中的应用虽然仅显示带有帮助文本的字段,但在其中输入数据不会导致界面更改。 为了验证此处实现的机制是否正确运行,可以使用
console.log()
命令。
现在,我们将在应用程序中负责显示图像模因的部分。 回想一下,现在我们有了一个数组,其中包含有关计划用作模因基础的图像信息。 该应用程序应通过按
Gen
键,从此数组中随机选择一个图像并形成一个模因。
这是
MemeGenerator
组件的更新代码。 在此,在
render()
方法中,在表单描述代码下方,有一个
<div>
元素,其中包括一个显示图像的
<img>
元素,以及几个显示标签的
<h2>
元素。
<div>
和
<h2>
元素是使用在项目开始时就添加到项目中的样式设计的。
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
这是该应用现在的样子。
浏览器中的应用请注意,此处显示了初始化状态的图像。 我们尚未使用状态属性
allMemeImgs
中存储的图像。 让我们尝试在文本字段中输入一些内容。
浏览器中的应用如您所见,负责处理文本的应用程序子系统正在按预期运行。 现在,仅需确保通过按下
Gen
按钮,即可从具有图像数据的数组中选择随机图像并将其加载到
<img>
元素中,该元素位于文本输入字段下方的页面上。
为了使应用程序具备此功能-请执行以下任务。 创建一个单击“生成”按钮时将触发的方法。 此方法应选择一张图像,有关其图像的信息存储在状态属性
allMemeImgs
,然后执行允许您在文本输入字段下的
<img>
元素中显示此图像的操作。
allMemeImgs
,
allMemeImgs
存储描述图像的对象数组,并且该数组中的每个对象都具有
url
属性。
这是提供此问题解决方案的代码:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } handleSubmit(event) { event.preventDefault() const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length) const randMemeImg = this.state.allMemeImgs[randNum].url this.setState({ randomImg: randMemeImg }) } render() { return ( <div> <form className="meme-form" onSubmit={this.handleSubmit}> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
可以为
Gen
按钮分配一个事件处理程序,该事件处理程序在您单击它时就会发生,与其他任何按钮一样。 但是,鉴于使用此按钮提交表单的事实,最好使用表单的
onSubmit
事件
onSubmit
。 在此处理程序
handleSubmit()
,我们调用其中的
event.preventDefault()
事件的方法,以取消重新加载页面的标准表单
event.preventDefault()
过程。 接下来,我们获得一个随机数,其范围是从0到与
allMemeImgs
数组的最后一个元素的索引对应的值,并使用该数字来引用具有相应索引的元素。 转到作为对象的元素,我们获得该对象
url
的属性并将其写入状态属性
randomImg
。 此后,该组件将重新呈现,并且页面外观也会更改。
浏览器中的应用程序页面课程项目完成。
总结
在本课程中,您创建了一个应用程序,该应用程序使用了在掌握React时学到的知识。 下次,我们将讨论开发现代的React应用程序,并讨论项目构想,并加以实施,以供您实践使用React。
亲爱的读者们! 完成本课程项目时是否遇到任何困难?