一、 在属性中使用变量
基本使用
this.state = {
imgUrl: 'http://p1.music.126.net/uFtGUm56jgbGlBQOk_PGcw==/109951164832828416.jpg'
}
render() {
{/*
JSX主要写在render函数中,随后将界面结构交由React进行渲染
*/}
const { imgUrl } = this.state
return (
<div>
{/* 可以直接使用大括号语法在属性中使用变量 */}
<img src={ imgUrl } alt="网络图片" />
</div>
)
}
此时在界面上就已经出现了一张图片

但是这个图片可能比较大,所以我们可以使用如下几种方式来修改这张图片的大小
-
通过css来进行设置
- 浏览器要解析CSS代码
- 浏览器需要缩放图片
所以这种设置方式不被推荐
-
在获取图片URL的时候,传递参数,以便于获取不同尺寸的图片(推荐)
例如// 原始图片地址 http://p1.music.126.net/uFtGUm56jgbGlBQOk_PGcw==/109951164832828416.jpg // 在请求的时候,告诉服务器 需要多高,多宽的图片 // 请求方式1 --- 查询字符串 (网易云) http://p1.music.126.net/uFtGUm56jgbGlBQOk_PGcw==/109951164832828416.jpg?param=140x140 // 请求方式2 --- params参数 (简书) https://upload.jianshu.io/users/upload_avatars/9838715/bb84ff12-e1b8-4226-93ba-5271229c29c0.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240- 使用这种方式在浏览器端不需要对图片的大小上进行过多的处理
- 会增加服务器处理图片的压力
调用函数
class App extends React.Component{
constructor() {
super()
this.state = {
imgUrl: 'http://p1.music.126.net/uFtGUm56jgbGlBQOk_PGcw==/109951164832828416.jpg'
}
}
formatImg(url, w, h) {
return `${url}?param=${w}x${h}`
}
render() {
const { imgUrl } = this.state
return (
<div>
{/*
可以直接在属性这里调用函数表达式来实现图片地址的格式化操作
这一操作类似于Vue中的过滤器 imgUrl | formatImg
*/}
<img src={ this.formatImg(imgUrl, 140, 140) } />
</div>
)
}
}
一些特殊的名称
{/*
JSX 将JS 和 html 混合在了一起
但是html中的一些属性 会和 js中的一些属性重名
此时html中的相关属性就需要使用JSX为其设置的alias
例如: for ---> htmlFor ===> 比如 <label htmlFor="XXX"> xxx </label>
class ---> className
*/}
{/* 如果没有使用别名,不会报错,但是会有warning */}
<div className="box title">我是一段文本</div>
样式的绑定
动态绑定class样式
class App extends React.Component{
constructor() {
super()
this.state = {
active: true
}
}
render() {
const { active } = this.state
return (
<div>
{/*
1. 动态绑定样式可以使用的是字符串拼接
2,因为需要先判断三元运算符, 所以使用括号进行包裹
3. 因为样式和样式之间使用空格进行隔开,所以在title后边需要加一个空格 (★★★)
*/}
<div className={ 'box title ' + ( active ? 'active' : '' ) }>一段测试文本</div>
</div>
)
}
}
动态绑定style样式
class App extends React.Component{
constructor() {
super()
this.state = {
active: true
}
}
render() {
const { active } = this.state
return (
<div>
{/*
1. 这里有2个大括号 外层的括号,表明内部需要使用的是jsx语法
2. 内部的大括号 表明的是 内部需要传递的是一个样式对象
3,一样特设样式的样式名需要进行转换
例如: font-size ---> fontSize
或者 `font-size`: '18px' 注意这里的`font-size`需要使用单引号括起来,表示是字符串
4. 样式对象中的属性值需要传递的解释字符串类型的数据
*/}
<div style={ { color: 'red', 'fontSize': '18px' } }>一段测试文本</div>
</div>
)
}
}
二、 React中的事件绑定
基本使用
class App extends React.Component{
constructor() {
super()
this.state = {
}
}
render() {
return (
<div>
{/*
1. 原生的js事件是全部都是小写的, 但是JSX中的事件其是使用小驼峰的书写方式,其是React对原生的js事件的封装
2. 在{ } 中传入事件 事件需要加上this,表示的是调用的是当前实例身上的this
*/}
<button onClick={ this.handleClick }>按钮</button>
</div>
)
}
handleClick() {
console.log('我被点击了')
}
}
事件中的this指向
暴露出来的问题
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
}
render() {
return (
<div>
{/*
1. React中的事件在调用我们传入的callback的时候
调用方式是 this.handClick.call(undefined)
所以在React的事件绑定中this指向会转换为undefined
*/}
<button onClick={ this.handleClick }>按钮</button>
</div>
)
}
handleClick() {
{/*
1. 此时点击是会报错的
因为此时这里的this的值是undefined
*/}
console.log(this.state.message)
}
}
解决方式1 --- 使用bind方法(隐式调用)
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
}
render() {
return (
<div>
{/*
bind 操作会返回给我们一个改变this后的新的函数
所以此时的this被修改回了实例对象
*/}
<button onClick={ this.handleClick.bind(this) }>按钮</button>
</div>
)
}
handleClick() {
console.log(this.state.message)
}
}
遗留的问题
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
}
render() {
return (
<div>
{/*
此时有多个元素需要设置点击事件,此时就会有大量的重复的bind操作,代码十分的冗余
*/}
<button onClick={ this.handleClick.bind(this) }>按钮1</button>
<button onClick={ this.handleClick.bind(this) }>按钮2</button>
<button onClick={ this.handleClick.bind(this) }>按钮3</button>
<button onClick={ this.handleClick.bind(this) }>按钮4</button>
<button onClick={ this.handleClick.bind(this) }>按钮5</button>
<button onClick={ this.handleClick.bind(this) }>按钮6</button>
</div>
)
}
handleClick() {
{/*
1. 此时点击是会报错的
因为此时这里的this的值是undefined
*/}
console.log(this.state.message)
}
}
修改如下:
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
// 在初始化实例的时候,就把实例中的this修改掉
// 所以就不需要在重复书写bind部分的代码了
this.handleClick = this.handleClick.bind(this)
}
render() {
return (
<div>
{/*
此时有多个元素需要设置点击事件,此时就会有大量的重复的bind操作,代码十分的冗余,减低了运行性能
*/}
<button onClick={ this.handleClick }>按钮1</button>
<button onClick={ this.handleClick }>按钮2</button>
<button onClick={ this.handleClick }>按钮3</button>
<button onClick={ this.handleClick }>按钮4</button>
<button onClick={ this.handleClick }>按钮5</button>
<button onClick={ this.handleClick }>按钮6</button>
</div>
)
}
handleClick() {
console.log(this.state.message)
}
}
方式1 虽然是
React中的this指向修改为了组件的实例对象但是如果在点击的时候,需要给
handleClick传递不同的参数此时就无法在constructor中统一修改this指向了
所以这种方式不推荐使用
解决方式2 --- 使用箭头函数
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
}
render() {
return (
<div>
<button onClick={ this.handleClick }>按钮</button>
</div>
)
}
handleClick = () => {
{/*
因为箭头函数内部是没有this的
所以根据js的作用域链,箭头函数内部的this会向上一级去进行寻找,直到最后寻找到全局作用域
所以此时箭头函数内部的this就是外层的this,也就是组件的实例对象
但是 在ES6中如果需要使用箭头函数定义方法,只能通过class fields的方式去进行进行定义
但是这种定义方式本质上定义的是成员属性,不是方法,所以依旧需要进行修改
*/}
console.log(this.state.message)
}
}
方式3 ---事件监听时传入箭头函数
class App extends React.Component{
constructor() {
super()
this.state = {
message: 'React事件中的this指向问题'
}
}
render() {
return (
<div>
{/*
在函数调用的外围封装一层箭头函数,
因为箭头函数内部无this,所以给箭头函数显示绑定this是没有什么作用和意义的
有因为作用域链,此时方法handleClick的调用的this,就是外层的this
也就是当前的组件对象
*/}
<button onClick={ () => this.handleClick }>按钮</button>
</div>
)
}
handleClick() {
console.log(this.state.message)
}
}
使用方式3来进行
this的修改,定义的callback是一个函数,不是方式2中的成员变量,又比较便于进行参数的传递,所以方式3 推荐使用
三、 React事件调用和传递参数
3.1 事件调用
原生的事件调用
<div id="dv">点击我</div>
<script>
document.getElementById('dv').addEventListener('click', e => console.log(e))
</script>
React中事件的调用
class App extends React.Component{
constructor() {
super()
}
btnClick(e) {
console.log(e)
}
render() {
return (
<div onClick={e => this.btnClick(e)}>
{/*
1. react中的事件是对原生的js浏览器事件进行了封装
在原生的js事件中,有一个默认参数event,是浏览器中和当前事件相关的所有相关属性的集合对象(俗称事件对象)
在React中, 调用事件函数的时候,其也会传递进来一个事件对象,这个事件对象是React对原生的浏览器事件对象的二次封装 形成的对象
2. 在使用箭头函数作为React的事件函数绑定的this,因为React调用的是外部的箭头函数,所以其默认的event对象是传递给箭 头函数的,所以需要自己手动的将其传递给内部实际调用的那个对象
3. 使用箭头函数的封装实际调用函数的好处是:
1. 内部thi指向 ---- React的实例对象
2. 函数调用的时候,是自己调用的,不是react帮助我们进行调用的,所以对于参数的传递和使用更好的把控
*/}
点击我
</div>
)
}
}
原生的事件对象

