HTML: <button type="button" class="btn btn-default btn-circle"><i class="glyphicon glyphicon-ok"></i></button>…
细数jQuery和React用法差别, jQuery转React, jQuery和React的区别, jQuery和React实例对比
我也听说过React.js很好,最近花了一些时间玩它。既然我对React非常满意,我决定写一个关于这个主题的教程。
目标受众群:足够了解jQuery的人
在开始之前,我想澄清一下我的目标受众是谁。
在从未尝试过React的人们中,有些人对Backbone,Ember或Angular之类的前端JS框架感到满意,有些人非常了解JavaScript,有些人知道足够的jQuery可以解决。
对其中一些人有效的教程,对他一些可能就不是最佳的。
在本教程中,我针对的是我提到的第三组:了解jQuery的人。可能适合该类别的人员包括:
- 可以在HTML / CSS / jQuery中进行基本编码的设计师。
- 知道如何使用jQuery插件的WordPress开发人员。
- 刚完成在线基本HTML / CSS / JS教程的开发人员。
- 依靠Bootstrap和基本jQuery满足其前端需求的后端开发人员。
- 在JavaScript方面,任何喜欢复制粘贴代码的人。
如果您对JavaScript或Backbone / Ember / Angular之类的任何前端框架感到满意,那么本教程不适合您,并且我的写作风格会让您感到沮丧。您可以从中学习很多很棒的教程,包括官方的React教程。另外,如果您已经知道React,那么您也会对我感到不高兴,因为我主要谈论的是状态而不是不变性或组合化。但是,我发现首先讲状态是jQuery开发人员了解React优越性的最好方法。
无论如何,让我们开始吧!
预计时间:1〜2小时
如果您走得很快(并且复制粘贴示例代码而不是键入内容),那么本教程将花费一个多小时。如果您走慢,则需要2个小时以上。
概述:我们将构建一个“ Tweet Box”
许多React.js教程都是从解释React的工作方式或为什么React很棒的开始。我的教程没有。
取而代之的是,我们将正确构建一个简单的UI,在jQuery实现和React.js实现之间进行交替,并解释其中的差异。我相信您会以更多的方式思考,而不是仅输入示例。
我们将构建的UI类似于您在Twitter上找到的Tweet框。它不会完全像真正的Tweet框,但会非常相似。希望您会发现这个例子很实际。
步骤1:JSBin简介(5至10分钟)
我们将使用JSBin,一个在线HTML / CSS / JS编辑器,它同时支持jQuery和React.js代码。您可能熟悉诸如CodePen或JSFiddle之类的类似服务-它们非常相似,因此我决定使用JSBin。
这是一个JSBin示例:
jsbin.com上的JS Bin 无法加载吗?请点击这里。
尝试修改左侧的 HTML-即更改按钮的文本。您会在右侧看到更改。这就是JSBin的工作方式。
创建一个JSBin帐户
除非您已经有一个JSBin帐户,否则请转到jsbin.com创建一个帐户。单击菜单上的登录或注册以创建帐户。
创建帐户后,您可以将公共JSBins 克隆到您的帐户中,就像克隆公共GitHub存储库一样。
让我们尝试一下。在下面的JSBin菜单上单击“保存”。
jsbin.com上的JS Bin 无法加载吗?请点击这里。
进入JSBin网站后,可以从菜单中选择“添加库”以导入流行的CSS / JS库。
尝试执行以下操作:
- 点击“添加库”并添加最新的Bootstrap
btn btn-primary
在上添加课程<button>
输出变得更漂亮:
jsbin.com上的JS Bin 无法加载吗?请点击这里。
创建一个推文框
您现在似乎对JSBin非常满意。好吧,让我们建立一个Tweet框。仍与以前使用同一JSBin,像这样更改HTML里面的内容<body>
:
<div class="well clearfix"> <textarea class="form-control"></textarea><br/> <button class="btn btn-primary pull-right">Tweet</button> </div>
我们使用自举类像form-control
,well
,clearfix
等等,但这些都只是对外观和不相干的教程。结果如下:
这就是步骤!还不错吧?
步骤2:实现第一个功能 – 禁用 Tweet 按钮(5分钟)
现在,该花点时间学习一些JS。我们将首先实现以下功能:
功能1:首先应禁用“ Tweet”按钮。如果文本字段中至少有一个字符,则应启用“ Tweet”按钮。
这是演示。如您所见,该按钮最初被禁用。如果在文本框中键入内容,该按钮将变为启用状态。
要使其正常工作,请从上一个JSBin继续,打开JavaScript选项卡,并添加以下jQuery代码。您不需要添加jQuery,因为我们在上一步中添加的Bootstrap包括jQuery。
// Initially disable the button $("button").prop("disabled", true); // When the value of the text area changes... $("textarea").on("input", function() { // If there's at least one character... if ($(this).val().length > 0) { // Enable the button. $("button").prop("disabled", false); } else { // Else, disable the button. $("button").prop("disabled", true); } });
说明
- 我使用了标签名
button
和textarea
作为选择器-对于这个简单的示例,无需添加ID /类。 - 要启用/禁用按钮,请使用
$(...).prop(disabled, ...)
。 - 要监听中的更改
textarea
,请使用input
在现代浏览器上有效的事件。
通过在“推文”框中键入一些文本并查看按钮的启用/禁用状态更改来进行尝试。
如果这个例子让您感到困惑,请不要继续-您可能需要学习更多jQuery才能使用React。
现在,该功能已经完成,我们将尝试使用React重新实现相同的功能。这将需要几个步骤。
步骤3:使用React.js的Tweet框(5-10分钟)
在React中您会注意到的第一件事是,您将使用JS而不是HTML编写标记。
让我告诉你我的意思。这是显示相同Tweet框的React.js代码。
警告!您不需要继续学习-只需阅读代码。
一些观察:
- 里面
return (...)
是HTML代码,而不是JavaScript。在React中,您将使用称为JSX的特殊语法编写代码,该语法可将类似HTML的代码放入JavaScript中。 - 我说HTML-“ like”是因为它与HTML不同。请注意,它使用
className
代替class
-,但是它们非常相似,因此您将快速学习它们。 - 您的浏览器不了解JSX,因此当React处理您的JSX代码时,它将自动将JSX中的HTML部分转换为有效的JavaScript代码,以便浏览器可以理解它。
- 其中
return (...)
的HTML代码与步骤1中的HTML代码几乎相同。 - 尝试单击上述JSBin上的“ HTML”,您会发现HTML中除了之外没有其他标记
<body><div id="container"></div></body>
。这就是我在React中说的意思,您将使用JavaScript(JSX)而不是HTML编写标记。
常见问题与解答
问题:做什么React.createClass
和ReactDOM.render
做什么?我现在需要了解它们吗?
答:暂时不要担心。基本上,React.createClass
创建一个带有名称的UI(在本例中为TweetBox
)。然后通过ReactDOM.render(<TweetBox />, document.getElementById("container"))
– 将其附加到DOM,这意味着此UI已添加到<div id="container">
标记内。这就是您现在需要知道的。
问题:在本地计算机上编写JSX时,我需要做些特殊的事情吗?
答:是的,但这不在本教程的讨论范围之内-简而言之,您需要导入称为JSX转换器的东西(方法如下)。不过,在JSBin上不必执行此步骤。在JSBin上编写JSX所需要做的就是(1)从下拉列表中添加一个React库(一个没有插件的库),以及(2)从JS视图的下拉菜单中选择“ JSX(React)”。
问题:在同一位置编写标记(HTML)和行为(JS)是否不好?
答:对于简单的网页来说这可能是一种不好的风格,但对于大型的Web应用程序却不一定是这样。在大型Web应用程序中,将有数百个UI,每个UI包含自己的标记和行为。如果将每个UI的那些标记和行为放在一起,而不是将“所有标记”放在一起和“所有行为”放在一起,则代码将更易于管理。React是为开发大型Web应用程序而设计的。实际上,React实际上是由Facebook创建和使用的,Facebook是有史以来最大的Web应用程序之一。
接下来,我将向您展示如何逐步编写上述React代码。
第4步:编写您的第一个React.js代码(5至10分钟)
我为您创建了一个入门HTML文件。使用“添加库”,我导入了Bootstrap(删除了bootstrap.js和jquery)和React(没有附加组件)。
请尝试跟随。首先,单击“保存”以将其复制到您的JSBin中。
保存到您的JSBin后,打开JavaScript选项卡,然后选择“ JSX(反应)”:
现在您可以编写一些React了。尝试遵循并在您的JSBin上键入以下JS代码段。
var TweetBox = React.createClass({ render: function() { } });
这是使用React(在本例中为Tweet框)创建UI的模板。$(function() { ... })
与jQuery 一样重要。
要实际构建UI,我们必须填写该render()
方法。现在,让我们仅用一个div
标签就可以使其简单。
var TweetBox = React.createClass({ render: function() { return ( <div> Hello World! </div> ); } });
像上述例子中,把一对括号的(...)
后return
,并写入标记的内部。
JSX陷阱
启用JSX时render()
,您需要记住一件事,里面必须恰好有一个最外面的标签return (...)
。
因此以下操作无效,因为最外面的标签为零:
return ( Hello World! );
这也不起作用,因为里面有两个最外面的(span
)标签return (...)
:
return ( <span> Hello </span> <span> World </span> );
对于上面的示例,解决方法是创建一个包装两个span
标签的额外标签。我只是div
在这里用过。使用React时这是必不可少的。
return ( <div> <span> Hello </span> <span> World </span> </div> );
将UI附加到DOM
现在,我们需要将该UI“附加”到DOM才能看到Hello World
。为此,在我们刚刚编写的代码下面添加ReactDOM.render()
:
var TweetBox = React.createClass({ ... }); ReactDOM.render( <TweetBox />, document.getElementById("container") );
(请注意:...
代码段中的省略号()表示为清楚起见已省略了代码。换句话说,请勿触摸代码的这一部分并保持原样。)
ReactDOM.render
有两个参数。第一个参数是UI对象,即<VariableName />
。第二个参数是DOM对象(在本例中为document.getElementById("container")
)。放在一起,上面的代码将TweetBox
UI 呈现在内部<div id="container">
。
现在,您应该看到Hello World
出现在您的JSBin上。恭喜,您编写了第一个React UI!
编写推文框的实际HTML
现在,代替Hello World
,我们将为Tweet Box实现HTML。交换内部代码render()
:
return ( <div className="well clearfix"> <textarea className="form-control"></textarea> <br/> <button className="btn btn-primary pull-right">Tweet</button> </div> );
您需要注意两件事:
- 不要使用
class
。而是使用className
。这是因为JSX被翻译成JS,并且class
是JS最新版本中的关键字。 - 如果您使用
<br>
代替<br/>
,它将无法正常工作。确保贴上/
自动关闭标签。
其他所有内容都应与之前的jQuery示例相同。
如果输入正确,则应该在JSBin上看到Tweet框。如果输出中没有任何内容,请非常仔细地检查代码,以确保没有错别字。
这就是步骤!这是到目前为止的JSBin:
第5步:重新实现第一个功能-应在React中最初禁用Tweet按钮-5至10分钟
我们将在React中重新实现我们使用jQuery实现的第一个功能:
功能1:首先应禁用“ Tweet”按钮。如果文本字段中至少有一个字符,则应启用“ Tweet”按钮。
这是我们编写的jQuery代码:
<!DOCTYPE html> <html> <head> <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" /> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div class="well clearfix"> <textarea class="form-control"></textarea><br> <button class="btn btn-primary pull-right">Tweet</button> </div> </body> </html>
// Initially disable the button $("button").prop("disabled", true); // When the value of the text area changes... $("textarea").on("input", function() { // If there's at least one character... if ($(this).val().length > 0) { // Enable the button. $("button").prop("disabled", false); } else { // Else, disable the button. $("button").prop("disabled", true); } });
让我们看看如何在React中做到这一点。
从上一步的JSBin开始。(提示:由于您不会在React中触摸HTML,因此可以关闭JSBin上的HTML选项卡,以便获得更多的屏幕空间。)
首先,让我们通过添加禁用按钮disabled
。
render: function() { return ( ... <button className="..." disabled>Tweet</button> ... ); }
然后,该按钮现在应该被禁用。注意,在我们的jQuery实现中,我们编写了:
$("button").prop("disabled", true);
最初禁用该按钮,但我们可以button
像上面那样修改标记。
现在,当文本字段中至少有一个字符时,我们需要启用该按钮。
处理变更事件
首先,我们需要等待用户输入文本。在我们的jQuery实现中,我们写道:
$("textarea").on("input", function() { ... }
在React领域,我们将事件处理程序编写为method。让我们称之为handleChange
:
React.createClass({ handleChange: function(event) { }, render: function() { ... } });
接下来,我们在输入文本时调用此处理程序。为此,请像这样修改textarea
标记render()
:
<textarea className="form-control" onChange={this.handleChange}></textarea>
- 我们将
input
事件用于jQuery,但是在React中我们将使用onChange
-您将从React文档中了解事件在React的JSX中的不同之处,所以现在不必太担心。 - 更重要的是,我们使用
{...}
语法在JSX的HTML语法部分内包含所有JavaScript代码。在这种情况下,我们要传递处理程序handleChange
,并为其加上前缀,this.
因为它是此UI对象上的方法。 - 如果您习惯使用jQuery,这似乎是一种不好的做法,但是请不要担心。同样,在大型应用程序中,如果对于每个用户界面,这些标记和行为都保持在一起,则代码将更易于管理。
为了确保确实调用了该处理程序,让我们在console.log
里面添加handleChange
:
handleChange: function(event) { console.log(event.target.value); },
所述event
对象包含target
,这是textarea
。我们用.value
它来输出的当前值textarea
。
在您的JSBin中,打开console
选项卡以检查输出。然后在“推文”框中键入内容。
您可以在这里尝试:
注意:完成后,关闭JSBin上的控制台选项卡。我们不再需要它。
步骤6:执行中的状态(10到15分钟)
现在,我将解释jQuery风格的代码和React.js风格的代码之间的最大区别之一。
在jQuery中,当发生某些事件时,通常会更改DOM(就像我们之前所做的那样):
在React中,您不会直接修改DOM。相反,在事件处理程序中,您可以修改称为“状态”的内容。这是通过调用来完成的this.setState
。
然后,每次状态更新时,render()
都会再次调用。而且在render()里面
你可以访问状态。
这是您响应事件来更新UI的方式。是的,这很令人困惑,所以让我解释一下代码。
编写事件处理程序
从上一步的JSBin开始。首先,我们需要初始化状态对象 -如果没有此对象,则将无法执行任何操作。
为此,我们需要编写一个称为的特殊方法getInitialState
,并使其返回一个JS对象,该对象成为初始状态。
对象中有什么?让我们创建一个名为的密钥,text
并将其存储在Tweet框中的任何内容。
var TweetBox = React.createClass({ getInitialState: function() { return { text: "" }; }, handleChange: ... render: ... });
接下来,我们将修改事件处理程序,以将状态text
字段设置为当前文本框中的内容。为此,我们使用一种特殊的内置方法,称为,setState
并传递更新的键值对。
handleChange: function(event) { this.setState({ text: event.target.value }); },
现在,我们通过在中编写一些仅调试的代码来检查状态是否已正确设置render()
。
为此,只需this.state.text
在的末尾添加render()
,然后使用该{ ... }
语法在JSX的HTML语法部分内调用JS代码。
render: function() { return ( <div ...> ... <button ...>Tweet</button> <br/> {this.state.text} </div> ) }
现在,尝试在推文框中输入一些文本。同一组文本应显示在按钮下方。
您也可以在下面的JSBin上尝试一下:
现在,上一张图可能对您更有意义。
删除调试代码
确认正确设置了状态后,请删除我们刚刚添加的调试代码:
<br/> {this.state.text}
启用/禁用按钮
现在我们可以监视文本的更改,剩下的就是根据是否输入文本来启用/禁用按钮。
使用状态,我们可以使用以下逻辑:
- 如果为
this.state.text.length === 0
,则应禁用该按钮。
要在React中执行此操作,请添加disabled
属性,并将其设置为返回值this.state.text.length === 0
。由于这是JS代码,因此需要使用进行包装{}
。
<button className="btn btn-primary pull-right" disabled={this.state.text.length === 0}>Tweet</button>
如果您使用原始HTML 编写disabled="true"
或disabled="false"
使用原始HTML,则无法使用-在原始HTML中,您需要删除disabled
属性以启用按钮。但是React 不是原始的HTML-它在幕后做了以下魔术:
- 如果
disabled={true}
使用JSX,它将转换为仅<button ... disabled>
HTML。 - 如果您
disabled={false}
使用JSX,disabled
则会从button
HTML 的标记中删除该属性。
这适用于其他布尔属性,例如checked
。撰写本文时尚未正式记录,但应尽快将其包括在内。
生成的JSBin在这里:
感言
同样,在继续下一步之前,请记住jQuery和React之间的区别:
- 在jQuery中,您编写了修改DOM的事件处理程序。
- 在React.js中,您编写了可修改state的事件处理程序。然后您写
render()
以反映当前状态。
步骤7:jQuery中的剩余字符数(5分钟)
我们将实现的下一个功能是剩余字符数。
规格如下:
- 将显示字符数
140 - the number of characters entered
。
我们将首先在jQuery中实现,然后在React中实现。
我们将从先前的jQuery实现开始。我们将保留我们的React.js代码。从现在开始,随着我们在jQuery和React之间交替,我将在每章的开头为您提供新的代码。这意味着在完成每个步骤之后,您可以先处理代码,然后再进行下一步。
首先,使用来添加HTML中的字符数span
。让我们将其设置为span
:
<textarea ...></textarea><br> <span>140</span> <button ...>Tweet</button>
而input里面
的JS处理程序,添加以下代码来更新字符数:
$("textarea").on("input", function() { $("span").text(140 - $(this).val().length); ... });
而已!尝试在“推文”框中键入内容,您会看到字符计数更新。这是JSBin:
步骤8:React.js中的剩余字符数(5分钟)
在React中怎么样?您应该尝试自己执行此操作。从我们之前的React实现开始。
- 无需更改
getInitialState()
或handleChange()
this.state.text.length
在中使用render()
。
回答:
在
render()中<br/>
以下添加:
<span>{140 - this.state.text.length}</span>
太容易了?不知道为什么React.js比jQuery好得多吗?好了,下一步变得更加复杂了,这就是React.js真正发挥作用的时候。
第9步:“添加照片”按钮(5分钟)
对于我们的下一个功能,我们将向用户界面添加“添加照片”按钮。这是事情变得棘手的时候。
但是,我们实际上不会允许用户上传照片。相反,这是我们要做的。
当您在Twitter上上传照片时,它会计入您可以使用的字符数。我尝试将剩余字符数从140个减少到117个:
这就是我们要做的。规格如下:
- 创建一个“添加照片”按钮。
- 单击此按钮可切换开/关状态。如果打开,按钮将显示
✓ Photo Added
。 - 如果此按钮为开,则可用字符数减少23。
- 同样,如果此按钮为ON,即使没有输入任何文本,“ Tweet”按钮仍保持启用状态。
这是演示JSBin。尝试单击“添加照片”按钮,查看字符数和“tweet”按钮会发生什么。
让我们实现它。我们将首先尝试使用jQuery。
步骤10:使用jQuery的“添加照片”按钮(15-20分钟)
从我们先前的jQuery实现开始。
我们将同时修改HTML和JS。之前,我们在上附加了一个处理程序$("button")
,但是如果有两个按钮,则此方法将无效。因此,让我们像这样修改HTML:
... <button class="js-tweet-button btn btn-primary pull-right" disabled>Tweet</button> <button class="js-add-photo-button btn btn-default pull-right">Add Photo</button> ...
更改如下:
- 添加了第二个按钮 “添加照片”。
- 添加了类
js-tweet-button
和js-add-photo-button
每个按钮。之所以加上前缀,js-
是因为它们仅在JS中使用,而不在CSS中使用。 - 将
disabled
属性添加到“推文”按钮,因此我不必在JS中执行此操作。
接下来,像这样重写整个JS文件:
$("textarea").on("input", function() { $("span").text(140 - $(this).val().length); if ($(this).val().length > 0) { $(".js-tweet-button").prop("disabled", false); } else { $(".js-tweet-button").prop("disabled", true); } });
更改如下:
- (重要)
$("button").prop("disabled", true);
已从第一行删除,因为我disabled
在“推特”按钮中添加了属性, - 替换为
$("button")
,$(".js-tweet-button")
因此可以与区别.js-add-photo-button
。
添加按钮
接下来,我们将实现以下功能之一:
- 单击“添加照片”按钮切换ON / OFF状态。如果打开,按钮将显示
✓ Photo Added
。
为此,我们添加以下代码:
$("textarea").on("input", function() { ... }); $(".js-add-photo-button").on("click", function() { if ($(this).hasClass("is-on")) { $(this) .removeClass("is-on") .text("Add Photo"); } else { $(this) .addClass("is-on") .text("✓ Photo Added"); } });
我们使用该类is-on
来跟踪状态。多次单击“添加照片”按钮,然后交替查看文本,以检查是否有效。
减字符数
接下来,我们将实现此功能:
- 如果“添加照片”按钮为开,则可用字符数减少23。
为此,请像这样修改刚刚添加的点击处理程序。
if ($(this).hasClass("is-on")) { $(this) .removeClass("is-on") .text("Add Photo"); $("span").text(140 - $("textarea").val().length); } else { $(this) .addClass("is-on") .text("✓ Photo Added"); $("span").text(140 - 23 - $("textarea").val().length); }
span
每次点击都会更改的文本。如果按钮变为ON,则需要从117中减去文本长度,即140 - 23
。140 - 23
现在我们为了清楚起见使用-最终我们应该使用常量。
单击“添加照片”按钮,以检查是否可以使用。
修复输入处理程序
但是,这还不完整- 如果您打开了“添加照片”按钮并开始在文本区域中键入内容,则剩余字符数将不同步。
要解决此问题,我们还需要更新以下输入处理程序textarea
:
$("textarea").on("input", function() { if ($(".js-add-photo-button").hasClass("is-on")) { $("span").text(140 - 23 - $(this).val().length); } else { $("span").text(140 - $(this).val().length); } if (...) { ... });
请检查该作品点击“上传照片”按钮,并输入一些文字。
我知道这需要一些时间…
但是坚持下去!此处的jQuery代码应该令人困惑,所以不用担心!
实施最终功能
我们需要实现的最后一个功能是:
- 如果“添加照片”按钮为开,则即使没有输入文字,“推文”按钮仍保持启用状态。
为此,我们需要修改“添加照片”按钮的点击处理程序:
$(".js-add-photo-button").on("click", function() { if ($(this).hasClass("is-on")) { ... if ($("textarea").val().length === 0) { $(".js-tweet-button").prop("disabled", true); } } else { ... $(".js-tweet-button").prop("disabled", false); } });
解释如下:
- 如果“添加照片”按钮从“开”变为“关”(
if
子句),我们需要检查是否未输入文本,如果是,请禁用“推文”按钮。 - 如果“添加照片”按钮从“关闭”变为“开启”(
else
子句),我们将始终启用“推文”按钮。
但是,这又被打破了
我们还没有完成。以下步骤将破坏代码。自己尝试一下:
- 打开“添加照片”按钮。
- 输入一些文字。
- 删除所有文本。
- 由于“添加照片”按钮处于打开状态,因此应该仍启用“推特”按钮,但实际情况并非如此。
这意味着我们的输入处理程序textarea
缺少一些逻辑。为了解决这个问题,我们需要if
在输入处理程序的语句中添加另一个条件。
$("textarea").on("input", function() { ... if ($(this).val().length > 0 || $(".js-add-photo-button").hasClass("is-on")) { ... } else { ... } });
我们对是否应禁用按钮添加了以下检查:
- 文本更改时,如果“添加照片”按钮为开,则不要禁用该按钮。
再次尝试上述步骤,这次不会中断。
第11步:对jQuery代码的思考-为什么如此令人困惑?(5分钟)
这是上一步的最终HTML和JS代码:
再次看一下jQuery代码。这非常令人困惑。如果您将代码保持原样,则可能需要一些注释,以便您记住所做的事情。有明显的重复迹象,但是您必须对如何重构进行一些思考。
问题是:为什么它变得如此丑陋如此之快?
答案与我们之前讨论的“ jQuery样式”有关。回想一下这个图:
当只有1个事件处理程序和1个DOM时,这很简单。但是,就像我们刚刚看到的那样,如果多个事件处理程序正在修改DOM的多个部分,则代码将变得难看。
想象添加了一些可能影响字符数限制和“ Tweet”按钮状态的功能。上图将有更多箭头。而且代码将变得难以管理。
从理论上讲,您可以通过重构为可重用的函数来减轻这种情况。但是,每次添加新内容时,您仍然都必须认真考虑一下。(更新:Hacker News的某人向我发送了重构的jQuery代码。非常干净,但是又需要一些思考。)
现在,让我们看看在React中做同样的事情的感觉。提示:它将变得更加简单。
步骤12:React中的“添加照片”按钮(10-20分钟)
从我们之前的React实现开始。
添加按钮
首先,让我们添加“添加照片”按钮。修改JSX:
<button ...>Tweet</button> <button className="btn btn-default pull-right">Add Photo</button>
现在,让我们向该按钮添加一个点击处理程序,以使文本从Add Photo
变为✓ Photo Added
。回想一下React的编写代码风格:
我们会:
- 创建一个状态变量,以跟踪“添加照片”按钮是打开还是关闭。
- 使用状态上
render()
,以决定是否显示Add Photo
或✓ Photo Added
。 - 修改点击处理程序上的状态。
对于(1),我们将getInitialState
在状态下修改并添加一个键值对,以跟踪是否添加了照片:
getInitialState: function() { return { text: "", photoAdded: false }; },
对于(2),我们将为 “添加照片”按钮修改JSX标记。如果this.state.photoAdded
为true,我们将显示“添加照片”按钮。我们可以在这里使用三元表达式。
<button className="btn btn-default pull-right"> {this.state.photoAdded ? "✓ Photo Added" : "Add Photo" } </button>
最后,对于(3),我们将在JSX上附加一个点击处理程序,就像对以下操作一样textarea
:
<button className="btn btn-default pull-right" onClick={this.togglePhoto}> {this.state.photoAdded ? "✓ Photo Added" : "Add Photo" } </button>
并添加一个与之相反的处理程序方法this.state.photoAdded
:
togglePhoto: function(event) { this.setState({ photoAdded: !this.state.photoAdded }); },
现在,单击Add Photo
将切换文本。自己尝试一下。
减字符数
现在,我们将实现下一个功能:
- 如果“添加照片”按钮为开,则可用字符数减少23。
当前,可用字符数显示如下render()
:
<span>{140 - this.state.text.length}</span>
现在这也将取决于this.state.photoAdded
,因此我们需要if
and else
在这里。
但是,在JSX中,您不能编写if
或else
inside{ ... }
。您可以a ? b : c
像以前一样使用三元表达式(),但是在这种情况下会很长。
通常,在这种情况下,最简单的方法是将条件重构为方法。让我们尝试一下。
首先,修改上面的代码以使用如下方法:
<span>{ this.remainingCharacters() }</span>
并定义如下方法:
remainingCharacters: function() { if (this.state.photoAdded) { return 140 - 23 - this.state.text.length; } else { return 140 - this.state.text.length; } },
现在,当切换“添加照片”按钮时,剩余字符数应相应更新。
问:在render()
,为什么{ this.remainingCharacters() }
有()
,但{ this.handleChange }
和{ this.togglePhoto }
没有?
好问题。让我们render()
再看一看:
render: function() { return ( ... <textarea className="..." onChange={ this.handleChange }></textarea> ... <span>{ this.remainingCharacters() }</span> ... <button className="..." onClick={ this.togglePhoto }> ... </button> </div> );
答:
- 我们已经编写
remainingCharacters()
了返回数字的方法。我们需要获取此数字并将其放在中间<span></span>
,因此我们需要使用来调用remainingCharacters()
method()
。这就是为什么有()
在remainingCharacters()
。 - 另一方面,
handleChange
和togglePhoto
是事件处理程序。我们希望仅在用户与UI交互(更改文本或单击按钮)时才调用这些方法。为此,在中render()
,我们需要编写不带它们的代码,()
并将它们分配给诸如onChange
和的属性onClick
。
“ Tweet”按钮的状态
我们还有另一个功能要实现:
- 如果“添加照片”按钮为开,则即使没有输入文字,“推文”按钮仍保持启用状态。
这实际上很容易做到。以前,“tweet”按钮的disabled
选项设置为:
<button ... disabled={this.state.text.length === 0}>...</button>
换句话说,以前如果文本的长度为0 ,则“ Tweet”按钮被禁用。现在,如果满足以下条件,则“ Tweet”按钮被禁用:
- 文字的长度为0,且:
- “添加照片”按钮处于关闭状态。
因此逻辑变为:
<button ... disabled={this.state.text.length === 0 && !this.state.photoAdded}>...</button>
或者,您可以利用简化上述代码remainingCharacters()
。如果剩余140个字符,则表示不输入任何文本,并且“添加照片”按钮为OFF,因此应禁用“ Tweet”按钮。
<button ... disabled={this.remainingCharacters() === 140}>...</button>
而已!尝试切换“添加照片”按钮,并检查“ Tweet按钮”是否已正确启用/禁用。
我们做完了!
那很简单。这是生成的JSBin:
步骤13:对React代码的反思-为什么这么简单?(5分钟)
使用React时,为适应“添加照片”按钮所做的更改很小。无需重构。为什么会这样呢?
同样,它与React编写UI代码的风格有关。在React中,事件处理程序会修改“状态”,并且每当修改状态时,React都会自动render()
再次调用以更新UI。
在此特定示例中,该图现在看起来像这样:
状态变成介于事件处理程序和render()
以下事件之间的中间事物:
- 事件处理程序不必担心DOM的哪一部分会更改。他们只需要设置状态。
- 同样,在编写时
render()
,您只需担心当前state
是什么。
与jQuery比较
您可以想象,随着UI获得更多功能,将会发生什么。没有中介“状态”,我们将很难处理复杂性。这就是为什么您要针对复杂的UI使用React over jQuery的原因。
同样,可以编写看起来不像意大利面条的干净的jQuery代码。但是您必须自己弄清楚代码结构,并在每次添加新功能时考虑如何重构。React为您提供了这种结构并减轻了您的认知负担。
步骤14:最终功能-突出显示溢出字符(5分钟)
我们要实现的最后一个功能是突出显示超出限制的字符。
不幸的是,我们不会在Tweet框内突出显示实际文本,因为这将需要我们更改textarea
为contenteditable
,并且contenteditable
出于说明目的太复杂了。
相反,我们将在顶部显示一个警告框,并指出需要删除的字符,如下所示:
要试用,请复制史蒂夫·乔布斯的以下报价:
如果尚未找到它,请继续寻找。别解决 与内心所有事情一样,当您找到它时就会知道。而且,就像任何伟大的关系一样,随着岁月的流逝,这种关系会越来越好。
并将其粘贴到下面的“ Tweet”框中:
- 它应该显示一个警告框,其中溢出的字符以红色突出显示
- 它也应该在截止点之前显示10个字符,并且不突出显示。
如果我们要在jQuery中实现这一点,我们的代码将更加混乱。请注意,在图中,我们将为一项新功能添加另外两个箭头。
所以我们不会在jQuery中实现它。我们将在React中进行,并称之为一天。在React中做起来非常简单-图表上只有一个额外的箭头:
第15步:突出显示React中的溢出字符(10-15分钟)
从我们之前的React实现开始。
我们将逐步进行此操作。首先,当您超出限制时,我们将显示一个简单的警报。该警报将包含一些静态文本。
由于这将需要条件,因此我们将其编写为单独的方法。在文本框前面添加{ this.overflowAlert() }
:
{ this.overflowAlert() } <textarea className="form-control" onChange={this.handleChange}></textarea>
现在,此方法应返回:
- 如果没有更多的字符,则为警报框的div标签。
- 否则没有其他内容(即空文本)。
事实证明,在React中,您可以从一个方法返回JSX标记,并在其他方法中使用它,一切都将正常工作。换句话说,您可以执行以下操作:
someMethod: function() { return ( <a href="#">Hello World</a> ); }, someMethod2: function() { return ( <h1> { this.someMethod() } </h1> ); },
在我们的情况下,我们可以( <div> ... </div> )
在一种情况下返回,而在另一种情况下什么也不能返回。因此,我们的overflowAlert
方法将如下所示:
overflowAlert: function() { if (this.remainingCharacters() < 0) { return ( <div className="alert alert-warning"> <strong>Oops! Too Long:</strong> </div> ); } else { return ""; } },
注意,我们正在检查this.remainingCharacters()
是否应该显示警报。
通过键入140+个字符(或在“添加照片”按钮为ON的情况下输入117+个字符)来尝试一下。它应该显示警报。
显示溢出字符
这是警报消息中内容的细分:
- 在“糟糕!太长:”和实际文本之间,有一个空的单个空格,后跟三个点。我
在这里使用它是因为在React中编写标记时,标签之间的空白会被删除。 - 然后是的第131〜140个字符(共10个)
this.state.text
。 - 然后,其余字符以红色突出显示。
让我们用JSX编写它。在的if
子句中overflowAlert
,我们将创建两个变量:beforeOverflowText
和overflowText
。我们将.substring()
在上使用method this.state.text
。
if (this.remainingCharacters() < 0) { var beforeOverflowText = this.state.text.substring(140 - 10, 140); var overflowText = this.state.text.substring(140); return ( <div className="alert alert-warning"> <strong>Oops! Too Long:</strong> ...{beforeOverflowText} <strong className="bg-danger">{overflowText}</strong> </div> ); }
- 如果这样做
.substring(a, b)
,它将从字符串中返回a + 1
第b
th个字符。 - 如果这样做
.substring(a)
,它将返回a + 1
字符串中的最后一个字符。 - 我们使用Bootstrap的
bg-danger
类以红色突出显示文本。
复制后再次粘贴此文本,然后查看正确的文本。我们快完成了!
如果尚未找到它,请继续寻找。别解决 与内心所有事情一样,当您找到它时就会知道。而且,就像任何伟大的关系一样,随着岁月的流逝,这种关系会越来越好。
如果“添加照片”按钮处于打开状态怎么办?
如果“添加照片”按钮为ON,则字符限制由23降低所以我们beforeOverflowText
并overflowText
需要考虑到这一点:
if (this.state.photoAdded) { var beforeOverflowText = this.state.text.substring(140 - 23 - 10, 140 - 23); var overflowText = this.state.text.substring(140 - 23); } else { var beforeOverflowText = this.state.text.substring(140 - 10, 140); var overflowText = this.state.text.substring(140); }
现在,尝试在输入任何超出限制的文本时切换“添加照片”按钮。它应该可以正常工作。这是JSBin:
而已!同样,您可以看到代码更改很简单:
步骤16:下一步是什么?(5分钟)
我的教程到此结束。希望你学到了:
- jQuery代码与React代码之间的区别,以及
- 如何在JSX中编写一些基本的React代码。
本文:细数jQuery和React用法差别, jQuery转React, jQuery和React的区别, jQuery和React实例对比