1.JSX简介
JSX(JavaScript XML)是一种类似于XML的语法扩展,用于在JavaScript中编写类似于HTML的结构。它被广泛应用于React框架中,用于描述React组件的结构和UI。
JSX允许开发者在JavaScript代码中直接编写类似于HTML的标记,使得编写和阅读组件的结构更加直观和易于理解。在编译过程中,Babel等工具会将JSX代码转换为纯JavaScript代码,以便在浏览器中运行。
React框架是一个用于构建用户界面的JavaScript库。它采用了组件化开发的思想,允许开发者将界面拆分为独立、可重用的组件,并通过数据流动和状态管理来构建动态的用户界面。
在React中,使用JSX语法编写组件的结构和UI。JSX允许在组件中以声明式的方式描述界面的样式、交互和数据渲染逻辑。当React应用启动时,它会将JSX代码转换为对应的JavaScript函数调用,从而创建React元素树,并通过调用ReactDOM库中的方法将它们渲染到DOM中。
2.JSX书写规范
JSX与HTML有一定区别,书写时存在一些编写规范,此外还贴了一个HTML 转化为 JSX 代码的工具transform.tools/html-to-jsx
1. 只能返回一个根元素
JSX语法被转化为JavaScript代码时,会被转化为一个函数调用,而函数调用只能返回一个值。因此,JSX语法中只能有一个根元素,其他的元素必须作为根元素的子元素存在。如果有多个根元素,需要将它们包裹在一个父元素中。
例如对于下列代码,需要采用<div> 标签对多个元素进行包裹
render() {
return (
<div>
<h2>{this.state.count}</h2>
<button onClick={this.addCount}>+1</button>
<button onClick={this.subCount}>-1</button>
</div>
)
}
如果你不想在标签中增加一个额外的 <div>,可以用 <> 和 </> 元素来代替:该空标签被称作 Fragment。React Fragment 允许你将子元素分组,而不会在 HTML 结构中添加额外节点。
render() {
return (
<>
<h2>{this.state.count}</h2>
<button onClick={this.addCount}>+1</button>
<button onClick={this.subCount}>-1</button>
</>
)
}
2.标签必须自闭合
对于没有子元素的标签,使用自闭合的形式(在标签末尾加上斜杠),例如:<img src="image.jpg" alt="Image" />。
3.JSX注释
在JSX中添加注释,可以使用花括号{/* */}来包裹注释内容。例如:{/* 这是一个注释 */}。
// 渲染内容
render() {
return (
<div>
{/* jsx注释写法 */}
<h2>{this.state.message}</h2>
</div>
)
}
4.JSX外层包裹小括号()
可以使用小括号()将最外层的jsx包裹起来,方便代码阅读
return (
<>
<h1>海蒂·拉玛的代办事项</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
<ul>
<li>发明一种新式交通信号灯</li>
<li>排练一个电影场景</li>
<li>改进频谱技术</li>
</ul>
</>
);
3 JSX中花括号{}的意义
在编写JSX的过程中,有时候,可能想要在标签中添加一些 JavaScript 逻辑或者引用动态的属性。这种情况下,你可以在 JSX 的大括号内来编写 JavaScript。
在JSX中, { } 表示一个表达式的开始和结束。它用于在JSX中嵌入JavaScript代码。
你可以在{}中放置以下类型的内容:
- 1变量:你可以将JavaScript变量放在{}中,以在JSX中使用它们。例如:{myVariable}。
- 表达式:你可以在{}中使用JavaScript表达式,例如数学运算、函数调用等。例如:{2 + 2}。
- 函数:你可以在{}中调用JavaScript函数,并使用其返回值。例如:{myFunction()}。
- 对象属性:你可以在{}中使用JavaScript对象的属性。例如:{myObject.property}。
- 条件语句:你可以在{}中使用JavaScript的条件语句,例如if语句或三元运算符。例如:{condition ? trueValue : falseValue}。
- JSX元素:你可以在{}中嵌套其他JSX元素,以构建复杂的JSX结构。例如:{Some JSX content}。
需要注意的是,{}中的内容会被当作JavaScript代码进行解析和执行,因此确保在{}中只放置合法的JavaScript代码。
4.JSX嵌入变量作为子元素
4.1 变量为Number、String、Array类型,可以直接渲染
<script type="text/babel">
class App extends React.Component {
// 构建数据
constructor() {
super()
this.state = {
message: "hello world",
score: 100,
books: ['math', 'english', 'music']
}
}
// 渲染内容
render() {
return (
<div>
<h2>{this.state.message}</h2>
<h2>{this.state.score}</h2>
<h2>{this.state.books}</h2>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
</script>
需要注意的是,数组默认是可以直接渲染的,也就是说不需要采用map等方法也可以渲染,它会把内容默认连接在一起,显然这么做没有什么意义。
4.2变量为null、undefined、Boolean类型,内容为空
变量为上述三种类型,并且直接通过{ } 渲染时,会直接不显示内容。
class App extends React.Component {
// 构建数据
constructor() {
super()
this.state = {
message: "hello world",
score: 100,
books: ['math', 'english', 'music'],
nullVal: null,
unVal: undefined,
isOpen: true
}
}
// 渲染内容
render() {
return (
<div>
<div>
<h1>变量为Number、String、Array类型</h1>
<h2>{this.state.message}</h2>
<h2>{this.state.score}</h2>
<h2>{this.state.books}</h2>
</div>
<div>
<h1>null、undefined、Boolean类型</h1>
<h2>{this.state.nullVal}</h2>
<h2>{this.state.nullVal+ ""}</h2>
<h2>{this.state.unVal}</h2>
<h2>{this.state.isOpen}</h2>
</div>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
如果必要情况下想要在页面显示null,undefined等,可以考虑采用“空字符串拼接”,“String数据类型转换”等等
对应的div结构如下,可以看到通过空字符串拼接处理后的h2标签可以正常显示null,其余则直接为空
4.3变量为Object类型,不可以直接作为子元素
如果要把Object类型直接放到{}中间,会直接报错。对于Object类型,需要选择其中具体的属性来进行展示。
class App extends React.Component {
// 构建数据
constructor() {
super()
this.state = {
message: "hello world",
score: 100,
books: ['math', 'english', 'music'],
nullVal: null,
unVal: undefined,
isOpen: true,
Person: {
age: 18,
height: 172
}
}
}
// 渲染内容
render() {
return (
<div>
<div>
<h1>Object类型</h1>
<h2>{this.state.Person}</h2>
</div>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
因此应该在对应的jsx代码处按下述方式对Object类型进行访问
<div>
<h1>Object类型</h1>
<h2>{this.state.Person.age}</h2>
<h2>{this.state.Person.height}</h2>
</div>
5.JSX嵌入表达式
在本章的演示中,通过this.state初始化了组件的状态,包含了firstName、lastName、books、score1、score2和Person等属性。
constructor() {
super()
this.state = {
firstName: 'Hao',
lastName: 'Wei',
books: ['math', 'english', 'music'],
score1: 80,
score2: 95,
Person: {
age: 18,
height: 172
}
}
}
对应的完整渲染函数 如下:,具体的每一部分分别在下方分别讲述。在render方法中,使用了大括号{}来插入JSX表达式,将变量、运算、方法调用等动态内容渲染到组件中。使用了const关键字定义了一些局部变量,将this.state中的数据进行解构和组合。使用map()方法和箭头函数将数组中的每个元素映射为
render() {
const { firstName, lastName } = this.state
const { score1, score2 } = this.state
const { books } = this.state
const fullName = firstName + lastName
const liELs = books.map(book => <li>{book}</li>)
return (
<div>
<div>
<h1>JSX插入表达式</h1>
<h2>{firstName + '' + lastName}</h2>
<h2>{fullName}</h2>
<h2>{3 + 5}</h2>
</div>
<div>
<h1>JSX插入三元运算符</h1>
<h2>{score1 > 90 ? '优秀':'良好'}</h2>
<h2>{score2 > 90 ? '优秀':'良好'}</h2>
</div>
<div>
<h1>JSX调用方法</h1>
<ul>{liELs}</ul>
<ul>{books.map(book => <li>{book}</li>)}</ul>
<ul>{this.getBooks()}</ul>
</div>
</div>
)
}
5.1 运算表达式
JSX内可以使用运算表达式。
<div>
<h1>JSX插入表达式</h1>
<h2>{firstName + '' + lastName}</h2>
<h2>{fullName}</h2>
<h2>{3 + 5}</h2>
</div>
5.2 三元运算符
<div>
<h1>JSX插入三元运算符</h1>
<h2>{score1 > 90 ? '优秀':'良好'}</h2>
<h2>{score2 > 90 ? '优秀':'良好'}</h2>
</div>
5.3 引用函数
在getBooks方法中,你使用this.state.books.map()将书籍数组转换为<li>元素的数组,并将其作为方法的返回值。
在jsx的{}中,可以直接调用方法
<div>
<h1>JSX调用方法</h1>
<ul>{liELs}</ul>
<ul>{books.map(book => <li>{book}</li>)}</ul>
<ul>{this.getBooks()}</ul>
</div>
getBooks() {
const liEls = this.state.books.map(book => <li>{book}</li>)
return liEls
}
6.JSX绑定className属性
下列代码讲述了两种不同的方式来绑定className属性。
在JavaScript部分,定义了一个名为App的React类组件。在构造函数中,使用super()调用父类的构造函数,然后通过this.state初始化了组件的状态,包含了message和isActive两个属性。
在render方法中,使用了大括号{}来插入JSX表达式,动态渲染组件的UI。首先,使用解构赋值从this.state中获取isActive的值。
接下来,展示了两种不同的方式来绑定className属性。
- a. 方法一:使用模板字符串
创建了一个名为h2Class的变量,使用模板字符串的方式将多个类名拼接在一起,并根据isActive的值决定是否添加active类名。
- b. 方法二:使用样式数组
创建了一个名为h2ClassArray的数组,初始值为['abc', 'cba'],然后根据isActive的值决定是否将'active'添加到数组中。最后,使用join()方法将数组元素拼接为一个字符串,并赋值给h2Class2变量。
在return语句中,通过使用大括号{}将变量h2Class和h2Class2嵌入到className属性中,实现了动态绑定类名。
最后,使用ReactDOM.createRoot方法创建了一个根节点,并使用root.render方法将组件渲染到根节点上。
整体而言,这段代码实现了一个简单的React应用。App组件的render方法根据isActive的值,动态绑定了不同的类名到两个<h2>元素的className属性上。 通过这种方式,可以在组件的渲染过程中根据状态数据来控制类名的动态变化,从而实现样式的动态切换。
<script type="text/babel">
class App extends React.Component {
// 构建数据
constructor() {
super()
this.state = {
message: 'Hello',
isActive: false
}
}
// 渲染内容
render() {
const { isActive } = this.state
{/*1.className属性绑定方法一:模版字符串*/}
const h2Class = `abc cba ${isActive? 'active':''}`
{/*2.className属性绑定方法二:样式数组*/}
const h2ClassArray = ['abc', 'cba']
if (isActive) {
h2ClassArray.push('active')
}
const h2Class2 = h2ClassArray.join(" ")
return (
<div>
<h2 className={h2Class}>{this.state.message}</h2>
<h2 className={h2Class2}>{this.state.message}</h2>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
</script>
7.JSX绑定元素的内联样式style属性
展示了如何在JSX中绑定style属性,并设置不同的样式。
在render方法中,使用了大括号{}来插入JSX表达式,动态渲染组件的UI。首先,使用解构赋值从this.state中获取styleObj的值。
在<h2>元素中,使用了两种方式来设置样式:
- a. 方法一:直接在style属性中写入样式对象
使用双大括号{{ }},外层大括号表示JSX表达式,内层大括号表示样式对象。直接在style属性中写入color: 'blue',即将文字颜色设置为蓝色。
- b. 方法二:将样式对象作为变量
将styleObj作为变量,通过style={styleObj}将样式对象传递给style属性。
在return语句中,将上述两个<h2>元素嵌入到<div>元素中,实现了两个不同样式的文本显示。
最后,使用ReactDOM.createRoot方法创建了一个根节点,并使用root.render方法将组件渲染到根节点上。
App组件的render方法根据状态数据动态设置了两个<h2>元素的样式。通过直接在style属性中写入样式对象或使用变量传递样式对象,可以在组件的渲染过程中灵活地设置元素的内联样式。
<script type="text/babel">
class App extends React.Component {
// 构建数据
constructor() {
super()
this.state = {
message: "hello world",
styleObj: { color: "red", fontSize: "30px" }
}
}
// 渲染内容
render() {
const {styleObj} = this.state
return (
<div>
<h2 style={{color: 'blue'}}>{this.state.message}</h2>
<h2 style={styleObj}>{this.state.message}</h2>
</div>
)
}
}
</script>
此外,如果想要根据条件动态创建样式对象,并将其作为style属性的值,可以参考下列代码的写法:
const isActive = true;
const dynamicStyles = {
color: isActive ? 'green' : 'red',
fontSize: isActive ? '18px' : '14px'
};
return <div style={dynamicStyles}>Hello, JSX!</div>;
8.JSX的本质
jsx实际上是对React.createElement函数的调用,是一种语法糖。JSX(JavaScript XML)是一种JavaScript的扩展语法,它允许我们在JavaScript代码中编写类似XML的标记,用于描述React元素的结构。在jsx中,我们可以使用类似HTML的语法来创建React元素。
例如,在jsx中,我们可以这样创建一个简单的
const element = <div>Hello, JSX!</div>;
这个jsx代码看起来类似HTML,但实际上,这是JavaScript代码。
8.1 jsx编译过程:
当使用jsx语法时,它并不是直接在浏览器中执行的,而是需要经过编译的过程。在编译阶段,jsx代码会被转换为普通的JavaScript代码。
转换的过程主要是通过Babel这样的工具来完成。Babel是一个广泛使用的JavaScript编译器,可以将高级JavaScript代码(包括jsx)转换为ES5代码,以便在现代和旧版浏览器中执行。
jsx转换为React.createElement:
在jsx编译过程中,jsx代码会被转换为React.createElement函数的调用。例如,上面的jsx代码会被转换为如下形式的JavaScript代码:
const element = React.createElement("div", null, "Hello, JSX!");
React.createElement函数接收三个参数:元素类型(标签名或组件),属性对象(包含元素的属性),和子元素。在这个例子中,React.createElement创建了一个
这样,我们可以看到,jsx实际上是对React.createElement函数的调用,它将帮助我们简化创建React元素的过程,使代码更加易读和直观。
总结:jsx是React的一种语法扩展,它允许我们在JavaScript代码中编写类似XML的标记,用于描述React元素的结构。在编译阶段,jsx代码会被转换为React.createElement函数的调用,帮助我们更方便地创建React元素,使代码更加易读和维护。这也是为什么我们可以使用jsx来创建React组件。
Babel官网babeljs.io/ 也提供了代码转换的工具,可以看到jsx实时转换为react原生写法的过程。
8.2案例演示
<script>
class App extends React.Component {
// 构建数据
constructor() {
super();
this.state = {
message: "hello world",
};
}
// 渲染内容
render() {
// react原生创建元素的方式
const element = /*#__PURE__*/ React.createElement(
"div",
null,
/*#__PURE__*/ React.createElement(
"div",
{
className: "header",
},
"header"
),
/*#__PURE__*/ React.createElement(
"div",
{
className: "content",
},
/*#__PURE__*/ React.createElement(
"div",
null,
"\u5185\u5BB9\u4E00"
),
/*#__PURE__*/ React.createElement(
"div",
null,
"\u5185\u5BB9\u4E8C"
)
),
/*#__PURE__*/ React.createElement(
"div",
{
className: "footer",
},
"footer"
)
);
console.log("element元素(虚拟DOM对象)", element);
return element;
}
}
// 2. 创建root并渲染App组件
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(React.createElement(App, null));
</script>
定义了一个React类组件 App,它有一个构造函数用于初始化组件的状态(state),并且定义了一个render方法,用于渲染组件的内容。在render方法中,使用了React.createElement方法来创建React元素。
上面你展示的原生React元素创建方式与使用JSX创建的效果是等效的,但是使用JSX可以大大简化代码。
对于上面你使用原生方式创建的element元素,如果用JSX来表示,它会是这样的:
const element = (
<div>
<div className="header">header</div>
<div className="content">
<div>内容一</div>
<div>内容二</div>
</div>
<div className="footer">footer</div>
</div>
);
这样的写法更加直观和易读,而且更符合类似HTML的结构。因此,jsx的本质是一种语法糖,它可以更方便地描述React元素的结构,最终在构建应用时会被转换为原生的React元素创建方式。
log控制台打印虚拟DOM element的具体信息: