任务:利用React编写一个Tweet Box。
要求:
- 没有文字输入,tweet按钮不可点击;未添加图片时图片按钮显示Add Photo,添加图片后显示Photo Added。
- 另外,只要添加了图片,tweet按钮就可以点击,即使未输入文字。
- 一张图片相当于23个文字的长度,这儿仅用toggle来模拟添加图片就好;
- 超出文字部分高亮显示(在这儿,我们把多余字符拿到textarea外面高亮了,简单一些);
先来用jquery实现一下
<!DOCTYPE html>
<html>
<head>
<title>
</title>
<script src="jquery.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<meta charset="utf-8">
</head>
<body>
<div class="container">
<div class="well clearfix">
<div class="alert alert-warning hidden ">
<strong>Oops! Too Long:</strong> ...<span class="beforeOverflow"></span><strong class="bg-danger" ></strong>
</div>
<textarea class="form-control"></textarea>
<button class="btn btn-default pull-right tweet">Tweet</button>
<button class="btn btn-default pull-right photo">Add Photo</button>
<span class="pull-right">140</span>
</div>
</div>
<script type="text/javascript">
$(function(){
var tweet=$('.tweet'),
textVal=$('textarea'),
photo=$('.photo'),
len=0,
characters=$('span');
tweet.prop("disabled",true);
textVal.on("input",function(e){
len=$(this).val().length;
if(len){
tweet.prop('disabled',false);
}else{
tweet.prop('disabled',true);
}
if(photo.hasClass('isOn')){
characters.text(140-23-len);
}else{
characters.text(140-len);
}
remainingCharaters();
});
photo.on("click",function(e){
if(photo.hasClass('isOn')){
photo.removeClass('isOn').text('Add Photo');
characters.text(140-len);
if(len==0){
tweet.prop('disabled',true);
}
}else{
photo.addClass('isOn').text('Photo Added');
characters.text(140-23-len);
if(len==0){
tweet.prop('disabled',false);
}
}
remainingCharaters();
});
function remainingCharaters(){
var num=parseInt(characters.text());
console.log(num);
if(num>=0){return;}
if(photo.hasClass('isOn')){
$('.beforeOverflow').text(textVal.val().substring(130-23,140-23));
$('.bg-danger').text(textVal.val().substring(140-23));
}else{
$('.beforeOverflow').text(textVal.val().substring(130,140));
$('.bg-danger').text(textVal.val().substring(140));
}
$('.alert.alert-warning').removeClass('hidden');
}
})
</script>
</body>
</html>
从以上代码中大家可以看出,tweet按钮的点击与字数超出后的警示都是和剩余字数相关的,而剩余字数又和textarea和add photo按钮有关,因此这两个事件严重耦合在一起,每次为实现需求做条件判断时,几乎每次都要把另外一个事件对剩余字数的影响考虑进来。这个功能还算是比较简单的,如果耦合的事件再多一些,那么我们在每一个事件发生时,都要做很多判断,然后再去操作对应的DOM,这真的是个体力活儿。
而 react,在这方面就做的比较让人省心了,它仅仅需要我们去关注当前的状态。它就像是一个有限状态机,我们只需对于不同状态去设置相应的表现就好,而不用像jquery那样时时刻刻去记着其它事件带来的影响。
下面是react的实现:
<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="./react-demos-master/build/react.js"></script>
<script src="./react-demos-master/build/react-dom.js"></script>
<script src="./react-demos-master/build/browser.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var TweetBox = React.createClass({
getInitialState:function(){
return{
text:"",
photoAdded:false
}
},
handleChange:function(e){
this.setState({
text:e.target.value
})
},
remainingCharacters:function(e){
if(this.state.photoAdded){
return 140-23-this.state.text.length;
}else{
return 140-this.state.text.length;
}
},
togglePhoto:function(e){
this.setState({
photoAdded:!this.state.photoAdded
})
},
overflowText:function(e){
if(this.remainingCharacters()>=0){return;}
var beforeOverflowText,afterOverflowText;
if(this.state.photoAdded){
beforeOverflowText=this.state.text.substring(140-23-10,140-23),
afterOverflowText=this.state.text.substring(140-23);
}else{
beforeOverflowText=this.state.text.substring(140-10,140),
afterOverflowText=this.state.text.substring(140);
}
return (
<div className="alert alert-warning">
<strong>Oops! Too Long:</strong> ...{beforeOverflowText}<strong className="bg-danger" >{afterOverflowText}</strong>
</div>
);
},
render: function() {
return (
< div className = "well clearfix" >
{this.overflowText()}
< textarea className = "form-control" onChange={this.handleChange}> < /textarea>
<br/ >
< button className = "btn btn-primary pull-right" disabled={this.remainingCharacters()===140} > Tweet < /button>
<button className="pull-right btn btn-primary" onClick={this.togglePhoto}> {this.state.photoAdded?"Photo Added":"Add Photo"}</button>
<span className="pull-right">{this.remainingCharacters()}</span>
</div > );
}
});
ReactDOM.render( < TweetBox / > , document.getElementById("example"));
</script>
</body>
</html>
本案例摘抄自:http://www.th7.cn/web/js/201508/118318.shtml ,这里对两种做了详细的分析对比,值得一看。
为什么使用React?
虽然在这个例子中,是用react在代码量上对比jquery没有看出优势,但是要记得,react可是为不断扩大的项目而生的。对于逻辑复杂的组件来说使用react是相当方便的,因为在这个过程中我们只用去考虑组件当前的状态和可能的改变,而不是像jquery去不断的操作DOM,不断去判断各种情况,然后在几个方法之间来回穿梭。react的逻辑很符合我们对现实世界的认知,状态改变之后,会自动的去render,从而改变展示。
- 简单 :只要表达出这个程序在该段时间应该长什么样,当底层数据变化时,React会自动处理所有界面的更新。
- 声明式:数据变化后,会自动刷新,但只更新变化的部分。
特性:
虚拟DOM机制,每当数据变化,React会重新构建整个DOM树,将当前DOM树和上一次的作比较,这一过程都通过虚拟DOM进行,最后将需要变化的部分进行实际渲染更新。
组件化【React对你的唯一要求】:
和MVC思想的框架不同,每个组件独立封装,功能独立,我们只需关心自己部分的逻辑。与单一功能原则相同:独立的组件应该只做一件事情。
预渲染特性——Pre-rendering
虚拟DOM不依赖浏览器,可以在任何javascript环境执行。所以在后端运行代码也能渲染整个DOM,生成HTML字符串,返回给浏览器。这样,页面SEO和首次打开速度都可以解决。
rails项目中只要使用react-rails gem 就可以在rails后端渲染前端React组件。
网友评论