一、搭建环境
(安装过yarn之后,它会根据yarn来自动创建项目 cnpm install -g yarn)
- 安装脚手架:npm install -g create-react-app
- 创建项目 :Create-react-app 项目名称
- 运行:npm run start(或yarn start) 构建:npm run build(或yarn build)
快速搭建:npx create-react-app 项目名称 (1、安装脚手架2、创建项目3、删除create-react-app工具)(使用条件:node版本大于6,npm版本大于5.2)
二、React目录结构 React创建组件、 ReactJSX语法、 React绑定数据 React绑定对象 、React绑定属性( 绑定class 绑定style 图片)
manifest.json 文件简介:(不用管)
https://lavas.baidu.com/mip/doc/engage-retain-users/add-to-home-screen/introduction
index.js 入口文件
//React是React的核心库
//react-dom.js是提供与DOM相关的功能
import React from 'react';
import ReactDOM from 'react-dom';
//公共样式(拿到项目把css删掉即可)
import './index.css';
//组件
import App from './App';
//不用管,加快react运行速度的一个js文件
import * as serviceWorker from './serviceWorker';
//把APP这个节点渲染到root这个节点上
ReactDOM.render(<App />, document.getElementById('root'));
//加速的
serviceWorker.unregister();
root在index.html中,意思是在root这个节点下,引入App组件
一般进入src目录以后
新建components目录(放组件)
新建assets目录(放静态文件) 下面再新建images目录和css目录 (改下路径)
import React, { Component } from 'react';
import logo from './assets/images/logo.svg';
import './assets/css/App.css';
class App extends Component {
//jsx:html和js的混写模式
//render 模板
render() {
return (
<div className="App">
根组件
</div>
);
}
}
export default App;
创建子组件挂载在根组件上
在components里创建Home.js(组件文件名称首字母大写,组件类名也要首字母大写)
import React,{ Component } from "react";
export default class Home extends Component{
constructor(){
super();
this.state={
name:"张三"
}
}
render(){
return(
<div>
你好{this.state.name}
</div>
)
}
}
在APP.js中引入
import Home from "./components/Home";
<Home/>
构造函数constructor里面必须有super()
在构造函数constructor中定义该组件的参数:this.state={ key:value}
另一种写法:
import React from "react";
class News extends React.Component{
}
等于
import React,{Component} from "react";
class News extends Component{
}
Es6中的super可以用在类的继承中,super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
官方文档写法:
constructor(props){
super(props);//用于父子组件传值
}
只有一个理由需要传递props作为super()的参数,那就是你需要在构造函数内使用this.props
官方提供学习的例子中都是写成super(props),所以说写成super(props)是完全没问题的,也建议就直接这样写。
绑定属性注意:
class 要变成 className
for 要变成 htmlFor (label中这个for中值如果和Input的id一样,点击label就会在input中获取焦点)
style属性和以前的写法有些不一样
<div style={{'color':'blue'}}>{this.state.title}</div>
<div style={{'color':this.state.color}}>{this.state.title}</div>
其它的都一样
import React,{ Component } from "react";
import "../assets/css/home.css"
export default class Home extends Component{
constructor(props){
super(props);
this.state={
name:"张三",
title:"我是一个title",
color:'red',
style:{
color:'red'
}
}
}
render(){
return(
<div>
你好{this.state.name}
<div title={this.state.title}>title竟然是个指令</div>
<div className="red">红色</div>
<div className={this.state.color}>这样也可以红色</div>
<div style={{"color":'red'}}>行内样式</div>
<div style={this.state.style}>另一种行内样式写法</div>
<label htmlFor="name">姓名</label>
<input type="text" id="name"/>
</div>
)
}
}
引入图片:必须通过模块化的形式
最上面import logo from "../assets/images/image.png";
<img src={logo}/>
另一种ES5的方法 <img src={require(“../assets/images/image.png”)}/>
远程图片直接引入即可
渲染数组(循环):
什么都不加就可以直接显示出来,还可以循环dom元素,还可以把数组转成dom数组,用map
循环DOM数据要加key(不会影响什么,但会报错,在DOM数组定义的时候就要加key)
import React,{ Component } from "react";
import "../assets/css/home.css";
export default class Home extends Component{
constructor(props){
super(props);
this.state={
list:[<h2 key="1">我是一个H2标签</h2>,<h3 key="2">我是一个h3标签</h3>],
list2:['12111','2222','333232323'],
list3:[
{title:"123123123"},
{title:"456456456"},
]
}
}
render(){
var lResult=this.state.list2.map(function(value,key){
return <li key={key}>{value}</li>
})
return(
<div>
{this.state.list}
{this.state.list2}
{lResult}
{
this.state.list3.map((function(value,key){
return <li key={key}>{value.title}</li>
//return里面是多行就加()
}))
}
</div>
)
}
}
三、事件和方法
定义方法:和construct和render平级(不需要有逗号)
run(){
alert("123");
}
render(){
return(
<div>
<button onClick={this.run}></button>
</div>
)
}
如果想在方法中调用this.state定义的参数 如果直接this.state.参数是不行的
run(){
alert(this.state.data);//是不行的,因为当前的this不是指向我们要的this
}
方法1:方法中传参:
run(){
alert(this.state.data);
}
render(){
return(
<div>
<button onClick={this.run.bind(this.state)}></button>
</div>
)
}
方法2:在构造函数中传参:
constructor(props){
super(props);
this.run=this.run.bind(this.state);
}
run(){
console.log(this.state.data);
}
render(){
return(
<div>
<button onClick={this.run}></button>
</div>
)
}
方法3:箭头函数(好用)
run=()=>{
alert(this.state.data);
}
render(){
return(
<div>
<button onClick={this.run}></button>
</div>
)
}
想在方法中改变state的值:用上面三种方法改变this
然后this.setData({key:value})即可
在方法中传值改变this.setData
<button onClick={this.run("张三")}></button> //会报错,因为this没有指向想要的this
必须<button onClick={this.run(bind(this),"张三")}>
方法中传参第一个参数一定是this
1、方法中传值——传的是state中定义的参数
<button onClick={this.runG.bind(this,this.state.changeName)}>方法中</button>
runG=(msg)=>{
this.state.name=msg
alert(this.state.name)
}
或者直接不在html中加参数,因为方法中可以直接用this.state.参数
<button onClick={this.runH}>方法中</button>
runH=()=>{
this.state.name=this.state.changeName;
alert(this.state.name)
}
2、方法中传值——传的不是state中定义的参数
在方法中传递参数,不管是否用ES6箭头函数,都要this.方法.bind(this)
<button onClick={this.runE.bind(this,"hi")}>方法中</button>
<button onClick={this.runF.bind(this,"nihao")}>方法中</button>
runE=(msg)=>{
this.state.name=msg
alert(this.state.name)
}
runF(msg){
this.state.name=msg
alert(this.state.name)
}
事件对象、键盘事件、表单事件、ref获取dom节点、React实现类似vue双向数据绑定
事件对象:在出发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息
直接在方法中打印event即可
<button onClick={this.run}></button>
run=(event)=>{
console.log(event); //包含着所有与事件有关的信息
最大作用;获取dom节点
console.log(event)
console.log(event.target); //获取执行事件的dom节点 获取到点击的button按钮
改变DOM的属性
event.target.style.background='red';
(小程序里无法传值,所以要用自定义属性来传值)
<button onClick={this.run}></button>
run=(event)=>{
console.log(event); //包含着所有与事件有关的信息
react里面没有提供双向数据绑定
表单事件
点击Button以后获取input中的值
方法一:使用Input的onChange事件和button的onClick事件
1、监听表单的改变事件
2、在改变的事件里面获取表单输入的值
3、把表单输入的值赋值给username
4、点击按钮的时候获取state里面的username
constructor(props){
super(props);
this.state={
username:""
}
}
inputChange=(event)=>{
this.setState({
username:event.target.value
})
}
getInput=()=>{
alert(this.state.username)
}
render(){
return(
<input onChange={this.inputChange}/>
<button onClick={this.getInput}></button>
)
}
方法二:ref获取dom节点(替换了使用event.target.value获取input的值)
<input onChange={this.inputChange} ref="username"/>
inputChange=()=>{
let val=this.refs.username.value;
}
键盘事件onKeyUp和onKeyDown (e.keyCode)
inputKeyUp=(e)=>{
console.log(e.keyCode)
回车
if(e.keyCode==13){
alert(e.target.value)
}
}
<input onKeyUp={this.inputKeyUp}/>
双向数据绑定:model改变影响view,view改变影响model(vue中v-model,angular中ng-model,react中没有,react不是mvvm框架)
constructor(props){
super(props)
this.state={
username:"123"
}
}
<input value={{this.state.username}}/> //model层影响view,如果只是写value,不写onChange会报错,得写成defaultValue
<input defaultValue={{this.state.username}}/>
双向数据绑定:
inputChange=(e)=>{
this.setState({
username:e.target.value
})
}
mvvm: m改变影响v,this.state={name:"xxx"}; 给input框绑定这个name;
v改变影响m,给input框绑定onChange事件,只要input中的value改变,就将这个改变值this.setState绑定给m层
约束性和非约束性组件:
非约束性:<input type="text" defaultValue="a"/> 这个defaultValue其实就是原生DOM中的value属性(是写死的)
约束性: <input value={{this.state.username}} onChange={this.inputChange}/>这里的value属性不再是一个写死的值,
constructor(props){
super(props);
this.state={
name:"",
sex:1,
citys:["","",""],
city:"",
hobbys:[{checked:true,title:""},{checked:false,title:""},{checked:false,title:""}],
hobby:""
}
}
inputChange=(e)=>{
this.setState({
username:e.target.value
})
}
submit=(e)=>{
//先阻止form中的submit的默认刷新事件
e.preventDefault();
console.log(this.state.name,this.state.sex,this.state.city)
}
handelSex=(e)=>{
this.setState={
sex:e.target.value
}
}
handleCity=(e)=>{
this.setState={
city:e.target.value
}
}
<form onSubmit={this.submit}>
用户名:<input value={{this.state.username}} onChange={this.inputChange}/><br/><br/>
性别:男<input tyoe="radio" value="1" checked={this.state.sex==1} onChange={this.handelSex}/>
女<input tyoe="radio" value="2" checked={this.state.sex==2} onChange={this.handelSex}/>
居住城市:(下拉框 循环)
<select value={this.state.city} onChange={this.handleCity}>
{
this.state.citys.map(function(value,key){
return <option key={key}>{value}</option>
})
}
</select>
爱好:{
this.state.hobbys.map(function(value,key){
return (
<div>
{value.title}<input type="checkbox" checked={value.checked}/>
</div>
只要是return()中,就需要用div根元素把子元素包起来
)
})
}
<input value="提交" type="submit"/>
</form>