很幸运刚毕业到公司,领导就给我选择了前端开发这个行当,而接触的第一个框架就是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组件生命周期作以对比,谢谢你们。