导读:
在未接触react,vue等组件化前端框架时,我所认知的前端均为许多不同的页面组成,不同的页面处理不同的业务逻辑,在一定角度上可以理解为页面的数量决定项目的大小。对前端的理解程度局限于页面不同元素的拼凑,样式的修改,js脚本实现参数传递,页面跳转,动态样式等等。
初识react框架后,我对它的第一认知是:通过组件与组件之间的关联,组合形成一整套完善的业务逻辑。
学习流程:
1.环境搭建:
- 安装node.js: 官网下载.msi安装包,默认安装即可。
- 安装vscode:官网下载.exe执行文件,同样默认安装。
- 新建html页面,页面引入相关js文件
1 <!--react核心库--> 2 <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> 3 <!--提供与Dom相关的功能--> 4 <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> 5 <!-- 升级es5->es6 支持jsx语法--> 6 <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
2.JSX:
jsx简单来说就是javascript上面的一种语法扩展,js-x见名知其意。
const component = <MyComponent />; let test1 = <div><h1>hello world!</h1></div>;
// =>相当于lambda表达式中的 参数值->返回值 const ListItems = message.map( (item) => <li>{item}</li> );
3.组件:
两种实现方式:
(1)定义 function函数,需注意函数需要接收props属性的对象,同时需要返回react元素。
function testFunc(props){ return <p>hello {props.name}</p> }
(2)定义一个class继承React.Component,需注意命名的组件以大写字母开头。
class MyComponent extends React.Component { render() { return <h1>hello {this.props.name} </h1>; } }
4.复合组件:
简单来说就是在一个父组件之间存在其他子组件,通过自顶向下的数据传输方式实现组件之间的耦合。
//实现组件之间的参数传递 ->接收组件 子组件 class RecieveComponent extends React.Component { constructor(props) { super(props); this.state = { age: props.age, name: props.name } }; render() { return ( <div> <h5>姓名:{this.state.name}</h5> <h5>年龄:{this.state.age}</h5> </div> ) } } //提供数据组件 ->父组件 class ProvideComponent extends React.Component { constructor() { super(); } render() { return ( <RecieveComponent age={22} name={"wsw"} /> ) } }
5.props与state:
props:属性,不可变,仅用于数据传输
- setProps(object newProps(,function callback)):
- replaceProps(object newProps(,function callback)):
state:状态 ,可变,可用于触发ui更新
- setState(object newState(,function callback))
- replaceState(object newState(,function callback))
class LearnComponentApi extends React.Component { constructor(props) { super(props); this.state = { clickCount: 0 } this.clickCountFunc = this.clickCountFunc.bind(this); } //设置每次点击改变clickCount属性的状态 clickCountFunc() { //setState每次都会造成一次组件渲染,并不会立即执行,而是会生成一个state,由react进行批量state,DOM渲染 this.setState(function (state) { return { clickCount: state.clickCount + 1 }; }); } render() { return ( <button onClick={this.clickCountFunc}>当前点击次数为:{this.state.clickCount}</button> ); } }
6.条件渲染:
1 //条件渲染,根据传入的属性改变页面的显示 2 function Login(props) { 3 4 function LoginIn(props) { 5 return <h1>欢迎登陆!</h1>; 6 } 7 8 function UnLogin(props) { 9 return <h1>登录失败!</h1>; 10 } 11 12 const isLogin = props.isLogin; 13 14 if (isLogin) { 15 return <LoginIn />; 16 } 17 return <UnLogin />; 18 }
7.事件:
ps:需要注意的是组件内自己定义的改变state的方法需要在初始化时进行绑定,否则使用该方法时会出现undefined未定义的问题
1 //事件绑定 用户点击切换状态 2 class MyEvent extends React.Component { 3 constructor(props) { 4 super(props); 5 this.state = { 6 isOn: true 7 }; 8 this.handleClick = this.handleClick.bind(this); 9 } 10 11 handleClick() { 12 this.setState(preState => ({ 13 isOn: !preState.isOn 14 })); 15 } 16 17 render() { 18 return ( 19 <button onClick={this.handleClick}> 20 {this.state.isOn ? <h2>开</h2> : <h2>关</h2>} 21 </button> 22 ) 23 } 24 }
handleClick() 等同于function handleClick(){}
{this.handleClick}等同于handleClick()
8.运算符:
//与运算符(true && expression ->expression /false && expression ->false) 三目运算符 condition ? true : false function UseConditionComponent(props) { const unReadMessage = props.unReadMessage; //与运算符 return ( <div> { unReadMessage.length > 0 && <h2>你有{unReadMessage.length}条消息未读!</h2> } </div> ); //三目运算符 return ( unReadMessage.length > 0 ? (<h2>你有{unReadMessage.length}条信息未读!</h2>) : (<h2>全部消息已读!</h2>) ); }
8.列表:
key:在react中用于获取每一个元素对象的状态,每一个元素对象都需要有自己的key且唯一
map()方法中的所返回的元素需要指定key
//列表 map 元素遍历 const message = ['react', 'vue', 'angular']; // =>相当于lambda表达式中的 参数值->返回值 const ListItems = message.map( (item) => <li>{item}</li> ); //通过组件进行列表元素的封装遍历,需要在<li>标签中声明key,否则报key找不到错误 const hobby = ["唱", "跳", "rap"]; function ListComponent(props) { const elements = props.elements; //在map()方法中的元素需要指定key const listElements = elements.map( (ele) => <li key={ele.toString()}>{ele}</li> ) return <ul>{listElements}</ul>; } //列表li元素 function ListItem(props) { return <li>{props.value}</li> } //遍历ul元素 function ElementsForeach(props) { const members = props.members; return ( <ul> { members.map( (els) => <ListItem key={els.toString} value={els} /> ) } </ul> ); }
key在兄弟元素之间只能唯一,指定为确定的一个属性
//元素的key在它的兄弟元素之间唯一 function ForeachItems(props) { const pid = ( <ul> { props.persons.map( (s) => <li key={s.pid}>id:{s.pid}</li> ) } </ul> ); const pbody = props.persons.map( (e) => <div key={e.pid}> <h5>姓名:{e.pname}</h5> <h5>年龄:{e.page}</h5> </div> ); return ( <div> <h4>key在兄弟元素中唯一</h4> {pid} {pbody} </div> ); } const persons = [ { pid: 1, pname: '张三', page: 18 }, { pid: 2, pname: '李四', page: 20 } ];
9.表单(受控组件):input/textarea/select
//受控组件 表单操作 input,textarea,select class FormComponent extends React.Component { constructor(props) { super(props); this.state = { text: "" } this.submitValue = this.submitValue.bind(this); this.changeValue = this.changeValue.bind(this); } submitValue(event) { alert("提交的内容:" + this.state.text); event.preventDefault(); } changeValue(e) { this.setState({ //设置text的值为target的value ,且输入值只要为字母全转为大写 text: e.target.value.toUpperCase() }); } render() { return ( <form onSubmit={this.submitValue}> <input type="text" value={this.state.text} onChange={this.changeValue} /> <Textarea value={this.state.text} onChange={this.changeValue} /> <select value={this.state.text} onChange={this.changeValue}> <option value="唱">唱</option> <option value="跳">跳</option> <option value="rap">rap</option> </select> <input type="submit" value="提交" /> </form> ) } }
10.ReactDOM.render():
将加载的内容转为html元素,并插入到指定的DOM节点
<div id="test"></div>
ReactDOM.render( <div align='center'> <MyEvent /> <MyComponent /> <MyChangeState /> <Login isLogin={true} /> <UseConditionComponent unReadMessage={message} /> <h5>通过单个组件遍历数组元素:</h5> <ListComponent elements={message} /> <h5>通过复合组件遍历数组元素:</h5> <ElementsForeach members={hobby} /> <ForeachItems persons={persons} /> <LearnComponentApi /> <FormComponent /> <ProvideComponent /> {test2} </div> , document.getElementById('test') );
11.React router(路由):
可以理解为一个url资源定位容器,通过路由配置可以实现如传统前端那样不同页面之间跳转的功能。
let Home = () => ( <Bundle load={loadHome}> {Home => <Home/>} </Bundle> ); let Detail = () => ( <Bundle load={loadDetail}> {Detail => <Detail/>} </Bundle> ); let Add = () => ( <Bundle load={loadAdd}> {Add => <Add/>} </Bundle> );
<Router> <Switch> <Route path="/" exact component={Home}/> <Route path="/detail" component={Detail}/> <Route path="/add" component={Add}/> <Redirect to="/"/> </Switch> </Router>
文章待完善。。。