很幸運剛畢業到公司,領導就給我選擇了前端開發這個行當,而接觸的第一個框架就是Angular1,和大部分人同樣,一本大漠老師的《使用AngularJS開發下一代WEB應用》帶我入門,也照着寫了一些代碼,看書的時候也以爲大部分理解了,可是一到實際項目開發徹底找不到北了,我想這也是不少人的寫照。css
就本身的體會,前端開發水平能夠大概分爲三個層次,每個層次都是一個質的跨越,第一層
是入門級的(從Angular1來看就是ng-controller黨,這樣更形象一點),誠然這種模式已經比當年有了極大進步,可是一樣的,現在的前端複雜程度大增,這種進步只能算不拖後腿,第二層
是進階級的,組件化開發已經在心中打下烙印,這些人看到的不是頁面,而是一顆組件樹(說的好玄啊^ ^),對於通常的團隊,我認爲能達到這個水平就夠用了,每一個成員打好基本功,這個團隊是很不錯的了。第三層
,是我想象的,我認爲在他們眼中都是數據,沒有UI,數據就是UI,經過精妙的架構體系控制着數據的流動,同時掌控着數據在每個環節的變化。這裏的角度更可能是按一個偏產品的前端開發團隊來分析的,本身的視野有限歡迎你們討論。我認爲若是達到了第二層就算是脫離貧困奔小康甚至過上小資生活,對於生活(工做)遇到的困難都能比較輕鬆的應對。我認爲一個框架的熟練度達到相似第二層是很重要的,不然盲目的追新是很難達到質的提高,因此但願你們共勉不要盲從,至少要在團隊中技術能hold住,再去想技能樹更新,這纔會事半功倍的。html
回到原題,因爲項目演進的緣由下半年會由Angular1轉爲React,所以本身是從一個Angular1的開發視角來學習react,有人會問爲啥要用視角來學習,爲啥要對比,我本身也不知道這是否是一個好的方式,但我我的以爲用一個更熟悉的視角,新知識會記得更深入,也許文中的一些對比有誤,請你們指正,go~前端
Angular1做爲一門09年的顛覆性技術,爲前端開發帶來了一場革命,但因爲那時候沒有成熟的模塊化方案,沒有ES6標準的推進,致使這場革命不是那麼完全。確實Angular1不夠組件化,但Angular1帶給其餘框架的影響是巨大的,react,Vue的出現沒有達到Angular1當年的顛覆,react和Vue的核心技術也都有着Angular1的影子(或者說變了形態的影子),所以這篇教程就是帶你們在react上找尋Angular1熟悉的味道。react
固然是angular.directive和angular.component,這也是Angular1最能體現組件化特徵的地方。通常來講一個組件會對外暴露屬性
、事件
和方法
。jquery
在angular1中屬性有三種@
,<
,=
,@表示不可修改的屬性,最多見的id都會用@來表示,若是@對應的值會變化時,要加上{{}},架構
<my-comp text={{::someText}}></my-comp>複製代碼
修飾符<
的樣子就體現了單向數據流的特徵,它相似Vue中watch的形式,在$onChanges中能夠watch到屬性的變化,不用再本身一個一個添加$watch*之類的東東了,框架
=
這個樣子也很是形象,父做用域和隔離做用域的屬性都指向同一個地址空間,所以隔離做用域也能夠修改父做用域的屬性,這每每使得問題難以定位。dom
react的屬性很js,沒有angular那麼多修飾符或者繼承、隔離這些東西,react很開放,它告訴你屬性應該像@同樣是不可變的,可是它就是一個js對象,你能夠改變它,可是你要本身承擔所可能帶來的後果,那麼想一想@改怎麼寫,react的props就該怎麼用,想象一下咱們在寫一個指令叫MyProps,它目前只有一個{id:'@', width: '@'}ide
angular版模塊化
angular.directive('myProps', function(){
return {
restrict: 'E',
scope: {
id:'@',
width: '@'
},
controller:function($scope){
scope.width = scope.width || 200
},
template: `<button id='{{::id}}' width='{{::width}}'></button>`
}
})複製代碼
react版
class MyProps extends React.Component {
render() {
return (
<button id={this.props.id} style={{ width: this.props.width + 'px' }}> idButton </button>
)
}
}
MyProps.defaultProps = { width: 200 }複製代碼
react很js很class吧,其實思路是否是很類似,this.props就和scope同樣,只不過react經過jsx實現了表達式計算。
在angular裏事件通常用&
來修飾,若是你但願對響應參數作定製也可使用=
。
angular版
angular.directive('myProps', function(){
return {
restrict: 'E',
scope: {
id:'@',
width: '@',
click: '&'
},
controller:function($scope){
scope.width = scope.width || 200
},
template: `<button id='{{::id}}' width='{{::width}}' ng-click='click()'></button>`
}
})複製代碼
react版
class MyButton extends React.Component {
render() {
return (
<div> <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }} onClick={this.props.click}>clickMe</div> </div>
)
}
}
class MyEvent extends React.Component {
constructor(props) {
super(props)
}
clickHandler() {
console.log('My Button Clicked')
}
render() {
return (
<MyButton id="event" click={this.clickHandler.bind(this)} w="200" h="40" bgColor="green" /> ) } } ReactDOM.render( <MyEvent />, document.getElementById('root'))複製代碼
你也能夠對響應參數作定製,就像angular中把事件修飾&變爲=那樣,這裏就不上angular的了
react版本
class MyButton extends React.Component {
constructor(props) {
super(props)
}
clickHandler() {
this.props.click(this.props.bgColor)
}
render() {
return (
<div> <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }} onClick={this.clickHandler.bind(this)}>clickMe</div> </div>
)
}
}
class MyEvent extends React.Component {
constructor(props) {
super(props)
}
clickHandler(color) {
console.log('My Button color: ' + color)
}
render() {
return (
<MyButton id="event" click={this.clickHandler.bind(this)} w="200" h="40" bgColor="green" /> ) } } ReactDOM.render( <MyEvent />, document.getElementById('root'))複製代碼
其實方法並非angular所包含的一個概念,angular提倡數據狀態影響UI的理念,除了angular提供的一些ng-內置指令,咱們要寫一大堆雙向綁定屬性(伴隨着一大堆$watch),性能堪憂,更重要的是你會發現定位問題很難(髒數據校驗)。所以在咱們項目除了disable、display之類會使用<
,界面變動都採用方法,將指令的UI變動方法綁定到$scope.$parent上,這樣父指令就能夠經過這些方法來操做子指令的UI變動了。
angular版
angular.module('myApp',[]);
myApp.controller('listCtrl',function($scope){ var display = false
$scope.showOrHide=function(){
$scope.btn.setDisplay(display?'block':'none')
display =!display
};
});
myApp.directive('kid',function(){
return {
'restrict':'E',
scope:{id: '@'},
template:'<div><button>click</button></div>',
link: function(scope, elem) {
scope.$parent[scope.id] = {
setDisplay: function(display){
elem.css('display', display)
}
}
}
}
});複製代碼
按照這個思路咱們在react上也試試。
class MyButton extends React.Component {
constructor(props) {
super(props)
}
setDisplay(display) {
this.refs.myButton_ref.style.display = display
}
render() {
return (
<div ref="myButton_ref"> <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }}>clickMe</div> </div>
)
}
}
class MyEvent extends React.Component {
constructor(props) {
super(props)
this.display = false
}
showOrHide() {
this.child.setDisplay(this.display ? 'block' : 'none')
this.display = !this.display
}
render() {
return (
<div> <MyButton id="event" w="200" h="40" bgColor="green" ref={(instance) => { this.child = instance }} /> <button onClick={this.showOrHide.bind(this)}>showOrHide</button> </div> ) } }複製代碼
代碼中ref="myButton_ref"
很是彆扭,由於直接對dom的操做讓咱們感受回到了jquery時代,所以這裏咱們應該使用一直未提到的state
,那state像angular的什麼呢,和指令中的controller很像,你能夠在controller裏對$scope裏增長新的屬性(這裏也包含了父指令傳進來的屬性),所以angular裏的$scope包含了react中的props和state,react把它分開會讓使用者更加清楚,讓使用者知道props是不能變的,state纔是可變的。所以咱們把代碼中的MyButton
稍做修改。
class MyButton extends React.Component {
constructor(props) {
super(props)
this.state = { display: 'block' } // 初始值
}
setDisplay(display) {
this.setState({ display })
}
render() {
return (
<div style={{ display: this.state.display }}> <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }}>clickMe</div> </div>
)
}
}複製代碼
這篇教程主要從本身這個Angular1使用者的的視角來看react,我以爲對於Angular開發人員來講是一個不錯的學習react的思路,本人也是剛剛接觸react,文中若有錯誤也請及時指正。下一篇將對Angular1指令的生命週期和react組件生命週期作以對比,謝謝你們。