任務:利用React編寫一個Tweet Box。
要求:
- 沒有文字輸入,tweet按鈕不可點擊;未添加圖片時圖片按鈕顯示Add Photo,添加圖片后顯示Photo Added。
- 另外,只要添加了圖片,tweet按鈕就可以點擊,即使未輸入文字。
- 一張圖片相當于23個文字的長度,這兒僅用toggle來模擬添加圖片就好;
- 超出文字部分高亮顯示(在這兒,我們把多余字符拿到textarea外面高亮了,簡單一些);
先來用jquery實現(xiàn)一下
<!DOCTYPE html>
<html>
<head>
<title>
</title>
<script src="jquery.js"></script>
<link 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按鈕的點擊與字數(shù)超出后的警示都是和剩余字數(shù)相關的,而剩余字數(shù)又和textarea和add photo按鈕有關,因此這兩個事件嚴重耦合在一起,每次為實現(xiàn)需求做條件判斷時,幾乎每次都要把另外一個事件對剩余字數(shù)的影響考慮進來。這個功能還算是比較簡單的,如果耦合的事件再多一些,那么我們在每一個事件發(fā)生時,都要做很多判斷,然后再去操作對應的DOM,這真的是個體力活兒。
而 react,在這方面就做的比較讓人省心了,它僅僅需要我們?nèi)リP注當前的狀態(tài)。它就像是一個有限狀態(tài)機,我們只需對于不同狀態(tài)去設置相應的表現(xiàn)就好,而不用像jquery那樣時時刻刻去記著其它事件帶來的影響。
下面是react的實現(xiàn):
<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<link 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沒有看出優(yōu)勢,但是要記得,react可是為不斷擴大的項目而生的。對于邏輯復雜的組件來說使用react是相當方便的,因為在這個過程中我們只用去考慮組件當前的狀態(tài)和可能的改變,而不是像jquery去不斷的操作DOM,不斷去判斷各種情況,然后在幾個方法之間來回穿梭。react的邏輯很符合我們對現(xiàn)實世界的認知,狀態(tài)改變之后,會自動的去render,從而改變展示。
- 簡單 :只要表達出這個程序在該段時間應該長什么樣,當?shù)讓訑?shù)據(jù)變化時,React會自動處理所有界面的更新。
- 聲明式:數(shù)據(jù)變化后,會自動刷新,但只更新變化的部分。
特性:
虛擬DOM機制,每當數(shù)據(jù)變化,React會重新構建整個DOM樹,將當前DOM樹和上一次的作比較,這一過程都通過虛擬DOM進行,最后將需要變化的部分進行實際渲染更新。
組件化【React對你的唯一要求】:
和MVC思想的框架不同,每個組件獨立封裝,功能獨立,我們只需關心自己部分的邏輯。與單一功能原則相同:獨立的組件應該只做一件事情。
預渲染特性——Pre-rendering
虛擬DOM不依賴瀏覽器,可以在任何javascript環(huán)境執(zhí)行。所以在后端運行代碼也能渲染整個DOM,生成HTML字符串,返回給瀏覽器。這樣,頁面SEO和首次打開速度都可以解決。
rails項目中只要使用react-rails gem 就可以在rails后端渲染前端React組件。