React中的事件对象

3,2 参数传递
需求:
有一个列表,点击列表项,在控制台中输出元素名称,索引值,this对象
使用bind来进行调用
class App extends React.Component{
constructor() {
super()
this.state = {
persons: [
'张三三',
'李思思',
'网无无',
'刘莉莉'
]
}
}
liClick(item, index, e) {
console.log(item, index, e)
}
render() {
const { persons } = this.state
return (
<ul>
{
persons.map((item, index) => {
return (
<li onClick={this.liClick.bind(this, item, index)}>
{/*
如果使用bind进行调用的时候,可以在bind后面进行传参
但是 其不可以写在构造函数中 如 this.liClick = this.liClick.bind(this, item, index)
因为在构造函数中并不存在变量item 和 index
在liClick进行调用的时候, 其依旧会传递进一个event对象,但是这个event对象不是第一个参数,而是函数调用时候的最后一个参数
liClick(item, index, e) (★★★)
*/}
{item}
</li>
)
})
}
</ul>
)
}
}
使用箭头函数来进行调用
class App extends React.Component{
constructor() {
super()
this.state = {
persons: [
'张三三',
'李思思',
'网无无',
'刘莉莉'
]
}
}
liClick(item, index, e) {
console.log(item, index, e)
}
render() {
{/*
对象解构
*/}
const { persons } = this.state
return (
<ul>
{
persons.map((item, index) => {
return (
<li onClick={e => this.liClick(item, index, e)}>
{/*
手动传递event参数
*/}
{item}
</li>
)
})
}
</ul>
)
}
}
四、 条件渲染
需求: 用户登录的时候,在页面显示欢迎回来, 如果用户没有登录的时候,显示请先登录
if表达式
class App extends React.Component{
constructor() {
super()
this.state = {
isLogin: false
}
}
render() {
{/* 在每次调用render函数的时候,是重新开辟了一个函数执行上下文,在其中开辟了一个新的常量 */}
const { isLogin } = this.state
let msg = null
if (isLogin) {
msg = <h2>欢迎回来</h2>
} else {
msg = <h2>请先登录</h2>
}
return (
<div>
{ msg }
</div>
)
}
}
三目运算符
class App extends React.Component{
constructor() {
super()
this.state = {
isLogin: false
}
}
render() {
const { isLogin } = this.state
return (
<div>
<h2>{ isLogin ? '欢迎回来' : '请先登录'} </h2>
</div>
)
}
}
使用逻辑与运算符
需求:如果用户登录后,在界面上显示用户名,
如果用户没有登录, 界面上什么也不显示
<div>
{/*
如果isLogin为true,就返回userName的值
如果isLogin为false, 那么就直接返回false
但是 React中 false在界面中不存在
注意: 这种写法,如果isLogin的值是false的时候
其页面中存在一个空的<h2></h2>
*/}
<h2>{ isLogin && userName } </h2>
{/*
使用这种方式去书写的时候,如果isLogin为false的时候
其是不会存在空的h2标签的
*/}
{ isLogin && <h2>userName</h2> }
</div>

