一、JSX
JSX是javascript XML的简写,实际上是javascript的扩展,既有javascript的语法结构,又有XML的结构
1、JSX的规则要求
-
jsx必须要有一个根节点
如果不想产生无用的根标签,但是还要遵守JSX的语法的要求,可以使用如下两种方式
JSX必须要有一个根节点,而且编译之后在浏览器中不产生根标签,jsx可以使用如下两种方式完成
-
使用空标签的方式来完成
const content=<>
<h1>Hello Giles</h1><h1>Hello Woniuxy</h1>
</>
-
Fragment组件来完成
const content=<Fragment>
<h1>Hello Giles</h1><h1>Hello Woniuxy</h1>
</Fragment>
-
JSX中的标签如果没有子元素,那么也要使用
</>
来作为结束
<img src='https://api.java.crmeb.net/crmebimage/store/2020/08/15/adae23e354114cd5bd8f3cae740741c23opxeh8kw2.jpg'/></img>
或者
<img src='https://api.java.crmeb.net/crmebimage/store/2020/08/15/adae23e354114cd5bd8f3cae740741c23opxeh8kw2.jpg'/>
-
采用驼峰式命名法
-
class---->className
-
for--->htmlFor
-
tabindex--->tabIndex
-
-
为了避免分号陷阱,建议大家必须使用
()
将元素括起来
const content=(<></>)
2、JSX的表达式
-
在JSX中不管是动态元素的渲染还是属性的渲染全部通过
{}
来进行渲染的
let name="Giles"
let age=38
let job="teacher"
let hobby=['play basketball','play football']
let avatar="https://www.baidu.com/img/flexible/logo/pc/result.png"
const template=(
<>
<h1>个人简介</h1>
<div>姓名:{name}</div>
<div>年龄:{age}</div>
<div>工作:{job}</div>
<div>爱好:{hobby}</div>
<div>
<img src={avatar}></img>
</div>
</>)
-
jsx的算数表达式和三元表达式
<div>是否成年:{age>=18?'成年':'未成年'}</div>
<div>虚岁:{age+1}</div>
-
函数表达式
let idcard="610122198404084030"
const getBirthday=idcard=>idcard.slice(6,10)+"-"+idcard.slice(10,12)+"-"+idcard.slice(12,14)
const template=(
<>
<h1>个人简介</h1>
<div>姓名:{name}</div>
<div>年龄:{age}</div>
<div>工作:{job}</div>
<div>爱好:{hobby}</div>
<div>
<img src={avatar}></img>
</div>
<div>是否成年:{age>=18?'成年':'未成年'}</div>
<div>虚岁:{age+1}</div>
<div>生日:{getBirthday(idcard)}</div>
</>)
-
对象表达式
let user={
name:'刘备',
age:39,
job:'皇帝'
}
const introduce=user=>`我叫${user.name},今年${user.age}岁,职业是${user.job}`
const template=(<>
<div>姓名:{user.name}</div>
<div>年龄:{user.age}</div>
<div>职业:{user.job}</div>
<div>
介绍:{introduce(user)}
</div>
</>)
3、列表渲染
import React, { Component, Fragment } from 'react'
import '@/App.css'
export default class App extends Component {
render() {
const orderList = [
{
title: '待付款',
icon: 'icon-daifukuan'
},
{
title: '待发货',
icon: 'icon-daifahuo'
},
{
title: '待收货',
icon: 'icon-daishouhuo'
},
{
title: '待评价',
icon: 'icon-daipingjia'
},
{
title: '售后/退款',
icon: 'icon-daifukuan'
}
]
return (
<Fragment>
<div className='mime'>
<div className='order-center'>
<div className='order-center-header'>
<div>订单中心</div>
<div>查看全部</div>
</div>
<div className='order-center-body'>
{
orderList.map(item => <div className='order-item'>
<i className={'iconfont '+item.icon}></i>
<div>{item.title}</div>
</div>
)
}
</div>
</div>
</div>
</Fragment>
)
}
}
二、react的样式的处理
针对于行内样式和类样式的处理如下
1、类样式
使用className="类样式名"方式来进行类样式的设置
-
在src/assets/css/index.css
.mtable{
border-collapse: collapse;
width: 900px;
}
.mtable td{
border:1px solid #ccc;
padding:10px;
text-align: center;
}
-
在src/index.js中引入
import './assets/css/index.css'
2、行内样式
语法
<div style={{key:value,key:value}}></div>
当然也可以将对象提取出来
const headStyle={border:'1px solid #eee',padding:'10px',backgroundColor:'#ccc',color:'#fff'}
<th style={headStyle}>序号</th>
注意:样式名采用驼峰式命名法,如果有多个单词,每个单词的首字母必须要大写才可以。
三、引入本地图片
如果在一个组件中要引入图片,这个图片可以来自本地,也可以来自网络,来自本地图片的处理
如果要引入本地中图片,常用的方法有两种
-
通过ES6的import方式进行导入
import logo from './assets/logo.png'
export default class App extends Component {
render() {
return <Fragment>
<img src={logo}></img>
</Fragment>
}
}
-
通过node.js的require方法引入
import logo from './assets/logo.png'
export default class App extends Component {
render() {
const logo=require('./assets/logo.png')
return <Fragment>
<img src={logo}></img>
</Fragment>
}
}
注意:如果图片是网络图片,直接写网址就可以了,无需进行其他处理,如果是网络图片,有的时候图片地址是正确的,但是图片却出不来,可能是防盗链问题。
四、虚拟DOM和jsx底层渲染机制
1、什么是虚拟DOM
在 React 中,每个 DOM 对象都有一个对应的 Virtual DOM 对象,它是 DOM 对象的 JavaScript 对象表现形式,其实就是使用 JavaScript 对象来描述 DOM 对象信息,比如 DOM 对象的类型是什么,它身上有哪些属性,它拥有哪些子元素。
下面是一个DOM对象
<div className="container">
<h3>Hello React</h3>
<p>React is great </p>
</div>
对应的虚拟DOM,如下
{
type: "div",
props: { className: "container" },
children: [
{
type: "h3",
props: null,
children: [
{
type: "text",
props: {
textContent: "Hello React"
}
}
]
},
{
type: "p",
props: null,
children: [
{
type: "text",
props: {
textContent: "React is great"
}
}
]
}
]
}
-
虚拟DOM如何提升效率的
精准找出发生变化的 DOM 对象,只更新发生变化的部分。
在 React 第一次创建 DOM 对象后,会为每个 DOM 对象创建其对应的 Virtual DOM 对象,在 DOM 对象发生更新之前,React 会先更新所有的 Virtual DOM 对象,然后 React 会将更新后的 Virtual DOM 和 更新前的 Virtual DOM 进行比较,从而找出发生变化的部分,React 会将发生变化的部分更新到真实的 DOM 对象中,React 仅更新必要更新的部分。
2、创建虚拟DOM的方式
2.1、使用createElement创建虚拟DOM
我们通过React对象中提供的createElement函数完成了虚拟DOM的创建,而后再通过ReactDOM的render函数将其渲染到页面的指定元素中,这种方式创建虚拟DOM的方式相对而言比较麻烦,而且循环创建多个元素的时候,还需要指定key,否则会报错。
import React from 'react';
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
const helloRectEle=React.createElement("h1",null,"Hello React");
const helloWoniuEle=React.createElement("h1",null,"Hello Woniuxy");
const helloGilesEle=React.createElement("h1",null,"Hello Giles");
const containerElement=React.createElement("div",null, [helloRectEle,helloWoniuEle,helloGilesEle]);
root.render(containerElement);
如上页面显示是正常的,但是控制台会报如下错误
Warning: Each child in a list should have a unique "key" prop.
Check the top-level render call using <div>. See https://reactjs.org/link/warning-keys for more information.
at h1
这是因为在循环生成多个组件的时候,没有给组件加上key引起,具体修改如下
import React from 'react';
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
const helloRectEle=React.createElement("h1",{key:0},"Hello React");
const helloWoniuEle=React.createElement("h1",{key:1},"Hello Woniuxy");
const helloGilesEle=React.createElement("h1",{key:2},"Hello Giles");
const containerElement=React.createElement("div",null, [helloRectEle,helloWoniuEle,helloGilesEle]);
root.render(containerElement);
Key的作⽤
: key是虚拟DOM对象的标识,在更新时标识为keys起着极其重要的作 ⽤:即当状态中的数据发⽣变化时,react会根据新数据⽣成新的虚拟 DOM,随后React进⾏新旧虚拟DOM的key的对⽐,如果存在相同的 key,若内容没变,则沿⽤之前的真实DOM,若数据变了,则⽣成新的真 实DOM,并且替换⻚⾯之前的真实DOM,若不存在key,则根据数据创 建新的真实DOM,随后进⾏⻚⾯渲染,减少不必要的元素重渲染,提升性能
1.2、使用JSX创建虚拟DOM
对于初学者来说,通过createElement
方法构建用户界面属实不太友好,但是在React内部确实需要通过这种方式创建虚拟DOM对象,如何解决这个矛盾呢?
React为createElement方法创造了替代语法,让开发者可以通过类似于HTML的语法创建用户界面,在构建应用时,再使用babel
将这种替换语法转换回createElement
方法的调用代码,下面就是使用JSX方式创建,下面我们先来通过一段代码来看一下,后续我们再具体详细讲解JSX的语法
const conatiner=(
<div>
<h1>Hello React</h1>
<h1>Hello Woniuxy</h1>
<h1>Hello Giles</h1>
</div>
)
ReactDOM.render(conatiner,document.getElementById('root'));
实际上JSX的方式最终还是会转成第一种使用React.createElement()函数创建的方式,这里只是为了方便使用了JSX,我们编写的JSX通过babel来转换的,下面我们可以在官网上来做这个实验
下面是babel的官网:babel官方网站: Babel 中文文档 | Babel中文网 · Babel 中文文档 | Babel中文网
这里提供了将JSX的方式最终转成createElement的方式
使用JSX的方式创建虚拟DOM的步骤
-
在body中定义一个div容器
-
导入包
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="./node_modules/babel-standalone/babel.js"></script>
注意:这里要引入babel.js对JSX进行转换,首先引入之前可以通过yarn add babel-standalone方式来下载babel
-
编写jsx
<script type="text/babel">
const divElement=<div>
<h1>个人介绍</h1>
<table>
<tr>
<td>姓名:</td>
<td>张三</td>
</tr>
<tr>
<td>年龄:</td>
<td>33</td>
</tr>
<tr>
<td>性别:</td>
<td>男</td>
</tr>
</table>
</div>
</script>
JSX中的代码可以是DOM元素,也可以是以后的自定义组件
-
渲染虚拟DOM到目标容器上
const root=ReactDOM.createRoot(document.getElementById('app'))
root.render(divElement)
3、JSX的底层渲染机制
jsx的底层渲染机制可以分为如下步骤
第1步:把编写好的jsx语法,编译成虚拟DOM对象
-
基于babel-preset-react-app把JSX编译为React.createElement(...)这种格式
可以在babel中测试一下(babel的地址:Babel · Babel)
下面介绍一下React.createElement(ele,props,...children)
参数说明
|- ele:元素的标签名或者组件
|- props:元素的属性集合(对象),注意:如果没有设置过任何的属性,则此值是null
|- children:第三个以及以后的参数,都是当前元素的子节点
-
执行createElement方法后,创建出virtual DOM虚拟DOM对象,格式如下