React培训课程第27部分:课程项目

在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.jsApp.js 。 您可以完全删除此代码并尝试自己编写,以在React-applications的标准机制的实现中进行测试。

在此项目中,邀请您使用以下样式:

 * {   box-sizing: border-box; } body {   margin: 0;   background-color: whitesmoke; } header {   height: 100px;   display: flex;   align-items: center;   background: #6441A5;  /* fallback for old browsers */   background: -webkit-linear-gradient(to right, #2a0845, #6441A5);  /* Chrome 10-25, Safari 5.1-6 */   background: linear-gradient(to right, #2a0845, #6441A5); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ } 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 { /* Chrome/Opera/Safari */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input::-moz-placeholder { /* Firefox 19+ */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-ms-input-placeholder { /* IE 10+ */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-moz-placeholder { /* Firefox 18- */ font-family: VT323, monospace; font-size: 25px; text-align: cen } 

这些样式可以包含在项目中已经存在的index.css文件中,也可以包含在index.js文件中。

因此,基于index.jsApp.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")) 

在这里,我们导入ReactReactDOM ,从index.cssApp组件导入样式。 之后,使用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组件。 现在,邀请您通过向其写入以下数据来独立初始化此组件的状态:

  • 显示在模因顶部的文本( topText属性)。
  • 显示在模因底部的文本( bottomText属性)。
  • 随机图像(需要使用链接http://i.imgflip.com/1bij.jpg初始化的randomImage属性)。

这是初始化状态后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 ,该代码与该组件的上述代码不同,因为在此处添加了空白表单,您可以自己创建几个文本字段topTextbottomText 。 请记住,这些必须是托管组件。 向它们添加必要的属性。 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>元素中显示此图像的操作。 allMemeImgsallMemeImgs存储描述图像的对象数组,并且该数组中的每个对象都具有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。

亲爱的读者们! 完成本课程项目时是否遇到任何困难?

Source: https://habr.com/ru/post/zh-CN447136/


All Articles