4.1 模拟v-if 和 v-show
在
vue中控制元素的显示和隐藏有2条常用的指令
v-if通过移除元素和添加元素的方式来控制元素的显示和隐藏 适合于切换频率不高的元素
v-show通过设置元素的display属性的方式来控制元素的显示和隐藏 适合于切换频率比较高的元素
模拟v-if
class App extends React.Component{
constructor() {
super()
this.state = {
isLogin: false,
userName: 'Klaus'
}
}
render() {
const { isLogin, userName } = this.state
return (
<div>
<h2>{ isLogin && userName } </h2>
</div>
)
}
}
模拟v-show
class App extends React.Component{
constructor() {
super()
this.state = {
isLogin: false,
userName: 'Klaus'
}
}
render() {
const { isLogin, userName } = this.state
return (
<div>
<h2 style={{'display' : isLogin ? 'block': 'none'}}>{ userName } </h2>
</div>
)
}
}
五、列表渲染
5.1 简单的列表渲染
class App extends React.Component{
constructor() {
super()
this.state = {
nums: [15, 20, 43, 54, 76, 123]
}
}
render() {
const { nums } = this.state
return (
<ul>
{
nums.map(item => <li>{ item }</li>)
}
</ul>
)
}
}
5.2 显示大于50的数据项
<ul>
{
nums
.filter(item => item > 50)
.map(item => <li>{ item }</li>)
}
</ul>
5.3 显示前4条数据项
<ul>
{
nums
.slice(0, 4)
.map(item => <li>{ item }</li>)
}
</ul>
补充
-
基本上
大多数的html标签都是有title属性的,表示的是鼠标悬浮上去时候的提示信息<div title="这是div"></div> <img src="这是图片的地址" alt="这是图片加载失败时候的替换文本" title="这是鼠标悬浮上去时候的提示文本" /> -
数值的
map,filter方法都有2个参数,分别为callback,和函数调用时候的this指向,每一个callback都有3个参数,分别为item,index,arr,
arr.map((item, index, arr) => return item, this指向)
arr.filter((item, index, arr) => return boolean值, this指向)
- 数组
slice方法的作用是截取数组中的某一段内容并进行返回
`arr.slice(start, end) ==> return 截取之后形成的新数组`
Tips: 1. 注意截取范围是[start, end)
2. `start`必须为大于0的正整数
3. `end`可以是负整数,表示的是从后往前数
例如 `-1 ==> -1 + arr.length ==> 即为数组胡总的最后一个元素`
4. 如果`slice`方法只写了一个参数,那么第2个参数的默认值就是`arr.length`
也就是数组的元素是从起始的位置开始,到数组的最后一个元素(`arr.length - 1`,所以`包含最后一个元素`)
例如 [1, 2, 3, 4, 5].slice(2) ==> [3, 4, 5]