<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hello_react</title>
<!-- 引入react,为了使用 React对象 -->
<script src="js/react.development.js"></script>
<!-- 引入 react-dom, 为了使用 ReactDOM 对象 -->
<script src="js/react-dom.development.js"></script>
<!-- 引入 babel, 为了 解析 JSX -->
<script src="js/babel.min.js"></script>
</head>
<body>
<div id="test"></div>
<!-- <button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button onclick="demo()">按钮3</button> -->
<!-- 1. 函数式组件 -->
<!-- <script type="text/babel">
// 创建组件
// 函数作为组件:函数名必须大写
function Demo() {
return <h2>hello,react</h2>
}
// 把组件渲染到页面
// 使用函数组件时,需要使用标签,且标签必须闭合
ReactDOM.render(<Demo/>, document.getElementById('test'))
</script> -->
<!-- 2. 复习类的相关知识 -->
<!-- <script type="text/javascript">
class Person {
// 构造器方法---中的this就是通过new Person构造出的实例对象
constructor(name, age) {
this.name = name
this.age = age
}
// 一般方法
// speak方法放在哪里?---放在了类的原型对象上。供实例调用。
// 通过Person的实例对象调用speak方法时,speak方法中的this就是Person的实例对象。
speak() {
console.log(this)
console.log(`我叫${this.name},年龄是:${this.age}`)
}
}
const p1 = new Person("tom", 18)
// console.log(p1) // Person {} p1是一个对象 {},前面的 Person代表这个对象是由Person类构造的。
p1.speak()
</script> -->
<!-- 3. 类式组件 -->
<!-- <script type="text/babel">
// 创建组件
class Demo extends React.Component {
// render放在了哪里?--放在类的原型对象上。供实例调用。--实例在哪里
// render中的this是谁?---谁调用了render? Demo类的实例调用了 render---render中的this就是实例对象。又叫组件实例对象。
// 注意,render中的this并不是指向demo类,而是指向demo类的实例。该实例是由react在使用<Demo/>标签时帮我们自动new出来的。
render() {
return <h2>hello,react!!!</h2>
}
}
// 把组件渲染到页面
ReactDOM.render(<Demo/>, document.getElementById('test'))
// ReactDOM.render(<Demo/>, document.getElementById('test')) 这句,React做了什么?
// React解析组件标签,找到了 <Demo/>组件。
// 发现<Demo/>组件是通过类定义的。就会 new 出来该类的一个实例,然后通过该实例调用类中的render方法。
// 将render返回的虚拟DOM转为真实Dom,呈现到页面上。
</script> -->
<!-- 4. 对state的理解 -->
<!-- 复杂组件:有状态的组件叫复杂组件
简单组件:无状态组件
状态: 人 状态 影响 行为
组件 状态 驱动 数据
-->
<!-- 5.组件实例的三大属性1:state -->
<!-- <script type="text/babel">
// 创建类式组件
class Weather extends React.Component {
// 构造器能接收到什么,取决于你new Weather时传的是什么。
// 但是new这个动作是由react帮你实现的---查询官网得知:可以接收到props
constructor(props) {
super(props) // 由于Weather继承自React.Component类,且在Weather类中写了构造器。则在构造器中super优先必调
// 写构造器的目的是什么?---在类的实例对象上添加一些属性
this.state = {
isHot: true
}
}
// render中的this---就是组件实例对象。如果你想在类的实例对象上添加一些属性,就需要通过constructor构造器
render() {
console.log(this)
return <h2>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
}
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script> -->
<!-- 6.原生事件的绑定 -->
<!-- <script type="text/javascript">
// 方式1
let btn1 = document.getElementById('btn1')
btn1.addEventListener('click', function() {
console.log('按钮1被点击了')
})
// 方式2
let btn2 = document.getElementById('btn2')
btn2.onclick = () => {
console.log('按钮2被点击了')
}
// 方式3
function demo() {
console.log('按钮3被点击了')
}
</script> -->
<!-- 7.react绑定事件、自定义方法中的this -->
<!-- <script type="text/babel">
// let that
// 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot: true
}
// that = this // 在构造器中缓存组件实例对象,再送出去。
}
// 构造器中的this是---组件实例对象
render() {
return <h2 onClick={demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
}
// render中的this是---组件实例对象。因为render是我们在使用组件标签时,由react自动帮我们new 的那个实例调用的。 【通过实例调用render时,render中的this就是实例】
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
// 自定义函数
function demo() {
// console.log('标题被点击了')
// 去修改组件实例对象上的isHot属性
// 先去拿到组件实例对象
console.log(this) // undefined
console.log(that) // 这样可以访问到外部被缓存的组件实例对象
}
// 为什么demo中的this是undefined?
// 分析: demo是自定义函数,那么demo中的this应该是 window。但是由于babel默认开启了严格模式,所以 demo 中的this指向了 undefined
// 怎么样才能让demo中的this指向组件实例对象?
// 通过在构造器中缓存组件实例对象this--可以实现在类的方法中访问组件实例
// 但这样做不规范。我们希望把所有类相关的方法都放在类的本身内部。
</script> -->
<!-- 8.把自定义方法放到类内部、类中方法的this-->
<!-- <script type="text/babel">
// 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot: true
}
}
// 构造器中的this是---组件实例对象
render() {
// 这里的this.demo有没有被调用?---没有。this.demo只是作为回调被放在堆中。当点击事件触发时作为onClick的回调被调用。此时的调用是直接调用。不是通过实例对象调用。
// 所以demo中的this并不会指向组件实例。而会指向window或undefined。取决于是否开启了严格模式
return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
}
// render中的this--组件实例对象
// 一般方法:注意类不是函数体,在类中定义方法,不需要加 function关键字
demo() {
console.log(this) // undefined
}
// 为什么构造器、render中的this都指向组件实例对象。而在demo中的this却是undefined?
// 类中的方法默认开启了局部严格模式。当demo作为onClick的回调,从堆中被直接调用时,demo中的this就指向了undefined.
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script> -->
<!--9.非严格模式this的指向 -->
<!-- <script type="text/javascript">
function demo() {
console.log(this) // Window
}
demo()
</script> -->
<!--10.严格模式this的指向 -->
<!-- <script type="text/javascript">
function demo() {
'use strict'
console.log(this) // undefined
}
demo()
</script> -->
<!-- 11.解决类中this指向 -->
<!-- <script type="text/babel">
// 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot: true
}
// 赋值语句:右侧--this是组件实例对象。this.demo放在哪里?---类的原型对象上
// bind语句返回一个新函数,且这个新函数中的this被指向了参数中的this。
// 参数中的this是--在构造器中,是组件实例对象。所以右边得到一个新函数,且新函数中this指向组件实例。
// 把新函数赋值给了组件实例上的demo属性。
this.demo = this.demo.bind(this)
}
render() {
// 这里的this.demo调用的是原型上的还是组件实例自身上的?
// ---自身。因为按照原型链查找规则,自身有就不会再查找原型链
return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
}
// demo放在哪里?--类的原型对象上
demo() {
console.log(this)
}
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script> -->
<!-- 12.setState的使用 -->
<!-- <script type="text/babel">
// 创建类式组件
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot: true,
wind: '微风'
}
this.demo = this.demo.bind(this)
}
render() {
const {isHot, wind} = this.state
return <h2 onClick={this.demo}>今天天气很{isHot ? '炎热':'凉爽'}, {wind}</h2>
}
demo() {
const {isHot} = this.state
this.state.isHot = !isHot
// 严重注意:在react中,更新state的值必须使用setState()API,且更新是一种合并,不是替换
this.setState({
isHot: !isHot
})
// 严重注意:在react中,不能直接修改state。下面的代码就是直接修改state
// console.log(this.state.isHot)
}
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script> -->
<!-- 13.类的小技巧 -->
<!-- <script type="text/javascript">
class Car {
constructor(name, price) {
this.name = name
this.price = price
}
// 在类中可以直接写赋值语句。
// 下面代码的含义是:给类的所有实例都添加一个属性,属性名为a,属性值为1
a = 1
}
const c1 = new Car('奔驰C63', 199)
const c2 = new Car('宝马', 299)
console.log(c1)
console.log(c2)
// 通过这个技巧,我们可以简写类中的state
</script> -->
<!-- 14.简写state、简写类组件 -->
<script type="text/babel">
// 创建类式组件
class Weather extends React.Component {
// 为什么要写构造器?---为了给组件实例的state属性初始化、 为了解决类中方法this指向
// 不通过构造器也可以实现这两个目的。
// constructor(props) {
// super(props)
// this.state = {
// isHot: true,
// wind: '微风'
// }
// this.demo = this.demo.bind(this)
// }
// 在类中直接写赋值语句--实现:给所有的组件实例自身都添加state属性
state = {
isHot: true,
wind: '微风'
}
render() {
const {isHot, wind} = this.state
// 这里的demo调用的是组件实例自身的demo,原型链上不再有demo
return <h2 onClick={this.demo}>今天天气很{isHot ? '炎热':'凉爽'}, {wind}</h2>
}
// 在类中写赋值语句:给组件实例自身添加demo属性。值是一个箭头函数。
// demo函数放在了哪里?----组件实例对象自身。不再是放在类的原型对象上。
// 程序员在类中写的demo方法、demo1、demo2都是作为事件的回调函数调用的。是一种直接调用。就会存在this指向为undefined的情况。
// 因为在使用组件标签时,实例是由react帮我们自动new的,且只调用了实例.render。
// react并不会帮你再调用写的其他方法如demo、demo1、demo2。这就一定会导致类中这些方法this一定无法指向组件实例。
// 所以,程序员以后在类中写方法,直接写成赋值语句 + 箭头函数形式。
// 可以在实例自身添加demo属性,值是一个箭头函数,箭头函数中this指向类中this。类中this恰好就是组件实例。这样的话,类中方法的this就不会丢失,而是一定会指向组件实例。
demo = () => {
// console.log(this) // 确实指向组件实例
const {isHot} = this.state
this.state.isHot = !isHot
this.setState({
isHot: !isHot
})
}
// 箭头函数中,没有this。如果箭头函数中使用了this,则this指向箭头函数外部的this。
// demo1放在了哪里--类的原型对象上
demo1() {}
// demo2放在了哪里--类的原型对象上
demo2() {}
}
// 将组件渲染到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>