旧版

hello world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>

<!-- 引入react核心库,必须第一个引入 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel"> /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM = <h1>Hello,React</h1> /* 此处一定不要写引号,因为不是字符串 */
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>

vdom

vdom介绍

关于虚拟DOM:

  1. 本质是Object类型的对象
  2. 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
  3. 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。

vdom的创建方式

使用jsx:语法糖

1
2
3
4
5
6
7
8
<script type="text/babel">
const VDOM = (
<h1 id="title">
<span>Hello,React</span>
</h1>
)
ReactDOM.render(VDOM,document.getElementById('test'))
</script>

使用js:不便于处理嵌套标签

bable会把jsx翻译成js,即转化为下方的代码↓

1
2
3
4
<script type="text/javascript" > 
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'))
ReactDOM.render(VDOM,document.getElementById('test'))
</script>

jsx语法

jsx语法规则:

  1. 定义虚拟DOM时,不要写引号
  2. 标签中混入JS表达式时要用{}
  3. 样式的类名指定不要用class,要用className
  4. 内联样式,要用style={{key:value}}的形式去写
  5. 只有一个根标签
  6. 标签必须闭合
  7. 标签首字母
    (1) 若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
    (2) 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const myId = 'aTgUiGu'
const myData = 'HeLlo,rEaCt'

//1.创建虚拟DOM
const VDOM = (
<div>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color:'white',fontSize:'29px'}}>{myData.toLowerCase()}</span>
</h2>
<h2 className="title" id={myId.toUpperCase()}>
<span style={{color:'white',fontSize:'29px'}}>{myData.toLowerCase()}</span>
</h2>
<input type="text"/>
</div>
)

// 注意{}内必须是表达式,语句是不可以的
const VDOM = (
<div>
<h1>前端js框架列表</h1>
<ul>
{
data.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))

组件

函数式组件

执行了ReactDOM.render(<MyComponent/>...之后,发生了什么?

  1. React解析组件标签,找到了MyComponent组件。
  2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
1
2
3
4
5
6
7
//1.创建函数式组件
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

类式组件

执行了ReactDOM.render(<MyComponent/>...之后,发生了什么?

  1. React解析组件标签,找到了MyComponent组件。
  2. 发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法。
  3. 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
1
2
3
4
5
6
7
8
9
10
11
12
//1.创建类式组件
class MyComponent extends React.Component {
render(){
//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
//render中的this是谁?—— MyComponent的实例对象 <=> 也叫MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

组件实例三大属性

state

理解:

  1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

  2. 组件被称为”状态机”, 通过更新组件的state来更新对应的页面显示(重新渲染组件)

this指向问题:

首先需要明确的内容:

  • 构造器内的this指向实例对象
  • render内的this也指向实例对象
  • class内开启局部严格模式,类其余方法内的this为undefined

现在关注render函数:

1
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>

如果没有上方的bind语句,在点击时以普通函数的方式触发changeWeather

故changeWeather内的this指向window,又因为局部的严格模式,所以this指向undefined,访问它的state就会报错

所以要使用bind,将weather实例对象绑定给changeWeather方法,使得this指向正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Weather extends React.Component{
//构造器调用1次
constructor(props){
super(props)
//初始化状态
this.state = {isHot:false,wind:'微风'}
//解决changeWeather中this指向问题
//将changeWeather方法绑定到实例对象上,以后在调用该方法时,其中的this指向实例对象
this.changeWeather = this.changeWeather.bind(this)
}

//render调用1+n次(1表示初始化 n是状态更新的次数)
render(){
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}

//changeWeather调用几次? ———— 点几次调几次
changeWeather(){
//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用

console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);

//注意:状态(state)不可直接更改
//this.state.isHot = !isHot //这是错误的写法
}
}

总结:

  1. 组件中render方法中的this为组件实例对象

  2. 组件自定义的方法中this为undefined,如何解决?

    1. 强制绑定this: 通过函数对象的bind()
    2. 箭头函数
  3. 状态数据,不能直接修改或更新